#!/usr/bin/env php bQ.box/.requirements.php ek;Ҷ.box/bin/check-requirements.php e[.box/src/Checker.php exA.box/src/IO.php  e KW!.box/src/IsExtensionFulfilled.phpv evx.box/src/IsFulfilled.phpv evzzR".box/src/IsPhpVersionFulfilled.php e;Xc.box/src/Printer.php e 2TG.box/src/Requirement.phpm em7B".box/src/RequirementCollection.php e.box/src/Terminal.php e }x&k.box/vendor/autoload.php esa*.box/vendor/composer/autoload_classmap.php, e, ,.box/vendor/composer/autoload_namespaces.php et!׶&.box/vendor/composer/autoload_psr4.php6 e6 ]8<&.box/vendor/composer/autoload_real.php eW(.box/vendor/composer/autoload_static.phpK eK0$.box/vendor/composer/ClassLoader.php> e>5Ky".box/vendor/composer/installed.php' e'1*.box/vendor/composer/InstalledVersions.phpm emhm׶.box/vendor/composer/LICENSE. e. #.box/vendor/composer/semver/LICENSE eBh..box/vendor/composer/semver/src/Comparator.phpu eu?}4.box/vendor/composer/semver/src/CompilingMatcher.php e8 ms4.box/vendor/composer/semver/src/Constraint/Bound.phpo eo9.box/vendor/composer/semver/src/Constraint/Constraint.php'& e'&w_B.box/vendor/composer/semver/src/Constraint/ConstraintInterface.php er|A.box/vendor/composer/semver/src/Constraint/MatchAllConstraint.php7 e7;B.box/vendor/composer/semver/src/Constraint/MatchNoneConstraint.phpU eU/E>.box/vendor/composer/semver/src/Constraint/MultiConstraint.php~ e~O,.box/vendor/composer/semver/src/Interval.php e}&-.box/vendor/composer/semver/src/Intervals.phpn: en:H1*.box/vendor/composer/semver/src/Semver.php e1.box/vendor/composer/semver/src/VersionParser.php9 e9:_bin/fw eCl commands.php e ˶ composer.jsong eg\s! composer.locky eysB src/App.php. e.e4˶src/Command/Addon.php e)n⊶src/Command/BaseCommand.php e &Vysrc/Command/Install.php9/ e9/Bֶsrc/Command/Login.php etX̶src/Command/Publish.php+ e+b-src/Command/SelfUpdate.php e Rsrc/Command/Setup.phpV eVE*2src/Command/Task.php eR"src/Command/Update.php0 e0src/Helpers/Process.php e t2src/Helpers/Prompt.php e src/Providers/BaseProvider.php e<.src/Providers/Bitbucket.php e 2src/Providers/Github.php9 e9 ӿsrc/Task/AbstractTask.php e*1`src/Task/Addon.php eN |src/Task/Assets.php@ e@;rZsrc/Task/Composer.php e%7src/Task/Download.php e!src/Task/GitClone.php eZsrc/Utils/AppInstall.php e ]src/Utils/CommandException.php e:j src/Utils/Config.php e 6pHsrc/Utils/Dependencies.phpv evyMsrc/Utils/ErrorHandler.php e Z3src/Utils/File.php{ e{Q src/Utils/FWStrategy.php e~)ضsrc/Utils/Registry.phpL eL#(src/Utils/RunContext.php e ,src/Utils/SystemConfig.phpk ekA=src/Utils/Updater.phpg egjxsrc/Utils/VersionUtils.php e avendor/autoload.php e *vendor/bennerinformatics/php-path/path.php e9ζ3vendor/bennerinformatics/php-path/test/PathTest.php{ e{ w:vendor/bit3/git-php/src/Command/AbstractCommandBuilder.php eb75vendor/bit3/git-php/src/Command/AddCommandBuilder.phpY eYE8vendor/bit3/git-php/src/Command/BranchCommandBuilder.php e*$O:vendor/bit3/git-php/src/Command/CheckoutCommandBuilder.php edws7vendor/bit3/git-php/src/Command/CloneCommandBuilder.php ef}Ͷ;vendor/bit3/git-php/src/Command/CommandBuilderInterface.php e!7vendor/bit3/git-php/src/Command/CommandBuilderTrait.php eeë58vendor/bit3/git-php/src/Command/CommitCommandBuilder.php) e)?z8vendor/bit3/git-php/src/Command/ConfigCommandBuilder.php9) e9)B:vendor/bit3/git-php/src/Command/DescribeCommandBuilder.phpp ephW[7vendor/bit3/git-php/src/Command/FetchCommandBuilder.php" e"f6vendor/bit3/git-php/src/Command/InitCommandBuilder.php/ e/ ? 5vendor/bit3/git-php/src/Command/LogCommandBuilder.php\ e\BR:vendor/bit3/git-php/src/Command/LsRemoteCommandBuilder.php eud7vendor/bit3/git-php/src/Command/MergeCommandBuilder.php e d1<Զ6vendor/bit3/git-php/src/Command/PullCommandBuilder.php e _ʶ6vendor/bit3/git-php/src/Command/PushCommandBuilder.phpa eafҶ8vendor/bit3/git-php/src/Command/RemoteCommandBuilder.php" e"7vendor/bit3/git-php/src/Command/ResetCommandBuilder.phps es x&:vendor/bit3/git-php/src/Command/RevParseCommandBuilder.php ' e 'ī4vendor/bit3/git-php/src/Command/RmCommandBuilder.php e Y:vendor/bit3/git-php/src/Command/ShortLogCommandBuilder.php e(Q6vendor/bit3/git-php/src/Command/ShowCommandBuilder.php e`y87vendor/bit3/git-php/src/Command/StashCommandBuilder.php e-Z8vendor/bit3/git-php/src/Command/StatusCommandBuilder.php" e""ж5vendor/bit3/git-php/src/Command/TagCommandBuilder.php e GE%vendor/bit3/git-php/src/GitConfig.php e=3(vendor/bit3/git-php/src/GitException.php, e, )vendor/bit3/git-php/src/GitRepository.php eTT/vendor/bit3/git-php/tests/GitRepositoryTest.phppX epX~%vendor/composer/autoload_classmap.phpB eB "vendor/composer/autoload_files.phpn enI'vendor/composer/autoload_namespaces.php eѶ!vendor/composer/autoload_psr4.php e WM!vendor/composer/autoload_real.php eA#vendor/composer/autoload_static.php΄ e΄ם@vendor/composer/ClassLoader.php@ e@>]׶vendor/composer/installed.json evendor/composer/installed.phpR eRp%vendor/composer/InstalledVersions.php: e:畎Kvendor/composer/LICENSE. e. "vendor/composer/platform_check.php e4)vendor/composer/semver/src/Comparator.php e g3 <vendor/composer/semver/src/Constraint/AbstractConstraint.phpn en;4vendor/composer/semver/src/Constraint/Constraint.php eV=vendor/composer/semver/src/Constraint/ConstraintInterface.php^ e^)X9vendor/composer/semver/src/Constraint/EmptyConstraint.php: e:@M9vendor/composer/semver/src/Constraint/MultiConstraint.php< e< ª %vendor/composer/semver/src/Semver.php e oI,vendor/composer/semver/src/VersionParser.phpKT eKTvʶ;vendor/defuse/php-encryption/dist/phar-testing-autoload.php eW)vendor/defuse/php-encryption/src/Core.phph= eh=Oܯ+vendor/defuse/php-encryption/src/Crypto.php 9 e 9Kt(0vendor/defuse/php-encryption/src/DerivedKeys.php  e !-vendor/defuse/php-encryption/src/Encoding.php$ e$OAvendor/defuse/php-encryption/src/Exception/BadFormatException.phpy ey=*>vendor/defuse/php-encryption/src/Exception/CryptoException.phpX eXKvendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php e :vendor/defuse/php-encryption/src/Exception/IOException.phpr er"i&ɶTvendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php ed+M)vendor/defuse/php-encryption/src/File.phpk ek?(vendor/defuse/php-encryption/src/Key.phpP eP q(2vendor/defuse/php-encryption/src/KeyOrPassword.php ec;vendor/defuse/php-encryption/src/KeyProtectedByPassword.phps es 1vendor/defuse/php-encryption/src/RuntimeTests.php e (Fvendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php:% e:%Uvendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php e/GǶ/vendor/guzzlehttp/guzzle/src/BodySummarizer.phpw ew^:8vendor/guzzlehttp/guzzle/src/BodySummarizerInterface.php e]Ӷ'vendor/guzzlehttp/guzzle/src/Client.phpH eHݶ0vendor/guzzlehttp/guzzle/src/ClientInterface.phpT eT ,vendor/guzzlehttp/guzzle/src/ClientTrait.php.# e.#Vx1vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php>% e>%(:vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php e UV5vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php e Y8vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php e1vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php7 e7_?vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php eOm:vendor/guzzlehttp/guzzle/src/Exception/ClientException.php ej;vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php eN :vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php e5O\$Cvendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php eco;vendor/guzzlehttp/guzzle/src/Exception/RequestException.php e0؜Ƕ:vendor/guzzlehttp/guzzle/src/Exception/ServerException.php eFjDvendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.phpe ee$<vendor/guzzlehttp/guzzle/src/Exception/TransferException.phpy ey/*vendor/guzzlehttp/guzzle/src/functions.php8 e8.2vendor/guzzlehttp/guzzle/src/functions_include.php eE94vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php` e`ju$=vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php eP4vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php2 e2I]9vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.phpW eWk(3vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.phpT eT ?C8vendor/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php  e 7{4vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php  e af.vendor/guzzlehttp/guzzle/src/Handler/Proxy.php e96vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.phpVS eVSb-vendor/guzzlehttp/guzzle/src/HandlerStack.php" e"l1vendor/guzzlehttp/guzzle/src/MessageFormatter.phps esGL:vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php/ e/t+vendor/guzzlehttp/guzzle/src/Middleware.php+ e+%vendor/guzzlehttp/guzzle/src/Pool.phpl elL+6vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.phpM eM HG3vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php eDS/vendor/guzzlehttp/guzzle/src/RequestOptions.php* e*n0vendor/guzzlehttp/guzzle/src/RetryMiddleware.php e.vendor/guzzlehttp/guzzle/src/TransferStats.phpj ej }Ͷ&vendor/guzzlehttp/guzzle/src/Utils.php3 e3NÖ5vendor/guzzlehttp/promises/src/AggregateException.php eb{8vendor/guzzlehttp/promises/src/CancellationException.php eLt,vendor/guzzlehttp/promises/src/Coroutine.phpA eAWP)vendor/guzzlehttp/promises/src/Create.php eR'vendor/guzzlehttp/promises/src/Each.phpc ec V%.vendor/guzzlehttp/promises/src/EachPromise.php e偢'3vendor/guzzlehttp/promises/src/FulfilledPromise.php e' c%vendor/guzzlehttp/promises/src/Is.php e0m*vendor/guzzlehttp/promises/src/Promise.php" e"NtD3vendor/guzzlehttp/promises/src/PromiseInterface.php e 逿4vendor/guzzlehttp/promises/src/PromisorInterface.php ed2vendor/guzzlehttp/promises/src/RejectedPromise.php ed15vendor/guzzlehttp/promises/src/RejectionException.php eGyֶ,vendor/guzzlehttp/promises/src/TaskQueue.php e4g5vendor/guzzlehttp/promises/src/TaskQueueInterface.php e>=(vendor/guzzlehttp/promises/src/Utils.php e +vendor/guzzlehttp/psr7/src/AppendStream.php; e;'+vendor/guzzlehttp/psr7/src/BufferStream.php e Dy,vendor/guzzlehttp/psr7/src/CachingStream.php eն-vendor/guzzlehttp/psr7/src/DroppingStream.php eq: t>vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php eN|'vendor/guzzlehttp/psr7/src/FnStream.php e=aԶ%vendor/guzzlehttp/psr7/src/Header.phpe ee*vendor/guzzlehttp/psr7/src/HttpFactory.php e hiD,vendor/guzzlehttp/psr7/src/InflateStream.php ek-vendor/guzzlehttp/psr7/src/LazyOpenStream.php@ e@u*vendor/guzzlehttp/psr7/src/LimitStream.php eEGOݶ&vendor/guzzlehttp/psr7/src/Message.php e J+vendor/guzzlehttp/psr7/src/MessageTrait.php@ e@ 'vendor/guzzlehttp/psr7/src/MimeType.php e{(.vendor/guzzlehttp/psr7/src/MultipartStream.php8 e8&_+vendor/guzzlehttp/psr7/src/NoSeekStream.php  e ×)vendor/guzzlehttp/psr7/src/PumpStream.php e=$vendor/guzzlehttp/psr7/src/Query.php? e?!.&vendor/guzzlehttp/psr7/src/Request.phpD eD)'vendor/guzzlehttp/psr7/src/Response.php* e*&vendor/guzzlehttp/psr7/src/Rfc7230.php eџU,vendor/guzzlehttp/psr7/src/ServerRequest.phpM% eM%-%vendor/guzzlehttp/psr7/src/Stream.php ez3vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php e jg,vendor/guzzlehttp/psr7/src/StreamWrapper.php e0 N_+vendor/guzzlehttp/psr7/src/UploadedFile.php eӠ"vendor/guzzlehttp/psr7/src/Uri.phpU eUu,vendor/guzzlehttp/psr7/src/UriComparator.php~ e~Ŝ ,vendor/guzzlehttp/psr7/src/UriNormalizer.php! e!׶*vendor/guzzlehttp/psr7/src/UriResolver.php! e!b$vendor/guzzlehttp/psr7/src/Utils.php< e<P7vendor/jakeasmith/http_build_url/src/http_build_url.php e¾4vendor/jakeasmith/http_build_url/tests/bootstrap.php elXр;vendor/jakeasmith/http_build_url/tests/HttpBuildUrlTest.php esm2vendor/jakub-onderka/php-console-color/example.php eși;vendor/jakub-onderka/php-console-color/src/ConsoleColor.php\ e\>Dvendor/jakub-onderka/php-console-color/src/InvalidStyleException.php e zAvendor/jakub-onderka/php-console-color/tests/ConsoleColorTest.php e°鍶Avendor/jakub-onderka/php-console-highlighter/examples/snippet.php, e,7d߇Dvendor/jakub-onderka/php-console-highlighter/examples/whole_file.php' e'bQvendor/jakub-onderka/php-console-highlighter/examples/whole_file_line_numbers.php6 e6=@cvendor/jakub-onderka/php-console-highlighter/src/JakubOnderka/PhpConsoleHighlighter/Highlighter.php e[ @vendor/jakub-onderka/php-console-highlighter/tests/bootstrap.phpA eArfvendor/jakub-onderka/php-console-highlighter/tests/JakubOnderka/PhpConsoleHighligter/HigligterTest.php eҔ33vendor/padraic/humbug_get_contents/src/function.php eEӶAvendor/padraic/humbug_get_contents/src/Humbug/FileGetContents.php3 e3XN6vendor/padraic/humbug_get_contents/tests/bootstrap.php e8LEvendor/padraic/humbug_get_contents/tests/Humbug/Test/FunctionTest.php e G@vendor/padraic/phar-updater/src/Exception/ExceptionInterface.php6 e6gQ7Avendor/padraic/phar-updater/src/Exception/FilesystemException.phpL eLP Bvendor/padraic/phar-updater/src/Exception/HttpRequestException.phpM eMDFvendor/padraic/phar-updater/src/Exception/InvalidArgumentException.phpp ep3DBvendor/padraic/phar-updater/src/Exception/JsonParsingException.phpM eMwBvendor/padraic/phar-updater/src/Exception/NoSignatureException.phpM eMb䢿>vendor/padraic/phar-updater/src/Exception/RuntimeException.phph ehyQ;vendor/padraic/phar-updater/src/Strategy/GithubStrategy.php eUK8vendor/padraic/phar-updater/src/Strategy/ShaStrategy.php. e.OlK>vendor/padraic/phar-updater/src/Strategy/StrategyInterface.php eVr+vendor/padraic/phar-updater/src/Updater.phpQ1 eQ1nq1vendor/padraic/phar-updater/src/VersionParser.phpg eg[/vendor/padraic/phar-updater/tests/bootstrap.php et Vvendor/padraic/phar-updater/tests/Humbug/Test/SelfUpdate/UpdaterGithubStrategyTest.php) e)ܘ!Hvendor/padraic/phar-updater/tests/Humbug/Test/SelfUpdate/UpdaterTest.php& e&[Nvendor/padraic/phar-updater/tests/Humbug/Test/SelfUpdate/VersionParserTest.php+ e+j.3Uvendor/padraic/phar-updater/tests/Humbug/Test/SelfUpdate/_files/build/src/new/run.php eFvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php eжSvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php eP,Wvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php eU]vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php eﱶHvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php eFvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php e bIvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php enCvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php{ e{[Evendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php] e] fDvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php eݽs:Gvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php eg-Kvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php ehLvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php  e UL Nvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php eKRvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php ehjLvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php e6Fvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php e9s!qBvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php e Dvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.phpq eq )Evendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php e 8YJvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php e+jmEvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php eVѶCvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.phpQ eQ j:Cvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php e f$M_Fvendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php e ]O9vendor/phpdocumentor/reflection-docblock/src/DocBlock.php e-h@vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php?% e?%lIvendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.phpu eu KHvendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php e滐Ӷ6vendor/phpdocumentor/reflection-docblock/src/Utils.php e TFp8vendor/phpdocumentor/type-resolver/src/FqsenResolver.php eg5vendor/phpdocumentor/type-resolver/src/PseudoType.phpm em~Avendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShape.phpZ eZEvendor/phpdocumentor/type-resolver/src/PseudoTypes/ArrayShapeItem.php e*rEvendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.phpA eAMFvendor/phpdocumentor/type-resolver/src/PseudoTypes/ConstExpression.phpX eX,=vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.phpQ eQG>Avendor/phpdocumentor/type-resolver/src/PseudoTypes/FloatValue.php[ e[0Hvendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.phpH eH;FCvendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php e Cvendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerValue.php_ e_wh<vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.phpo eo DDvendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php? e?nEFvendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.phpC eCX4Fvendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php< e<+1Cvendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyList.php eANvendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.phpU eUcEvendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.phpB eBozfDvendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php? e?ٶ?vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php eDFvendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php< e<f:Bvendor/phpdocumentor/type-resolver/src/PseudoTypes/StringValue.php e TBvendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php; e;oʶ<vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.phpM eM46/vendor/phpdocumentor/type-resolver/src/Type.php e9ض7vendor/phpdocumentor/type-resolver/src/TypeResolver.phpY eY =vendor/phpdocumentor/type-resolver/src/Types/AbstractList.phpz ezʢ?vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php e m9vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php e#0;7vendor/phpdocumentor/type-resolver/src/Types/Array_.php e8vendor/phpdocumentor/type-resolver/src/Types/Boolean.php_ e_R&gBvendor/phpdocumentor/type-resolver/src/Types/CallableParameter.phpn enTH8:vendor/phpdocumentor/type-resolver/src/Types/Callable_.php e<vendor/phpdocumentor/type-resolver/src/Types/ClassString.php e$*;vendor/phpdocumentor/type-resolver/src/Types/Collection.phpz ez9vendor/phpdocumentor/type-resolver/src/Types/Compound.php e ݲ8vendor/phpdocumentor/type-resolver/src/Types/Context.php e (&H?vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php9 e9W@f;vendor/phpdocumentor/type-resolver/src/Types/Expression.php eH7vendor/phpdocumentor/type-resolver/src/Types/Float_.php^ e^|=Ͷ8vendor/phpdocumentor/type-resolver/src/Types/Integer.php[ e[0@vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php e)=vendor/phpdocumentor/type-resolver/src/Types/Intersection.php ez:vendor/phpdocumentor/type-resolver/src/Types/Iterable_.php9 e9pQ7vendor/phpdocumentor/type-resolver/src/Types/Mixed_.phpq eqk7vendor/phpdocumentor/type-resolver/src/Types/Never_.php e-S9vendor/phpdocumentor/type-resolver/src/Types/Nullable.phpJ eJ26vendor/phpdocumentor/type-resolver/src/Types/Null_.phpi eiJ8vendor/phpdocumentor/type-resolver/src/Types/Object_.php emE8vendor/phpdocumentor/type-resolver/src/Types/Parent_.php e*ж:vendor/phpdocumentor/type-resolver/src/Types/Resource_.phpp epJ7vendor/phpdocumentor/type-resolver/src/Types/Scalar.php e9]@b6vendor/phpdocumentor/type-resolver/src/Types/Self_.php ec8vendor/phpdocumentor/type-resolver/src/Types/Static_.php e_%8vendor/phpdocumentor/type-resolver/src/Types/String_.phpd ed[5vendor/phpdocumentor/type-resolver/src/Types/This.phpJ eJ'J6vendor/phpdocumentor/type-resolver/src/Types/Void_.php e5_<vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php eR#2vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php/ e/NgIvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.phph ehhEvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php e0Evendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php  e 1Evendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php ePGvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php eR@vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php ewu{Dvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php  e [Fvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php eܻDvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php  e 9]Avendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.phps esDENvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php eE{xPvendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php e qQ-vendor/phpstan/phpdoc-parser/src/Ast/Node.php\ e\,7vendor/phpstan/phpdoc-parser/src/Ast/NodeAttributes.phpY eY#|7n6vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php e `Cvendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php ep4vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php e \\Hvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php` e`b+#dJvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.phpj ej߅Bvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php e^Fvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php eؼKvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php eJG[Ivendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.phpN eN¶Fvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php% e%*YJvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php eHLMvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php ewCvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.phpk ek~!Cvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php eEQ Fvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.phpn enжCvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php e**Bvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php6 e6~NPKvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php eaAvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.phpT eT?UDvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php ehѶAvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php e̛"?vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php e:vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php# e#X=vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php e$rBvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php efc:>vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.phpx exDvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php ed/Jvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php] e]BMvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php` e`gѶBvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.phpU eUlBCvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.phpX eX4'4(Dvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php e >Bvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.phpU eU23Kvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.phpT eT ~жEvendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php+ e+|Ivendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php e_Ŷ@vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.phph ehV?vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php e_@vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php eI,<vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.phpS eS,f;vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php4 e4>vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php eԢ Gvendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php4 e4}PMvendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php eà0Avendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php| e|*;vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php e"5e=vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.phpf ef.F#@vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.phps esn"Bvendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php eڶ=vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php e:F>vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php{ e{HɶAvendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php ejϏ=vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php esBvendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php e-ٶ:vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php eP+ 6vendor/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php e7P;vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php ej:f0vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.phph ehA};vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php" e"FZ;vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php eLf8vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php e;vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php e&~M'9vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php eїe6vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.phpm em\5vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.phpk ek6%3vendor/phpstan/phpdoc-parser/src/Printer/Differ.php eX4vendor/phpstan/phpdoc-parser/src/Printer/Printer.phpOl eOl | 8vendor/psr/container/src/ContainerExceptionInterface.php e^33/vendor/psr/container/src/ContainerInterface.php e7vendor/psr/container/src/NotFoundExceptionInterface.php e>悶<vendor/psr/event-dispatcher/src/EventDispatcherInterface.php e'a=vendor/psr/event-dispatcher/src/ListenerProviderInterface.php  e e;vendor/psr/event-dispatcher/src/StoppableEventInterface.php e7vendor/psr/http-client/src/ClientExceptionInterface.php e:.vendor/psr/http-client/src/ClientInterface.php eҞv 8vendor/psr/http-client/src/NetworkExceptionInterface.php e"78vendor/psr/http-client/src/RequestExceptionInterface.phpJ eJEu7vendor/psr/http-factory/src/RequestFactoryInterface.php erTX8vendor/psr/http-factory/src/ResponseFactoryInterface.php" e"X=vendor/psr/http-factory/src/ServerRequestFactoryInterface.php eBHA6vendor/psr/http-factory/src/StreamFactoryInterface.php eyۜ<vendor/psr/http-factory/src/UploadedFileFactoryInterface.phpV eV!3vendor/psr/http-factory/src/UriFactoryInterface.phpE eEDh0vendor/psr/http-message/src/MessageInterface.php e?0vendor/psr/http-message/src/RequestInterface.php7 e7_81vendor/psr/http-message/src/ResponseInterface.phpJ eJ bY66vendor/psr/http-message/src/ServerRequestInterface.php:( e:(iP:^/vendor/psr/http-message/src/StreamInterface.php eжJ5vendor/psr/http-message/src/UploadedFileInterface.php eZݶ,vendor/psr/http-message/src/UriInterface.php2 e2o%vendor/psr/log/src/AbstractLogger.php eۛ/vendor/psr/log/src/InvalidArgumentException.php` e` X1+vendor/psr/log/src/LoggerAwareInterface.php/ e/~'vendor/psr/log/src/LoggerAwareTrait.php e>&vendor/psr/log/src/LoggerInterface.phpA eA AaH"vendor/psr/log/src/LoggerTrait.phpw ew vendor/psr/log/src/LogLevel.phpP eP!vendor/psr/log/src/NullLogger.php eK;4vendor/ralouphie/getallheaders/src/getallheaders.phph ehz&vendor/symfony/console/Application.php e-˶.vendor/symfony/console/Attribute/AsCommand.php] e]֚2vendor/symfony/console/CI/GithubActionReporter.phpO eO {̂ vendor/symfony/console/Color.php e:㞶*vendor/symfony/console/Command/Command.phpY eYqO2vendor/symfony/console/Command/CompleteCommand.php5$ e5$E~8vendor/symfony/console/Command/DumpCompletionCommand.php@ e@˶.vendor/symfony/console/Command/HelpCommand.php e ^r.vendor/symfony/console/Command/LazyCommand.php e7B.vendor/symfony/console/Command/ListCommand.php e ǥB0vendor/symfony/console/Command/LockableTrait.php e5fF=vendor/symfony/console/Command/SignalableCommandInterface.php^ e^Ȩ03vendor/symfony/console/Command/TraceableCommand.php8( e8(ѢY?vendor/symfony/console/CommandLoader/CommandLoaderInterface.php* e* 8?vendor/symfony/console/CommandLoader/ContainerCommandLoader.php e-.=vendor/symfony/console/CommandLoader/FactoryCommandLoader.php! e!.U5vendor/symfony/console/Completion/CompletionInput.php e|;vendor/symfony/console/Completion/CompletionSuggestions.phpF eF$*Avendor/symfony/console/Completion/Output/BashCompletionOutput.php eSFvendor/symfony/console/Completion/Output/CompletionOutputInterface.php e3OAvendor/symfony/console/Completion/Output/FishCompletionOutput.php e+Ƕ@vendor/symfony/console/Completion/Output/ZshCompletionOutput.php eyZ10vendor/symfony/console/Completion/Suggestion.php; e;We(vendor/symfony/console/ConsoleEvents.php~ e~~6!vendor/symfony/console/Cursor.php e웶=vendor/symfony/console/DataCollector/CommandDataCollector.php e{OP+vendor/symfony/console/Debug/CliRequest.phpU eUvrDvendor/symfony/console/DependencyInjection/AddConsoleCommandPass.phps esZU<vendor/symfony/console/Descriptor/ApplicationDescription.php e=30vendor/symfony/console/Descriptor/Descriptor.php_ e_ j9vendor/symfony/console/Descriptor/DescriptorInterface.phpQ eQm'4vendor/symfony/console/Descriptor/JsonDescriptor.php8 e8A/8vendor/symfony/console/Descriptor/MarkdownDescriptor.php e厺@vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php) e)q M4vendor/symfony/console/Descriptor/TextDescriptor.php/ e/'L3vendor/symfony/console/Descriptor/XmlDescriptor.php/& e/&4vendor/symfony/console/Event/ConsoleCommandEvent.php. e.2vendor/symfony/console/Event/ConsoleErrorEvent.php eH8-vendor/symfony/console/Event/ConsoleEvent.phpP eP^O3vendor/symfony/console/Event/ConsoleSignalEvent.php e_W6vendor/symfony/console/Event/ConsoleTerminateEvent.php e996vendor/symfony/console/EventListener/ErrorListener.php@ e@ \`==vendor/symfony/console/Exception/CommandNotFoundException.php eb07vendor/symfony/console/Exception/ExceptionInterface.php el=vendor/symfony/console/Exception/InvalidArgumentException.php eu i;vendor/symfony/console/Exception/InvalidOptionException.php e/el3vendor/symfony/console/Exception/LogicException.php eSML:vendor/symfony/console/Exception/MissingInputException.php eQg;?vendor/symfony/console/Exception/NamespaceNotFoundException.php eBLH>vendor/symfony/console/Exception/RunCommandFailedException.phpQ eQ9QS?5vendor/symfony/console/Exception/RuntimeException.php e*b8vendor/symfony/console/Formatter/NullOutputFormatter.php e%=vendor/symfony/console/Formatter/NullOutputFormatterStyle.phpY eYq/04vendor/symfony/console/Formatter/OutputFormatter.php e vq =vendor/symfony/console/Formatter/OutputFormatterInterface.php e`)9vendor/symfony/console/Formatter/OutputFormatterStyle.php e lsBvendor/symfony/console/Formatter/OutputFormatterStyleInterface.php e&>vendor/symfony/console/Formatter/OutputFormatterStyleStack.php e XǿFvendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php e#ó6vendor/symfony/console/Helper/DebugFormatterHelper.php e gFF2vendor/symfony/console/Helper/DescriptorHelper.phpM eM Mr϶(vendor/symfony/console/Helper/Dumper.php$ e$zn!1vendor/symfony/console/Helper/FormatterHelper.php eq9(vendor/symfony/console/Helper/Helper.php ehѕ[1vendor/symfony/console/Helper/HelperInterface.phpI eI@Ɔ+vendor/symfony/console/Helper/HelperSet.phpI eIf&2vendor/symfony/console/Helper/InputAwareHelper.php e‚/vendor/symfony/console/Helper/OutputWrapper.php e wy!/vendor/symfony/console/Helper/ProcessHelper.php e-vendor/symfony/console/Helper/ProgressBar.php4M e4M;3vendor/symfony/console/Helper/ProgressIndicator.phpP ePūo0vendor/symfony/console/Helper/QuestionHelper.php~M e~MW7vendor/symfony/console/Helper/SymfonyQuestionHelper.php e 5ȶ'vendor/symfony/console/Helper/Table.php| e|+q+vendor/symfony/console/Helper/TableCell.php e 0vendor/symfony/console/Helper/TableCellStyle.php eNt+vendor/symfony/console/Helper/TableRows.phpN eN$0vendor/symfony/console/Helper/TableSeparator.php e& ,vendor/symfony/console/Helper/TableStyle.php1 e1D*vendor/symfony/console/Input/ArgvInput.php0 e0V島+vendor/symfony/console/Input/ArrayInput.php eEҶ&vendor/symfony/console/Input/Input.phpD eDv.vendor/symfony/console/Input/InputArgument.php e3A4vendor/symfony/console/Input/InputAwareInterface.phpU eU}U0vendor/symfony/console/Input/InputDefinition.php. e.v˜/vendor/symfony/console/Input/InputInterface.phpU eU@-x,vendor/symfony/console/Input/InputOption.php.! e.!9vendor/symfony/console/Input/StreamableInputInterface.php e&,vendor/symfony/console/Input/StringInput.php e p^E-/vendor/symfony/console/Logger/ConsoleLogger.php e96vendor/symfony/console/Messenger/RunCommandContext.php& e&b76vendor/symfony/console/Messenger/RunCommandMessage.php emr=vendor/symfony/console/Messenger/RunCommandMessageHandler.php+ e+޴t/vendor/symfony/console/Output/AnsiColorMode.php e <(0vendor/symfony/console/Output/BufferedOutput.phpF eF+n/vendor/symfony/console/Output/ConsoleOutput.php  e j8vendor/symfony/console/Output/ConsoleOutputInterface.php/ e/Rж6vendor/symfony/console/Output/ConsoleSectionOutput.php! e!5,vendor/symfony/console/Output/NullOutput.php# e#S(vendor/symfony/console/Output/Output.php e/4E1vendor/symfony/console/Output/OutputInterface.php e '.vendor/symfony/console/Output/StreamOutput.php e B5vendor/symfony/console/Output/TrimmedBufferOutput.php0 e08ȶ2vendor/symfony/console/Question/ChoiceQuestion.php etDW*8vendor/symfony/console/Question/ConfirmationQuestion.php! e!O!,vendor/symfony/console/Question/Question.php e84vendor/symfony/console/Resources/bin/hiddeninput.exe$ e$v3vendor/symfony/console/SignalRegistry/SignalMap.php ev'8vendor/symfony/console/SignalRegistry/SignalRegistry.php eD'O#3vendor/symfony/console/SingleCommandApplication.php eŶ,vendor/symfony/console/Style/OutputStyle.phps es K8L/vendor/symfony/console/Style/StyleInterface.php e PF-vendor/symfony/console/Style/SymfonyStyle.php; e;*V?#vendor/symfony/console/Terminal.php e3vendor/symfony/console/Tester/ApplicationTester.phpm em ǣnf9vendor/symfony/console/Tester/CommandCompletionTester.php eR/vendor/symfony/console/Tester/CommandTester.phpG eG Sb@vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php  e [-vendor/symfony/console/Tester/TesterTrait.php3 e37Q1vendor/symfony/deprecation-contracts/function.php eOݶ=vendor/symfony/event-dispatcher/Attribute/AsEventListener.php eUBvendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php`0 e`0 =9vendor/symfony/event-dispatcher/Debug/WrappedListener.php e `Kvendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php{ e{׶Mvendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php! e!3vendor/symfony/event-dispatcher/EventDispatcher.php$# e$#[<vendor/symfony/event-dispatcher/EventDispatcherInterface.php ee:<vendor/symfony/event-dispatcher/EventSubscriberInterface.php es0vendor/symfony/event-dispatcher/GenericEvent.php e <vendor/symfony/event-dispatcher/ImmutableEventDispatcher.phpz ezTjƶ3vendor/symfony/event-dispatcher-contracts/Event.php eс@Fvendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php ev:vendor/symfony/filesystem/Exception/ExceptionInterface.php e nj=vendor/symfony/filesystem/Exception/FileNotFoundException.php e Fʹ@vendor/symfony/filesystem/Exception/InvalidArgumentException.php e*3vendor/symfony/filesystem/Exception/IOException.php e#<vendor/symfony/filesystem/Exception/IOExceptionInterface.php e'~i8vendor/symfony/filesystem/Exception/RuntimeException.php eiҶ(vendor/symfony/filesystem/Filesystem.phpq eq3"vendor/symfony/filesystem/Path.phpxe exe&1vendor/symfony/finder/Adapter/AbstractAdapter.php e8k5vendor/symfony/finder/Adapter/AbstractFindAdapter.php?* e?*2vendor/symfony/finder/Adapter/AdapterInterface.php e”0vendor/symfony/finder/Adapter/BsdFindAdapter.php e J+0vendor/symfony/finder/Adapter/GnuFindAdapter.php e ͂,vendor/symfony/finder/Adapter/PhpAdapter.phpq eq ҔT/vendor/symfony/finder/Comparator/Comparator.php ep3vendor/symfony/finder/Comparator/DateComparator.php eGö5vendor/symfony/finder/Comparator/NumberComparator.php e 9vendor/symfony/finder/Exception/AccessDeniedException.php ecW޶;vendor/symfony/finder/Exception/AdapterFailureException.php e6vendor/symfony/finder/Exception/ExceptionInterface.php e7Avendor/symfony/finder/Exception/OperationNotPermitedException.phpr er[&=@vendor/symfony/finder/Exception/ShellCommandFailureException.php[ e[/vendor/symfony/finder/Expression/Expression.php e R4)vendor/symfony/finder/Expression/Glob.php! e!NŜ̶*vendor/symfony/finder/Expression/Regex.phpW eW3vendor/symfony/finder/Expression/ValueInterface.php eyz< vendor/symfony/finder/Finder.phpa eai^vendor/symfony/finder/Glob.php e 27vendor/symfony/finder/Iterator/CustomFilterIterator.php e :vendor/symfony/finder/Iterator/DateRangeFilterIterator.php e@;vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php eAvendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php e ,<vendor/symfony/finder/Iterator/FilecontentFilterIterator.php er~9vendor/symfony/finder/Iterator/FilenameFilterIterator.php e p4vendor/symfony/finder/Iterator/FilePathsIterator.phpS eS +Q9vendor/symfony/finder/Iterator/FileTypeFilterIterator.php> e>pY1vendor/symfony/finder/Iterator/FilterIterator.php e8=/=vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php e 55vendor/symfony/finder/Iterator/PathFilterIterator.php e}=vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php eyM:vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php e:~ж3vendor/symfony/finder/Iterator/SortableIterator.php e v0ZN'vendor/symfony/finder/Shell/Command.phpQ eQ%vendor/symfony/finder/Shell/Shell.phpM eM9%vendor/symfony/finder/SplFileInfo.phpW eW!tVb+vendor/symfony/polyfill-ctype/bootstrap.php@ e@jQ9-vendor/symfony/polyfill-ctype/bootstrap80.phpr erF)'vendor/symfony/polyfill-ctype/Ctype.php exs+vendor/symfony/polyfill-iconv/bootstrap.php eZ-vendor/symfony/polyfill-iconv/bootstrap80.php e|2'vendor/symfony/polyfill-iconv/Iconv.phpaX eaX3e=vendor/symfony/polyfill-iconv/Resources/charset/from.big5.php e>vendor/symfony/polyfill-iconv/Resources/charset/from.cp037.php es1 ?vendor/symfony/polyfill-iconv/Resources/charset/from.cp1006.php exB ɶ?vendor/symfony/polyfill-iconv/Resources/charset/from.cp1026.php e#޶>vendor/symfony/polyfill-iconv/Resources/charset/from.cp424.php e >vendor/symfony/polyfill-iconv/Resources/charset/from.cp437.php eU(>vendor/symfony/polyfill-iconv/Resources/charset/from.cp500.php e0pIq>vendor/symfony/polyfill-iconv/Resources/charset/from.cp737.php eA>vendor/symfony/polyfill-iconv/Resources/charset/from.cp775.php ewgܶ>vendor/symfony/polyfill-iconv/Resources/charset/from.cp850.php e0/>vendor/symfony/polyfill-iconv/Resources/charset/from.cp852.php e`i>vendor/symfony/polyfill-iconv/Resources/charset/from.cp855.php eb|>vendor/symfony/polyfill-iconv/Resources/charset/from.cp856.phpz ez U>vendor/symfony/polyfill-iconv/Resources/charset/from.cp857.php erP>vendor/symfony/polyfill-iconv/Resources/charset/from.cp860.php e>>vendor/symfony/polyfill-iconv/Resources/charset/from.cp861.php eKW>vendor/symfony/polyfill-iconv/Resources/charset/from.cp862.php e|>vendor/symfony/polyfill-iconv/Resources/charset/from.cp863.php eŬ>vendor/symfony/polyfill-iconv/Resources/charset/from.cp864.php eLtw>vendor/symfony/polyfill-iconv/Resources/charset/from.cp865.php e?*>vendor/symfony/polyfill-iconv/Resources/charset/from.cp866.php eD;>vendor/symfony/polyfill-iconv/Resources/charset/from.cp869.php\ e\K>vendor/symfony/polyfill-iconv/Resources/charset/from.cp874.phpR eR i>vendor/symfony/polyfill-iconv/Resources/charset/from.cp875.php e *>vendor/symfony/polyfill-iconv/Resources/charset/from.cp932.php  e gCG>vendor/symfony/polyfill-iconv/Resources/charset/from.cp936.php; e;DH>vendor/symfony/polyfill-iconv/Resources/charset/from.cp949.phpr er >vendor/symfony/polyfill-iconv/Resources/charset/from.cp950.php  e ~VCvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-1.php ez;7Dvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-10.php eRDvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-11.php e2 Dvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-13.php e94|Dvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-14.php elDvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-15.php eXQжDvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-16.php e1MCvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-2.php eCvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-3.phpZ eZcCvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-4.php ej Cvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-5.php e&Cvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-6.php e \Cvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-7.phpl eldlACvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-8.php e ͩŶCvendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-9.php exz?vendor/symfony/polyfill-iconv/Resources/charset/from.koi8-r.php e uň?vendor/symfony/polyfill-iconv/Resources/charset/from.koi8-u.php eB4Avendor/symfony/polyfill-iconv/Resources/charset/from.us-ascii.phpC eCOPgEvendor/symfony/polyfill-iconv/Resources/charset/from.windows-1250.php e Evendor/symfony/polyfill-iconv/Resources/charset/from.windows-1251.php eZԶEvendor/symfony/polyfill-iconv/Resources/charset/from.windows-1252.php eȫ˶Evendor/symfony/polyfill-iconv/Resources/charset/from.windows-1253.php e CжEvendor/symfony/polyfill-iconv/Resources/charset/from.windows-1254.phpk ekEvendor/symfony/polyfill-iconv/Resources/charset/from.windows-1255.php~ e~ @Evendor/symfony/polyfill-iconv/Resources/charset/from.windows-1256.php eJTEvendor/symfony/polyfill-iconv/Resources/charset/from.windows-1257.php  e ,Evendor/symfony/polyfill-iconv/Resources/charset/from.windows-1258.phpN eNO ߶<vendor/symfony/polyfill-iconv/Resources/charset/translit.php! e!^ӎ3vendor/symfony/polyfill-intl-grapheme/bootstrap.php e5vendor/symfony/polyfill-intl-grapheme/bootstrap80.phpg eg E{2vendor/symfony/polyfill-intl-grapheme/Grapheme.php8& e8&I.vendor/symfony/polyfill-intl-idn/bootstrap.php en~0vendor/symfony/polyfill-intl-idn/bootstrap80.php e7`Z(vendor/symfony/polyfill-intl-idn/Idn.phpv ev1q$)vendor/symfony/polyfill-intl-idn/Info.php e&u{@vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.phpS eSH}Avendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php̭ ḙPGvendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php" e"0Mvendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.phpB eBdLvendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php eu >vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php e]P*=vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.phpK eK͎<vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php eRo̶=vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.phpU eUж5vendor/symfony/polyfill-intl-normalizer/bootstrap.php e#p 7vendor/symfony/polyfill-intl-normalizer/bootstrap80.php e,6vendor/symfony/polyfill-intl-normalizer/Normalizer.phpd% ed%uFvendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php e%Rvendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.phpD eD'CԶTvendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php{ e{jeLvendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.phpD5 eD5 Xvendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.phpo eoc,.vendor/symfony/polyfill-mbstring/bootstrap.phpV eVm<0vendor/symfony/polyfill-mbstring/bootstrap80.phpa# ea#,-vendor/symfony/polyfill-mbstring/Mbstring.php} e}{.LBvendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.phpa ea |⳶@vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php_ e_dFvendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php9 e9>|zK@vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.phpf efP+vendor/symfony/polyfill-php72/bootstrap.php eF f'vendor/symfony/polyfill-php72/Php72.php e 7vendor/symfony/process/Exception/ExceptionInterface.php e+=vendor/symfony/process/Exception/InvalidArgumentException.php e˅3vendor/symfony/process/Exception/LogicException.php eW;vendor/symfony/process/Exception/ProcessFailedException.php e7V=vendor/symfony/process/Exception/ProcessSignaledException.php er+=vendor/symfony/process/Exception/ProcessTimedOutException.php e[>vendor/symfony/process/Exception/RunProcessFailedException.php eU-.5vendor/symfony/process/Exception/RuntimeException.php e>H+vendor/symfony/process/ExecutableFinder.phpu eu _&vendor/symfony/process/InputStream.php e ض6vendor/symfony/process/Messenger/RunProcessContext.phpt et䌻p6vendor/symfony/process/Messenger/RunProcessMessage.php eQ=vendor/symfony/process/Messenger/RunProcessMessageHandler.php e^|Ķ.vendor/symfony/process/PhpExecutableFinder.php: e: %vendor/symfony/process/PhpProcess.php e e6>(vendor/symfony/process/PhpSubprocess.php eQɶ.vendor/symfony/process/Pipes/AbstractPipes.php e(d/vendor/symfony/process/Pipes/PipesInterface.php e\ *vendor/symfony/process/Pipes/UnixPipes.php eĶ-vendor/symfony/process/Pipes/WindowsPipes.php e|6"vendor/symfony/process/Process.php eR'!'vendor/symfony/process/ProcessUtils.php e^Ѷ7vendor/symfony/service-contracts/Attribute/Required.php ee;Z@vendor/symfony/service-contracts/Attribute/SubscribedService.php eОy3vendor/symfony/service-contracts/ResetInterface.php  e 񁒳8vendor/symfony/service-contracts/ServiceLocatorTrait.phpA eAe;=vendor/symfony/service-contracts/ServiceProviderInterface.phpf efζ?vendor/symfony/service-contracts/ServiceSubscriberInterface.php e Ŵ;vendor/symfony/service-contracts/ServiceSubscriberTrait.php' e' +<vendor/symfony/service-contracts/Test/ServiceLocatorTest.php e_8@vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.phpi ei D:4 (vendor/symfony/string/AbstractString.phpI eIݍo/vendor/symfony/string/AbstractUnicodeString.phpd edZ(?$vendor/symfony/string/ByteString.php49 e49@̶)vendor/symfony/string/CodePointString.php$ e$0 6vendor/symfony/string/Exception/ExceptionInterface.phpQ eQ$ն<vendor/symfony/string/Exception/InvalidArgumentException.php ee4vendor/symfony/string/Exception/RuntimeException.phpp ep0ʶ4vendor/symfony/string/Inflector/EnglishInflector.php? e?W[3vendor/symfony/string/Inflector/FrenchInflector.phpK eKn@6vendor/symfony/string/Inflector/InflectorInterface.phpC eCQcc$vendor/symfony/string/LazyString.php e*Ҷ<vendor/symfony/string/Resources/data/wcswidth_table_wide.php.1 e.1Pu<vendor/symfony/string/Resources/data/wcswidth_table_zero.php: e:-vendor/symfony/string/Resources/functions.phpT eT0.vendor/symfony/string/Slugger/AsciiSlugger.php en2vendor/symfony/string/Slugger/SluggerInterface.php e"O'vendor/symfony/string/UnicodeString.php0 e00vendor/voku/anti-xss/src/voku/helper/AntiXSS.php7  e7  ?_?vendor/voku/anti-xss/src/voku/helper/data/entities_fallback.php eȲ=3!vendor/voku/arrayy/src/Arrayy.phpD~ eD~<)vendor/voku/arrayy/src/ArrayyIterator.php; e; @%vendor/voku/arrayy/src/ArrayyMeta.phpf efLn<vendor/voku/arrayy/src/ArrayyRewindableExtendedGenerator.php e?Ҷ4vendor/voku/arrayy/src/ArrayyRewindableGenerator.php7 e7 'vendor/voku/arrayy/src/ArrayyStrict.php es 8vendor/voku/arrayy/src/Collection/AbstractCollection.php1, e1,r0vendor/voku/arrayy/src/Collection/Collection.php e,?'9vendor/voku/arrayy/src/Collection/CollectionInterface.php< e<W!vendor/voku/arrayy/src/Create.php e&vendor/voku/arrayy/src/Mapper/Json.phpad ead]'vendor/voku/arrayy/src/StaticArrayy.phpY eY k/vendor/voku/arrayy/src/Type/ArrayCollection.php eS93vendor/voku/arrayy/src/Type/BoolArrayCollection.php eG0.vendor/voku/arrayy/src/Type/BoolCollection.php| e|늺2vendor/voku/arrayy/src/Type/CallableCollection.php eeUж>vendor/voku/arrayy/src/Type/DetectFirstValueTypeCollection.php ez4vendor/voku/arrayy/src/Type/FloatArrayCollection.php e&ɓ/vendor/voku/arrayy/src/Type/FloatCollection.php e@$ֶ7vendor/voku/arrayy/src/Type/FloatIntArrayCollection.php e;(2vendor/voku/arrayy/src/Type/FloatIntCollection.php e?in2vendor/voku/arrayy/src/Type/InstanceCollection.php e7d3vendor/voku/arrayy/src/Type/InstancesCollection.php  e 2vendor/voku/arrayy/src/Type/IntArrayCollection.php e ùĶ-vendor/voku/arrayy/src/Type/IntCollection.phpy eyn:vendor/voku/arrayy/src/Type/JsonSerializableCollection.php euĘa/vendor/voku/arrayy/src/Type/MixedCollection.php e^?[8vendor/voku/arrayy/src/Type/NonEmptyStringCollection.php eW(1vendor/voku/arrayy/src/Type/NumericCollection.php} e}7vendor/voku/arrayy/src/Type/NumericStringCollection.php e|0vendor/voku/arrayy/src/Type/ObjectCollection.php euɶ2vendor/voku/arrayy/src/Type/ResourceCollection.php e W#0vendor/voku/arrayy/src/Type/ScalarCollection.php eVZ2vendor/voku/arrayy/src/Type/StdClassCollection.php eF5vendor/voku/arrayy/src/Type/StringArrayCollection.php eA$0vendor/voku/arrayy/src/Type/StringCollection.php| e|]-vendor/voku/arrayy/src/Type/TypeInterface.php; e;(Mȶ6vendor/voku/arrayy/src/TypeCheck/AbstractTypeCheck.php ey 3vendor/voku/arrayy/src/TypeCheck/TypeCheckArray.php$ e$*F6vendor/voku/arrayy/src/TypeCheck/TypeCheckCallback.php ee7vendor/voku/arrayy/src/TypeCheck/TypeCheckInterface.php3 e3K4vendor/voku/arrayy/src/TypeCheck/TypeCheckPhpDoc.php eܝ4vendor/voku/arrayy/src/TypeCheck/TypeCheckSimple.php e?vendor/voku/email-check/src/voku/helper/data/domainsExample.php eQhAvendor/voku/email-check/src/voku/helper/data/domainsTemporary.php eNٶ<vendor/voku/email-check/src/voku/helper/data/domainsTypo.php ey6vendor/voku/email-check/src/voku/helper/EmailCheck.php" e"*)4vendor/voku/portable-ascii/src/voku/helper/ASCII.php eEgFvendor/voku/portable-ascii/src/voku/helper/data/ascii_by_languages.phpi ei7zOMvendor/voku/portable-ascii/src/voku/helper/data/ascii_extras_by_languages.phprG erG31Jvendor/voku/portable-ascii/src/voku/helper/data/ascii_language_max_key.php9 e9 8=vendor/voku/portable-ascii/src/voku/helper/data/ascii_ord.php eF_8vendor/voku/portable-ascii/src/voku/helper/data/x000.phps es:`,8vendor/voku/portable-ascii/src/voku/helper/data/x001.php7 e7>{88vendor/voku/portable-ascii/src/voku/helper/data/x002.php? e?48vendor/voku/portable-ascii/src/voku/helper/data/x003.php1 e1jyȶ8vendor/voku/portable-ascii/src/voku/helper/data/x004.php eU98vendor/voku/portable-ascii/src/voku/helper/data/x005.php eq䈋8vendor/voku/portable-ascii/src/voku/helper/data/x006.php e:~=L8vendor/voku/portable-ascii/src/voku/helper/data/x007.php( e(898vendor/voku/portable-ascii/src/voku/helper/data/x009.php e8vendor/voku/portable-ascii/src/voku/helper/data/x00a.php' e'_,8vendor/voku/portable-ascii/src/voku/helper/data/x00b.php2 e2p)8vendor/voku/portable-ascii/src/voku/helper/data/x00c.php e+L8vendor/voku/portable-ascii/src/voku/helper/data/x00d.php' e'O8vendor/voku/portable-ascii/src/voku/helper/data/x00e.php  e Աz8vendor/voku/portable-ascii/src/voku/helper/data/x00f.php e_c^H8vendor/voku/portable-ascii/src/voku/helper/data/x010.php e8vendor/voku/portable-ascii/src/voku/helper/data/x011.php5 e598vendor/voku/portable-ascii/src/voku/helper/data/x012.php eK8vendor/voku/portable-ascii/src/voku/helper/data/x013.php etL8vendor/voku/portable-ascii/src/voku/helper/data/x014.php e- 8vendor/voku/portable-ascii/src/voku/helper/data/x015.php ekFi8vendor/voku/portable-ascii/src/voku/helper/data/x016.php: e:~8vendor/voku/portable-ascii/src/voku/helper/data/x017.phpl el>+Ŷ8vendor/voku/portable-ascii/src/voku/helper/data/x018.php eb`i8vendor/voku/portable-ascii/src/voku/helper/data/x01d.php e?8vendor/voku/portable-ascii/src/voku/helper/data/x01e.php e8vendor/voku/portable-ascii/src/voku/helper/data/x01f.phpP ePc8vendor/voku/portable-ascii/src/voku/helper/data/x020.php ey8vendor/voku/portable-ascii/src/voku/helper/data/x021.php eHrBt8vendor/voku/portable-ascii/src/voku/helper/data/x022.php e(O38vendor/voku/portable-ascii/src/voku/helper/data/x023.php eCJy8vendor/voku/portable-ascii/src/voku/helper/data/x024.php eoa8vendor/voku/portable-ascii/src/voku/helper/data/x025.php* e*|8vendor/voku/portable-ascii/src/voku/helper/data/x026.php e=18vendor/voku/portable-ascii/src/voku/helper/data/x027.php eH8vendor/voku/portable-ascii/src/voku/helper/data/x028.php e )'@8vendor/voku/portable-ascii/src/voku/helper/data/x029.php eI8vendor/voku/portable-ascii/src/voku/helper/data/x02a.php eö8vendor/voku/portable-ascii/src/voku/helper/data/x02c.php eH8vendor/voku/portable-ascii/src/voku/helper/data/x02e.php= e=K8vendor/voku/portable-ascii/src/voku/helper/data/x02f.php e&8vendor/voku/portable-ascii/src/voku/helper/data/x030.phpM eM E<8vendor/voku/portable-ascii/src/voku/helper/data/x031.php+ e+`ж8vendor/voku/portable-ascii/src/voku/helper/data/x032.php eA*Sܶ8vendor/voku/portable-ascii/src/voku/helper/data/x033.php em%\8vendor/voku/portable-ascii/src/voku/helper/data/x04d.php e2m[68vendor/voku/portable-ascii/src/voku/helper/data/x04e.php* e*Rq8vendor/voku/portable-ascii/src/voku/helper/data/x04f.php en8vendor/voku/portable-ascii/src/voku/helper/data/x050.phpN eN8vendor/voku/portable-ascii/src/voku/helper/data/x051.phpQ eQw$Ͷ8vendor/voku/portable-ascii/src/voku/helper/data/x052.php2 e2v8vendor/voku/portable-ascii/src/voku/helper/data/x053.php  e ]p8vendor/voku/portable-ascii/src/voku/helper/data/x054.php eж8vendor/voku/portable-ascii/src/voku/helper/data/x055.php eUb'8vendor/voku/portable-ascii/src/voku/helper/data/x056.php  e EC8vendor/voku/portable-ascii/src/voku/helper/data/x057.php e.,8vendor/voku/portable-ascii/src/voku/helper/data/x058.phpJ eJz>8vendor/voku/portable-ascii/src/voku/helper/data/x059.php( e(zv8vendor/voku/portable-ascii/src/voku/helper/data/x05a.php  e 08vendor/voku/portable-ascii/src/voku/helper/data/x05b.php@ e@38vendor/voku/portable-ascii/src/voku/helper/data/x05c.php e[~8vendor/voku/portable-ascii/src/voku/helper/data/x05d.phpB eB8vendor/voku/portable-ascii/src/voku/helper/data/x05e.php@ e@P8vendor/voku/portable-ascii/src/voku/helper/data/x05f.php8 e8ab8vendor/voku/portable-ascii/src/voku/helper/data/x060.php& e&8vendor/voku/portable-ascii/src/voku/helper/data/x061.php: e:8vendor/voku/portable-ascii/src/voku/helper/data/x062.php eͶ8vendor/voku/portable-ascii/src/voku/helper/data/x063.php4 e4c8vendor/voku/portable-ascii/src/voku/helper/data/x064.php3 e3738vendor/voku/portable-ascii/src/voku/helper/data/x065.php" e")D68vendor/voku/portable-ascii/src/voku/helper/data/x066.phpI eI?S8vendor/voku/portable-ascii/src/voku/helper/data/x067.php eNG8vendor/voku/portable-ascii/src/voku/helper/data/x068.phpF eFhKf8vendor/voku/portable-ascii/src/voku/helper/data/x069.phpE eE@Z8vendor/voku/portable-ascii/src/voku/helper/data/x06a.phpF eFMGP8vendor/voku/portable-ascii/src/voku/helper/data/x06b.php eR@8vendor/voku/portable-ascii/src/voku/helper/data/x06c.php' e'D8vendor/voku/portable-ascii/src/voku/helper/data/x06d.php/ e/8vendor/voku/portable-ascii/src/voku/helper/data/x06e.php$ e$'Ҷ8vendor/voku/portable-ascii/src/voku/helper/data/x06f.php. e.48vendor/voku/portable-ascii/src/voku/helper/data/x070.phpY eY808vendor/voku/portable-ascii/src/voku/helper/data/x071.phpB eBY8vendor/voku/portable-ascii/src/voku/helper/data/x072.php7 e7ž,8vendor/voku/portable-ascii/src/voku/helper/data/x073.php* e*Y8vendor/voku/portable-ascii/src/voku/helper/data/x074.php\ e\aA8vendor/voku/portable-ascii/src/voku/helper/data/x075.phpG eG7ζ8vendor/voku/portable-ascii/src/voku/helper/data/x076.php# e#x 8vendor/voku/portable-ascii/src/voku/helper/data/x077.phpG eG 8vendor/voku/portable-ascii/src/voku/helper/data/x078.php, e,08vendor/voku/portable-ascii/src/voku/helper/data/x079.php e|_78vendor/voku/portable-ascii/src/voku/helper/data/x07a.phpA eA_&08vendor/voku/portable-ascii/src/voku/helper/data/x07b.phpA eAO8vendor/voku/portable-ascii/src/voku/helper/data/x07c.php; e;k˶8vendor/voku/portable-ascii/src/voku/helper/data/x07d.phpJ eJzDP8vendor/voku/portable-ascii/src/voku/helper/data/x07e.phpN eNB 8vendor/voku/portable-ascii/src/voku/helper/data/x07f.php< e<8vendor/voku/portable-ascii/src/voku/helper/data/x080.php/ e/Ug8vendor/voku/portable-ascii/src/voku/helper/data/x081.phpE eEZ8vendor/voku/portable-ascii/src/voku/helper/data/x082.php- e-B`l8vendor/voku/portable-ascii/src/voku/helper/data/x083.php' e'l8vendor/voku/portable-ascii/src/voku/helper/data/x084.php* e*I8vendor/voku/portable-ascii/src/voku/helper/data/x085.php  e Q8vendor/voku/portable-ascii/src/voku/helper/data/x086.php  e F2Q8vendor/voku/portable-ascii/src/voku/helper/data/x087.php- e-8vendor/voku/portable-ascii/src/voku/helper/data/x088.php) e)s+8vendor/voku/portable-ascii/src/voku/helper/data/x089.php ek8vendor/voku/portable-ascii/src/voku/helper/data/x08a.php+ e+OUӶ8vendor/voku/portable-ascii/src/voku/helper/data/x08b.php' e'*'38vendor/voku/portable-ascii/src/voku/helper/data/x08c.php e˛8vendor/voku/portable-ascii/src/voku/helper/data/x08d.php  e 98vendor/voku/portable-ascii/src/voku/helper/data/x08e.php7 e7DG8vendor/voku/portable-ascii/src/voku/helper/data/x08f.php/ e/8vendor/voku/portable-ascii/src/voku/helper/data/x090.php e! 8vendor/voku/portable-ascii/src/voku/helper/data/x091.php3 e3gŶ8vendor/voku/portable-ascii/src/voku/helper/data/x092.php, e,^W8vendor/voku/portable-ascii/src/voku/helper/data/x093.php> e>h8vendor/voku/portable-ascii/src/voku/helper/data/x094.php9 e9JHܶ8vendor/voku/portable-ascii/src/voku/helper/data/x095.phpC eC}XǶ8vendor/voku/portable-ascii/src/voku/helper/data/x096.php e8vendor/voku/portable-ascii/src/voku/helper/data/x097.php' e'+8vendor/voku/portable-ascii/src/voku/helper/data/x098.php) e)w8vendor/voku/portable-ascii/src/voku/helper/data/x099.php e8vendor/voku/portable-ascii/src/voku/helper/data/x09a.php eUk8vendor/voku/portable-ascii/src/voku/helper/data/x09b.php3 e3Q8vendor/voku/portable-ascii/src/voku/helper/data/x09c.php7 e7E8vendor/voku/portable-ascii/src/voku/helper/data/x09d.php e 'ݶ8vendor/voku/portable-ascii/src/voku/helper/data/x09e.php  e G8vendor/voku/portable-ascii/src/voku/helper/data/x09f.php e-(*8vendor/voku/portable-ascii/src/voku/helper/data/x0a0.phpP eP5SC8vendor/voku/portable-ascii/src/voku/helper/data/x0a1.phpy eyt8vendor/voku/portable-ascii/src/voku/helper/data/x0a2.php e)ٶ8vendor/voku/portable-ascii/src/voku/helper/data/x0a3.php eǗζ8vendor/voku/portable-ascii/src/voku/helper/data/x0a4.phpc ec|8vendor/voku/portable-ascii/src/voku/helper/data/x0ac.phpi ei[ 8vendor/voku/portable-ascii/src/voku/helper/data/x0ad.php e8vendor/voku/portable-ascii/src/voku/helper/data/x0ae.php e ޕ"8vendor/voku/portable-ascii/src/voku/helper/data/x0af.php e 6w8vendor/voku/portable-ascii/src/voku/helper/data/x0b0.php eJص8vendor/voku/portable-ascii/src/voku/helper/data/x0b1.php eAR¶8vendor/voku/portable-ascii/src/voku/helper/data/x0b2.phpL eL8vendor/voku/portable-ascii/src/voku/helper/data/x0b3.php e@M8vendor/voku/portable-ascii/src/voku/helper/data/x0b4.php e8vendor/voku/portable-ascii/src/voku/helper/data/x0b5.php; e; 18vendor/voku/portable-ascii/src/voku/helper/data/x0b6.php e *8vendor/voku/portable-ascii/src/voku/helper/data/x0b7.php ei/8vendor/voku/portable-ascii/src/voku/helper/data/x0b8.phpn en]z8vendor/voku/portable-ascii/src/voku/helper/data/x0b9.phpd edض8vendor/voku/portable-ascii/src/voku/helper/data/x0ba.php e#8vendor/voku/portable-ascii/src/voku/helper/data/x0bb.php~ e~ ö8vendor/voku/portable-ascii/src/voku/helper/data/x0bc.phpg egX8vendor/voku/portable-ascii/src/voku/helper/data/x0bd.php e__/8vendor/voku/portable-ascii/src/voku/helper/data/x0be.php eGH8vendor/voku/portable-ascii/src/voku/helper/data/x0bf.php e rI8vendor/voku/portable-ascii/src/voku/helper/data/x0c0.php e~8vendor/voku/portable-ascii/src/voku/helper/data/x0c1.php eR]8vendor/voku/portable-ascii/src/voku/helper/data/x0c2.phpj ej98vendor/voku/portable-ascii/src/voku/helper/data/x0c3.phps es K'8vendor/voku/portable-ascii/src/voku/helper/data/x0c4.php e 8vendor/voku/portable-ascii/src/voku/helper/data/x0c5.php evKq18vendor/voku/portable-ascii/src/voku/helper/data/x0c6.php e`8vendor/voku/portable-ascii/src/voku/helper/data/x0c7.php e @8vendor/voku/portable-ascii/src/voku/helper/data/x0c8.php et͟ 8vendor/voku/portable-ascii/src/voku/helper/data/x0c9.phpv ev2xl8vendor/voku/portable-ascii/src/voku/helper/data/x0ca.php e +88vendor/voku/portable-ascii/src/voku/helper/data/x0cb.php e Id8vendor/voku/portable-ascii/src/voku/helper/data/x0cc.php e!>8vendor/voku/portable-ascii/src/voku/helper/data/x0cd.php e3$z]8vendor/voku/portable-ascii/src/voku/helper/data/x0ce.phph ehMUq8vendor/voku/portable-ascii/src/voku/helper/data/x0cf.phpm em\q@8vendor/voku/portable-ascii/src/voku/helper/data/x0d0.phpf efwTF8vendor/voku/portable-ascii/src/voku/helper/data/x0d1.php eEQ~8vendor/voku/portable-ascii/src/voku/helper/data/x0d2.phpx ex4۶8vendor/voku/portable-ascii/src/voku/helper/data/x0d3.phpe eeoKnڶ8vendor/voku/portable-ascii/src/voku/helper/data/x0d4.php er;*8vendor/voku/portable-ascii/src/voku/helper/data/x0d5.phpL eLE@8vendor/voku/portable-ascii/src/voku/helper/data/x0d6.php e8;8vendor/voku/portable-ascii/src/voku/helper/data/x0d7.php eң8vendor/voku/portable-ascii/src/voku/helper/data/x0f9.php e ~fI8vendor/voku/portable-ascii/src/voku/helper/data/x0fa.phpD eDE8vendor/voku/portable-ascii/src/voku/helper/data/x0fb.php ebΞ8vendor/voku/portable-ascii/src/voku/helper/data/x0fc.php e}~8vendor/voku/portable-ascii/src/voku/helper/data/x0fd.phpU eUm۶8vendor/voku/portable-ascii/src/voku/helper/data/x0fe.php eG8vendor/voku/portable-ascii/src/voku/helper/data/x0ff.php e7{M8vendor/voku/portable-ascii/src/voku/helper/data/x1d4.phpf efe8vendor/voku/portable-ascii/src/voku/helper/data/x1d5.php eD 8vendor/voku/portable-ascii/src/voku/helper/data/x1d6.php e:l_8vendor/voku/portable-ascii/src/voku/helper/data/x1d7.phpA eAB8vendor/voku/portable-ascii/src/voku/helper/data/x1f1.phpM eMޑ7'vendor/voku/portable-utf8/bootstrap.php ej4vendor/voku/portable-utf8/src/voku/helper/Bootup.php_ e_ 2|Cvendor/voku/portable-utf8/src/voku/helper/data/caseFolding_full.php eJ26vendor/voku/portable-utf8/src/voku/helper/data/chr.php eK8vendor/voku/portable-utf8/src/voku/helper/data/emoji.php e=ζ<vendor/voku/portable-utf8/src/voku/helper/data/encodings.phpE eE_S6vendor/voku/portable-utf8/src/voku/helper/data/ord.phpg egu68Fvendor/voku/portable-utf8/src/voku/helper/data/transliterator_list.phpy8 ey8};vendor/voku/portable-utf8/src/voku/helper/data/utf8_fix.php  e  ޟBvendor/voku/portable-utf8/src/voku/helper/data/win1252_to_utf8.phpN eN] 2vendor/voku/portable-utf8/src/voku/helper/UTF8.php) e)%N}7vendor/voku/stop-words/src/voku/helper/stopwords/ar.php e 7vendor/voku/stop-words/src/voku/helper/stopwords/bg.php e~ݶ7vendor/voku/stop-words/src/voku/helper/stopwords/ca.php e[7vendor/voku/stop-words/src/voku/helper/stopwords/cz.phpF eF 倶7vendor/voku/stop-words/src/voku/helper/stopwords/da.php( e(q;7vendor/voku/stop-words/src/voku/helper/stopwords/de.php: e:+7vendor/voku/stop-words/src/voku/helper/stopwords/el.php es}7vendor/voku/stop-words/src/voku/helper/stopwords/en.php eug<7vendor/voku/stop-words/src/voku/helper/stopwords/eo.phpm em}u7vendor/voku/stop-words/src/voku/helper/stopwords/es.phpi eigA7vendor/voku/stop-words/src/voku/helper/stopwords/et.php e8L5 7vendor/voku/stop-words/src/voku/helper/stopwords/fi.php e l7vendor/voku/stop-words/src/voku/helper/stopwords/fr.php' e'vD7vendor/voku/stop-words/src/voku/helper/stopwords/hi.php e\RS7vendor/voku/stop-words/src/voku/helper/stopwords/hr.php eܶ7vendor/voku/stop-words/src/voku/helper/stopwords/hu.php e x߶7vendor/voku/stop-words/src/voku/helper/stopwords/id.php e(A7vendor/voku/stop-words/src/voku/helper/stopwords/it.phpp ep޶7vendor/voku/stop-words/src/voku/helper/stopwords/ka.php1 e1/Ԥ̶7vendor/voku/stop-words/src/voku/helper/stopwords/lt.php7 e7`7vendor/voku/stop-words/src/voku/helper/stopwords/lv.php eqZܶ7vendor/voku/stop-words/src/voku/helper/stopwords/nl.php eAA_7vendor/voku/stop-words/src/voku/helper/stopwords/no.php} e}Ķ7vendor/voku/stop-words/src/voku/helper/stopwords/pl.php eּvö7vendor/voku/stop-words/src/voku/helper/stopwords/pt.php e l,rͶ7vendor/voku/stop-words/src/voku/helper/stopwords/ro.phpO eO ˳7vendor/voku/stop-words/src/voku/helper/stopwords/ru.phpL eL rǶ7vendor/voku/stop-words/src/voku/helper/stopwords/sk.phpq eqk7vendor/voku/stop-words/src/voku/helper/stopwords/sv.php e7vendor/voku/stop-words/src/voku/helper/stopwords/tr.php e.A7vendor/voku/stop-words/src/voku/helper/stopwords/uk.php e 7vendor/voku/stop-words/src/voku/helper/stopwords/vi.php") e")@h4vendor/voku/stop-words/src/voku/helper/StopWords.php e O"Evendor/voku/stop-words/src/voku/helper/StopWordsLanguageNotExists.php e]y6-vendor/voku/stringy/src/CollectionStringy.php2 e2 zH"vendor/voku/stringy/src/Create.php e)vendor/voku/stringy/src/StaticStringy.php;1 e;1Z#vendor/voku/stringy/src/Stringy.phpN eN2[-vendor/voku/urlify/src/voku/helper/URLify.phpQ eQ虎&vendor/webmozart/assert/src/Assert.php6 e6\18vendor/webmozart/assert/src/InvalidArgumentException.php[ e[*i%vendor/webmozart/assert/src/Mixin.php e.A'vendor/weew/helpers-array/src/array.php! e!a-vendor/weew/helpers-array/tests/ArrayTest.phpb$ eb$^-vendor/weew/helpers-array/tests/bootstrap.php2 e2!ö array ( 'type' => 'php', 'condition' => '>=7.0', 'message' => 'The application requires the version ">=7.0" or greater.', 'helpMessage' => 'The application requires the version ">=7.0" or greater.', ), 1 => array ( 'type' => 'extension', 'condition' => 'openssl', 'message' => 'The package "defuse/php-encryption" requires the extension "openssl". Enable it or install a polyfill.', 'helpMessage' => 'The package "defuse/php-encryption" requires the extension "openssl".', ), 2 => array ( 'type' => 'extension', 'condition' => 'json', 'message' => 'The package "guzzlehttp/guzzle" requires the extension "json". Enable it or install a polyfill.', 'helpMessage' => 'The package "guzzlehttp/guzzle" requires the extension "json".', ), 3 => array ( 'type' => 'extension', 'condition' => 'json', 'message' => 'The package "voku/arrayy" requires the extension "json". Enable it or install a polyfill.', 'helpMessage' => 'The package "voku/arrayy" requires the extension "json".', ), 4 => array ( 'type' => 'extension', 'condition' => 'json', 'message' => 'The package "voku/stringy" requires the extension "json". Enable it or install a polyfill.', 'helpMessage' => 'The package "voku/stringy" requires the extension "json".', ), 5 => array ( 'type' => 'extension', 'condition' => 'filter', 'message' => 'The package "phpdocumentor/reflection-docblock" requires the extension "filter". Enable it or install a polyfill.', 'helpMessage' => 'The package "phpdocumentor/reflection-docblock" requires the extension "filter".', ), );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) { 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'); $printer->printvln('> PHP is using the following php.ini file:', $verbosity); if ($iniPath) { $printer->printvln(' ' . $iniPath, $verbosity, 'green'); } else { $printer->printvln(' WARNING: No configuration file (php.ini) used by PHP!', $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 = array(); 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->getHelpText(), 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() { if (null === self::$requirementsConfig) { self::$requirementsConfig = __DIR__ . '/../.requirements.php'; } $config = (require self::$requirementsConfig); $requirements = new RequirementCollection(); foreach ($config as $constraint) { $requirements->addRequirement('php' === $constraint['type'] ? new IsPhpVersionFulfilled($constraint['condition']) : new IsExtensionFulfilled($constraint['condition']), $constraint['message'], $constraint['helpMessage']); } return $requirements; } } options = \implode(' ', $_SERVER['argv']); $shellVerbosity = $this->configureVerbosity(); $this->interactive = $this->checkInteractivity($shellVerbosity); $this->colorSupport = $this->checkColorSupport(); } public function isInteractive() { return $this->interactive; } public function getVerbosity() { return $this->verbosity; } public function hasColorSupport() { return $this->colorSupport; } public function hasParameter($values) { $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($shellVerbosity) { if (-1 === $shellVerbosity) { return \false; } if (\true === $this->hasParameter(array('--no-interaction', '-n'))) { return \false; } if (\function_exists('posix_isatty') && !@\posix_isatty(\STDOUT) && \false === \getenv('SHELL_INTERACTIVE')) { return \false; } return \true; } private function configureVerbosity() { 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(array('--quiet', '-q'))) { $this->verbosity = self::VERBOSITY_QUIET; $shellVerbosity = -1; } elseif ($this->hasParameter(array('-vvv', '--verbose=3', '--verbose 3'))) { $this->verbosity = self::VERBOSITY_DEBUG; $shellVerbosity = 3; } elseif ($this->hasParameter(array('-vv', '--verbose=2', '--verbose 2'))) { $this->verbosity = self::VERBOSITY_VERY_VERBOSE; $shellVerbosity = 2; } elseif ($this->hasParameter(array('-v', '--verbose=1', '--verbose 1', '--verbose'))) { $this->verbosity = self::VERBOSITY_VERBOSE; $shellVerbosity = 1; } return $shellVerbosity; } private function checkColorSupport() { if ($this->hasParameter(array('--ansi'))) { return \true; } if ($this->hasParameter(array('--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; } } requiredExtension = $requiredExtension; } public function __invoke() { return \extension_loaded($this->requiredExtension); } } requiredPhpVersion = $requiredPhpVersion; } public function __invoke() { return Semver::satisfies(\sprintf('%d.%d.%d', \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, \PHP_RELEASE_VERSION), $this->requiredPhpVersion); } } "\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($verbosity, $supportColors, $width = null) { if (null === $width) { $terminal = new Terminal(); $width = $terminal->getWidth(); } $this->verbosity = $verbosity; $this->supportColors = $supportColors; $this->width = $width ?: 80; } public function getVerbosity() { return $this->verbosity; } public function setVerbosity($verbosity) { $this->verbosity = $verbosity; } public function title($title, $verbosity, $style = null) { 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) { if ($requirement->isFulfilled()) { return null; } $errorMessage = \wordwrap($requirement->getTestMessage(), $this->width - 3, \PHP_EOL . ' ') . \PHP_EOL; return $errorMessage; } public function block($title, $message, $verbosity, $style = null) { $prefix = ' [' . $title . '] '; $lineLength = $this->width - \strlen($prefix) - 1; if ($lineLength < 0) { $lineLength = 0; } $message = $prefix . \trim($message); $lines = array(); $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($message, $verbosity, $style = null) { $this->printv($message, $verbosity, $style); $this->printv(\PHP_EOL, $verbosity, null); } public function printv($message, $verbosity, $style = null) { 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'] : ''); echo $message; } } checkIsFulfilled = $checkIsFulfilled; $this->testMessage = $testMessage; $this->helpText = $helpText; } public function isFulfilled() { if (null === $this->fulfilled) { $this->fulfilled = $this->checkIsFulfilled->__invoke(); } return (bool) $this->fulfilled; } public function getIsFullfilledChecker() { return $this->checkIsFulfilled; } public function getTestMessage() { return $this->testMessage; } public function getHelpText() { return $this->helpText; } } requirements); } #[ReturnTypeWillChange] public function count() { return \count($this->requirements); } public function add(Requirement $requirement) { $this->requirements[] = $requirement; } public function addRequirement($checkIsFulfilled, $testMessage, $helpText) { $this->add(new Requirement($checkIsFulfilled, $testMessage, $helpText)); } public function getRequirements() { return $this->requirements; } public function getPhpIniPath() { return \get_cfg_var('cfg_file_path'); } public function evaluateRequirements() { return \array_reduce($this->requirements, function ($checkPassed, Requirement $requirement) { return $checkPassed && $requirement->isFulfilled(); }, \true); } } &1', $output, $exitcode); return self::$stty = 0 === $exitcode; } private static function initDimensions() { 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() { return \function_exists('sapi_windows_vt100_support') && \sapi_windows_vt100_support(\fopen('php://stdout', 'wb')); } private static function initDimensionsUsingStty() { 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() { $info = self::readFromProcess('mode CON'); if (null === $info || !\preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) { return null; } return array((int) $matches[2], (int) $matches[1]); } private static function getSttyColumns() { return self::readFromProcess('stty -a | grep columns'); } private static function readFromProcess($command) { if (!\function_exists('proc_open')) { return null; } $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); $process = \proc_open($command, $descriptorspec, $pipes, null, null, array('suppress_errors' => \true)); if (!\is_resource($process)) { return null; } $info = \stream_get_contents($pipes[1]); \fclose($pipes[1]); \fclose($pipes[2]); \proc_close($process); return $info; } } $vendorDir . '/composer/InstalledVersions.php', 'HumbugBox3160\\Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php', 'HumbugBox3160\\Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php', 'HumbugBox3160\\Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php', 'HumbugBox3160\\Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php', 'HumbugBox3160\\Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php', 'HumbugBox3160\\Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Checker' => $baseDir . '/src/Checker.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IO' => $baseDir . '/src/IO.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IsExtensionFulfilled' => $baseDir . '/src/IsExtensionFulfilled.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IsFulfilled' => $baseDir . '/src/IsFulfilled.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IsPhpVersionFulfilled' => $baseDir . '/src/IsPhpVersionFulfilled.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Printer' => $baseDir . '/src/Printer.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Requirement' => $baseDir . '/src/Requirement.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\RequirementCollection' => $baseDir . '/src/RequirementCollection.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Terminal' => $baseDir . '/src/Terminal.php', ); array($baseDir . '/src'), 'HumbugBox3160\\Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'), ); = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInitf2436c64f9ae7d02cbb00119cae714ea::getInitializer($loader)); } else { $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } } $loader->setClassMapAuthoritative(true); $loader->register(true); return $loader; } } array ( 'HumbugBox3160\\KevinGH\\RequirementChecker\\' => 41, 'HumbugBox3160\\Composer\\Semver\\' => 30, ), ); public static $prefixDirsPsr4 = array ( 'HumbugBox3160\\KevinGH\\RequirementChecker\\' => array ( 0 => __DIR__ . '/../..' . '/src', ), 'HumbugBox3160\\Composer\\Semver\\' => array ( 0 => __DIR__ . '/..' . '/composer/semver/src', ), ); public static $classMap = array ( 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'HumbugBox3160\\Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php', 'HumbugBox3160\\Composer\\Semver\\CompilingMatcher' => __DIR__ . '/..' . '/composer/semver/src/CompilingMatcher.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\Bound' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Bound.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\MatchAllConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchAllConstraint.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchNoneConstraint.php', 'HumbugBox3160\\Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php', 'HumbugBox3160\\Composer\\Semver\\Interval' => __DIR__ . '/..' . '/composer/semver/src/Interval.php', 'HumbugBox3160\\Composer\\Semver\\Intervals' => __DIR__ . '/..' . '/composer/semver/src/Intervals.php', 'HumbugBox3160\\Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php', 'HumbugBox3160\\Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Checker' => __DIR__ . '/../..' . '/src/Checker.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IO' => __DIR__ . '/../..' . '/src/IO.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IsExtensionFulfilled' => __DIR__ . '/../..' . '/src/IsExtensionFulfilled.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IsFulfilled' => __DIR__ . '/../..' . '/src/IsFulfilled.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\IsPhpVersionFulfilled' => __DIR__ . '/../..' . '/src/IsPhpVersionFulfilled.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Printer' => __DIR__ . '/../..' . '/src/Printer.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Requirement' => __DIR__ . '/../..' . '/src/Requirement.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\RequirementCollection' => __DIR__ . '/../..' . '/src/RequirementCollection.php', 'HumbugBox3160\\KevinGH\\RequirementChecker\\Terminal' => __DIR__ . '/../..' . '/src/Terminal.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInitf2436c64f9ae7d02cbb00119cae714ea::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInitf2436c64f9ae7d02cbb00119cae714ea::$prefixDirsPsr4; $loader->classMap = ComposerStaticInitf2436c64f9ae7d02cbb00119cae714ea::$classMap; }, null, ClassLoader::class); } } * Jordi Boggiano * * 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 * @author Jordi Boggiano * @see https://www.php-fig.org/psr/psr-0/ * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { /** @var ?string */ private $vendorDir; // PSR-4 /** * @var array[] * @psalm-var array> */ private $prefixLengthsPsr4 = array(); /** * @var array[] * @psalm-var array> */ private $prefixDirsPsr4 = array(); /** * @var array[] * @psalm-var array */ private $fallbackDirsPsr4 = array(); // PSR-0 /** * @var array[] * @psalm-var array> */ private $prefixesPsr0 = array(); /** * @var array[] * @psalm-var array */ private $fallbackDirsPsr0 = array(); /** @var bool */ private $useIncludePath = false; /** * @var string[] * @psalm-var array */ private $classMap = array(); /** @var bool */ private $classMapAuthoritative = false; /** * @var bool[] * @psalm-var array */ private $missingClasses = array(); /** @var ?string */ private $apcuPrefix; /** * @var self[] */ private static $registeredLoaders = array(); /** * @param ?string $vendorDir */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; } /** * @return string[] */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } /** * @return array[] * @psalm-return array> */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } /** * @return array[] * @psalm-return array */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } /** * @return array[] * @psalm-return array */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } /** * @return string[] Array of classname => path * @psalm-return array */ public function getClassMap() { return $this->classMap; } /** * @param string[] $classMap Class to filename map * @psalm-param array $classMap * * @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 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) { if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( (array) $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, (array) $paths ); } return; } $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { $this->prefixesPsr0[$first][$prefix] = (array) $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( (array) $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], (array) $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 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) { if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( (array) $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, (array) $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] = (array) $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( (array) $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], (array) $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 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 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($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 indexed by their corresponding vendor directories. * * @return 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; } } /** * Scope isolated include. * * Prevents access to $this/self from included files. * * @param string $file * @return void * @private */ function includeFile($file) { include $file; } array('pretty_version' => '3.16.0', 'version' => '3.16.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => 'adb282ad00a20438fc881f8ec9207ed7446243b9', 'name' => 'humbug/requirement-checker', 'dev' => \true), 'versions' => array('composer/semver' => array('pretty_version' => '3.2.0', 'version' => '3.2.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/./semver', 'aliases' => array(), 'reference' => 'da7ce661431b17a71271cdf7f5437dc722133123', 'dev_requirement' => \false), 'doctrine/instantiator' => array('pretty_version' => '1.4.0', 'version' => '1.4.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/instantiator', 'aliases' => array(), 'reference' => 'd56bf6102915de5702778fe20f2de3b2fe570b5b', 'dev_requirement' => \true), 'humbug/requirement-checker' => array('pretty_version' => '3.16.0', 'version' => '3.16.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => 'adb282ad00a20438fc881f8ec9207ed7446243b9', 'dev_requirement' => \false), 'myclabs/deep-copy' => array('pretty_version' => '1.10.2', 'version' => '1.10.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../myclabs/deep-copy', 'aliases' => array(), 'reference' => '776f831124e9c62e1a2c601ecc52e776d8bb7220', 'dev_requirement' => \true, 'replaced' => array(0 => '1.10.2')), 'nikic/php-parser' => array('pretty_version' => 'v4.10.3', 'version' => '4.10.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), 'reference' => 'dbe56d23de8fcb157bbc0cfb3ad7c7de0cfb0984', 'dev_requirement' => \true), 'phar-io/manifest' => array('pretty_version' => '2.0.1', 'version' => '2.0.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/manifest', 'aliases' => array(), 'reference' => '85265efd3af7ba3ca4b2a2c34dbfc5788dd29133', 'dev_requirement' => \true), 'phar-io/version' => array('pretty_version' => '3.0.3', 'version' => '3.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/version', 'aliases' => array(), 'reference' => '726c026815142e4f8677b7cb7f2249c9ffb7ecae', 'dev_requirement' => \true), 'phpdocumentor/reflection-common' => array('pretty_version' => '2.2.0', 'version' => '2.2.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-common', 'aliases' => array(), 'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b', 'dev_requirement' => \true), 'phpdocumentor/reflection-docblock' => array('pretty_version' => '5.2.2', 'version' => '5.2.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock', 'aliases' => array(), 'reference' => '069a785b2141f5bcf49f3e353548dc1cce6df556', 'dev_requirement' => \true), 'phpdocumentor/type-resolver' => array('pretty_version' => '1.4.0', 'version' => '1.4.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'aliases' => array(), 'reference' => '6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0', 'dev_requirement' => \true), 'phpspec/prophecy' => array('pretty_version' => '1.12.1', 'version' => '1.12.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpspec/prophecy', 'aliases' => array(), 'reference' => '8ce87516be71aae9b956f81906aaf0338e0d8a2d', 'dev_requirement' => \true), 'phpunit/php-code-coverage' => array('pretty_version' => '9.2.5', 'version' => '9.2.5.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'aliases' => array(), 'reference' => 'f3e026641cc91909d421802dd3ac7827ebfd97e1', 'dev_requirement' => \true), 'phpunit/php-file-iterator' => array('pretty_version' => '3.0.5', 'version' => '3.0.5.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-file-iterator', 'aliases' => array(), 'reference' => 'aa4be8575f26070b100fccb67faabb28f21f66f8', 'dev_requirement' => \true), 'phpunit/php-invoker' => array('pretty_version' => '3.1.1', 'version' => '3.1.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-invoker', 'aliases' => array(), 'reference' => '5a10147d0aaf65b58940a0b72f71c9ac0423cc67', 'dev_requirement' => \true), 'phpunit/php-text-template' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-text-template', 'aliases' => array(), 'reference' => '5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28', 'dev_requirement' => \true), 'phpunit/php-timer' => array('pretty_version' => '5.0.3', 'version' => '5.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-timer', 'aliases' => array(), 'reference' => '5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2', 'dev_requirement' => \true), 'phpunit/phpunit' => array('pretty_version' => '9.5.0', 'version' => '9.5.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), 'reference' => '8e16c225d57c3d6808014df6b1dd7598d0a5bbbe', 'dev_requirement' => \true), 'sebastian/cli-parser' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/cli-parser', 'aliases' => array(), 'reference' => '442e7c7e687e42adc03470c7b668bc4b2402c0b2', 'dev_requirement' => \true), 'sebastian/code-unit' => array('pretty_version' => '1.0.8', 'version' => '1.0.8.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit', 'aliases' => array(), 'reference' => '1fc9f64c0927627ef78ba436c9b17d967e68e120', 'dev_requirement' => \true), 'sebastian/code-unit-reverse-lookup' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup', 'aliases' => array(), 'reference' => 'ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5', 'dev_requirement' => \true), 'sebastian/comparator' => array('pretty_version' => '4.0.6', 'version' => '4.0.6.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/comparator', 'aliases' => array(), 'reference' => '55f4261989e546dc112258c7a75935a81a7ce382', 'dev_requirement' => \true), 'sebastian/complexity' => array('pretty_version' => '2.0.2', 'version' => '2.0.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/complexity', 'aliases' => array(), 'reference' => '739b35e53379900cc9ac327b2147867b8b6efd88', 'dev_requirement' => \true), 'sebastian/diff' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), 'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d', 'dev_requirement' => \true), 'sebastian/environment' => array('pretty_version' => '5.1.3', 'version' => '5.1.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/environment', 'aliases' => array(), 'reference' => '388b6ced16caa751030f6a69e588299fa09200ac', 'dev_requirement' => \true), 'sebastian/exporter' => array('pretty_version' => '4.0.3', 'version' => '4.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/exporter', 'aliases' => array(), 'reference' => 'd89cc98761b8cb5a1a235a6b703ae50d34080e65', 'dev_requirement' => \true), 'sebastian/global-state' => array('pretty_version' => '5.0.2', 'version' => '5.0.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/global-state', 'aliases' => array(), 'reference' => 'a90ccbddffa067b51f574dea6eb25d5680839455', 'dev_requirement' => \true), 'sebastian/lines-of-code' => array('pretty_version' => '1.0.3', 'version' => '1.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/lines-of-code', 'aliases' => array(), 'reference' => 'c1c2e997aa3146983ed888ad08b15470a2e22ecc', 'dev_requirement' => \true), 'sebastian/object-enumerator' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-enumerator', 'aliases' => array(), 'reference' => '5c9eeac41b290a3712d88851518825ad78f45c71', 'dev_requirement' => \true), 'sebastian/object-reflector' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-reflector', 'aliases' => array(), 'reference' => 'b4f479ebdbf63ac605d183ece17d8d7fe49c15c7', 'dev_requirement' => \true), 'sebastian/recursion-context' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/recursion-context', 'aliases' => array(), 'reference' => 'cd9d8cf3c5804de4341c283ed787f099f5506172', 'dev_requirement' => \true), 'sebastian/resource-operations' => array('pretty_version' => '3.0.3', 'version' => '3.0.3.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/resource-operations', 'aliases' => array(), 'reference' => '0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8', 'dev_requirement' => \true), 'sebastian/type' => array('pretty_version' => '2.3.1', 'version' => '2.3.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/type', 'aliases' => array(), 'reference' => '81cd61ab7bbf2de744aba0ea61fae32f721df3d2', 'dev_requirement' => \true), 'sebastian/version' => array('pretty_version' => '3.0.2', 'version' => '3.0.2.0', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/version', 'aliases' => array(), 'reference' => 'c6c1022351a901512170118436c764e473f6de8c', 'dev_requirement' => \true), 'symfony/polyfill-ctype' => array('pretty_version' => 'v1.20.0', 'version' => '1.20.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'reference' => 'f4ba089a5b6366e453971d3aad5fe8e897b37f41', 'dev_requirement' => \true), 'theseer/tokenizer' => array('pretty_version' => '1.2.0', 'version' => '1.2.0.0', 'type' => 'library', 'install_path' => __DIR__ . '/../theseer/tokenizer', 'aliases' => array(), 'reference' => '75a63c33a8577608444246075ea0af0d052e452a', 'dev_requirement' => \true), 'webmozart/assert' => array('pretty_version' => '1.9.1', 'version' => '1.9.1.0', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'reference' => 'bafc69caeb4d49c39fd0779086c03a3738cbb389', 'dev_requirement' => \true))); $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 || empty($installed['versions'][$packageName]['dev_requirement']); } } return \false; } public static function satisfies(VersionParser $parser, $packageName, $constraint) { $constraint = $parser->parseConstraints($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(); } /** @psalm-return */ private static function getInstalled() { if (null === self::$canGetVendors) { self::$canGetVendors = \method_exists('HumbugBox3160\\Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders'); } $installed = array(); if (self::$canGetVendors) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (\is_file($vendorDir . '/composer/installed.php')) { $installed[] = self::$installedByVendor[$vendorDir] = (require $vendorDir . '/composer/installed.php'); if (null === self::$installed && \strtr($vendorDir . '/composer', '\\', '/') === \strtr(__DIR__, '\\', '/')) { self::$installed = $installed[\count($installed) - 1]; } } } } if (null === self::$installed) { if (\substr(__DIR__, -8, 1) !== 'C') { self::$installed = (require __DIR__ . '/installed.php'); } else { self::$installed = array(); } } $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. ', $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); } public static function compare($version1, $operator, $version2) { $constraint = new Constraint($operator, $version2); return $constraint->matchSpecific(new Constraint('==', $version1), \true); } } '==', Constraint::OP_LT => '<', Constraint::OP_LE => '<=', Constraint::OP_GT => '>', Constraint::OP_GE => '>=', Constraint::OP_NE => '!='); /** @phpstan-param */ public static function match(ConstraintInterface $constraint, $operator, $version) { if (self::$enabled === null) { self::$enabled = !\in_array('eval', \explode(',', \ini_get('disable_functions')), \true); } if (!self::$enabled) { return $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 $function($version, $version[0] === 'd' && 'dev-' === \substr($version, 0, 4)); } } 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); } } 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; 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; } 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(); } public static function getSupportedOperators() { return \array_keys(self::$transOpStr); } /** @phpstan-return */ public static function getOperatorConstant($operator) { return self::$transOpStr[$operator]; } 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 ($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 ($this->version[0] === 'd' && 'dev-' === \substr($this->version, 0, 4)) { 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'; } } elseif (self::OP_GT === $this->operator || self::OP_GE === $this->operator) { 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 && 'dev-' === \substr($provider->version, 0, 4)) { return \false; } if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && 'dev-' === \substr($this->version, 0, 4)) { return \false; } if (!$isEqualOp && !$isProviderEqualOp) { return \true; } return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches); } if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) { if ('dev-' === \substr($this->version, 0, 4) || 'dev-' === \substr($provider->version, 0, 4)) { return \false; } return \true; } $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; } } } 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(); } } 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); } } 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; } 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(); return $this->lowerBound; } public function getUpperBound() { $this->extractBounds(); 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); } 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 MultiConstraint && $left->conjunctive && $right instanceof MultiConstraint && $right->conjunctive && ($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_merge(array($left->constraints[0], $right->constraints[1]), \array_slice($left->constraints, 2), \array_slice($right->constraints, 2)), \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(); } } } } 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); } } =' => -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; $active = \false; $start = null; foreach ($borders as $border) { if ($border['side'] === 'start') { $activeIntervals++; } else { $activeIntervals--; } if (!$active && $activeIntervals >= $activationThreshold) { $start = new Constraint($border['operator'], $border['version']); $active = \true; } if ($active && $activeIntervals < $activationThreshold) { $active = \false; 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 (\substr($constraint->getVersion(), 0, 4) === 'dev-') { $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()); } } 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; } } expandStability($matches[$index]) . (!empty($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(\\d++\\.)*\\d++)(?:\\.x)?-dev$}i', $branch, $matches)) { return $matches['version'] . '.'; } return \false; } public function normalizeBranch($name) { $name = \trim($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 $name; } public function parseConstraints($constraints) { $prettyConstraint = $constraints; $orConstraints = \preg_split('{\\s*\\|\\|?\\s*}', \trim($constraints)); $orGroups = array(); foreach ($orConstraints as $constraints) { $andConstraints = \preg_split('{(?< ,]) *(? 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; } $constraint = MultiConstraint::create($orGroups, \false); $constraint->setPrettyString($prettyConstraint); return $constraint; } 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++|[xX*]))?(?:\\.(\\d++|[xX*]))?(?:\\.(\\d++|[xX*]))?' . self::$modifierRegex . '(?:\\+[^\\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; } for ($i = $position; $i >= 0; $i--) { if ($matches[$i] === 'x' || $matches[$i] === 'X' || $matches[$i] === '*') { $matches[$i] = '9999999'; } } $stabilitySuffix = ''; if (empty($matches[5]) && empty($matches[7])) { $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; } if ($position === 2 && ($matches[2] === 'x' || $matches[2] === 'X' || $matches[2] === '*')) { $position = 1; } $stabilitySuffix = ''; if (empty($matches[5]) && empty($matches[7])) { $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' . $versionRegex . ') +- +(?P' . $versionRegex . ')($)}i', $constraint, $matches)) { $lowStabilitySuffix = ''; if (empty($matches[6]) && empty($matches[8])) { $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[11]) && !$empty($matches[12]) || !empty($matches[14]) || !empty($matches[16])) { $highVersion = $this->normalize($matches['to']); $upperBound = new Constraint('<=', $highVersion); } else { $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]); $this->normalize($matches['to']); $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[11]) ? 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') { $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); } 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] < 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; } } } version); $app->loadCommands(require(__DIR__ . '/../commands.php')); $app->run(); [ '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.9", "description": "A command-line installer for FW-Api and its requisite apps/addons", "minimum-stability": "stable", "require": { "php": ">=7.0", "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", "padraic/phar-updater": "^1.0", "bit3/git-php": "dev-release/1.6.0", "voku/stringy": "~6.5", "jakeasmith/http_build_url": "^1.0", "weew/helpers-array": "^1.3", "guzzlehttp/guzzle": "^7.8", "bennerinformatics/php-path": "^0.1.0", "jakub-onderka/php-console-highlighter": "^0.3.2" }, "require-dev": { "phpunit/phpunit": "^8.0", "squizlabs/php_codesniffer": "^2.8.1", "jakub-onderka/php-parallel-lint": "^0.9.2" }, "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 && move fw.phar ../bin/fw.phar", "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": "f4edaa81697727808c62e523c76a2b18", "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": "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.2", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", "phpstan/phpstan": "1.4.10 || 1.10.15", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "psalm/plugin-phpunit": "0.18.4", "psr/log": "^1 || ^2 || ^3", "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, "type": "library", "autoload": { "psr-4": { "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" } }, "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.2" }, "time": "2023-09-27T20:04:15+00:00" }, { "name": "guzzlehttp/guzzle", "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.5.3 || ^2.0.1", "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", "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": "*", "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.36 || ^9.6.15", "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.8.1" }, "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": "2023-12-03T20:35:24+00:00" }, { "name": "guzzlehttp/promises", "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "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.0.2" }, "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": "2023-12-03T20:19:20+00:00" }, { "name": "guzzlehttp/psr7", "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "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", "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "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.6.2" }, "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": "2023-12-03T20:05:35+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": "jakub-onderka/php-console-color", "version": "v0.2", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", "shasum": "" }, "require": { "php": ">=5.4.0" }, "require-dev": { "jakub-onderka/php-code-style": "1.0", "jakub-onderka/php-parallel-lint": "1.0", "jakub-onderka/php-var-dump-check": "0.*", "phpunit/phpunit": "~4.3", "squizlabs/php_codesniffer": "1.*" }, "type": "library", "autoload": { "psr-4": { "JakubOnderka\\PhpConsoleColor\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-2-Clause" ], "authors": [ { "name": "Jakub Onderka", "email": "jakub.onderka@gmail.com" } ], "support": { "issues": "https://github.com/JakubOnderka/PHP-Console-Color/issues", "source": "https://github.com/JakubOnderka/PHP-Console-Color/tree/master" }, "abandoned": "php-parallel-lint/php-console-color", "time": "2018-09-29T17:23:10+00:00" }, { "name": "jakub-onderka/php-console-highlighter", "version": "v0.3.2", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", "shasum": "" }, "require": { "jakub-onderka/php-console-color": "~0.1", "php": ">=5.3.0" }, "require-dev": { "jakub-onderka/php-code-style": "~1.0", "jakub-onderka/php-parallel-lint": "~0.5", "jakub-onderka/php-var-dump-check": "~0.1", "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~1.5" }, "type": "library", "autoload": { "psr-0": { "JakubOnderka\\PhpConsoleHighlighter": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Jakub Onderka", "email": "acci@acci.cz", "homepage": "http://www.acci.cz/" } ], "support": { "issues": "https://github.com/JakubOnderka/PHP-Console-Highlighter/issues", "source": "https://github.com/JakubOnderka/PHP-Console-Highlighter/tree/master" }, "abandoned": "php-parallel-lint/php-console-highlighter", "time": "2015-04-20T18:58:01+00:00" }, { "name": "padraic/humbug_get_contents", "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/humbug/file_get_contents.git", "reference": "66797199019d0cb4529cb8d29c6f0b4c5085b53a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/humbug/file_get_contents/zipball/66797199019d0cb4529cb8d29c6f0b4c5085b53a", "reference": "66797199019d0cb4529cb8d29c6f0b4c5085b53a", "shasum": "" }, "require": { "php": ">=5.3" }, "require-dev": { "phpunit/phpunit": "~4.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0-dev" } }, "autoload": { "files": [ "src/function.php" ], "psr-4": { "Humbug\\": "src/Humbug/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", "homepage": "http://blog.astrumfutura.com" } ], "description": "Secure wrapper for accessing HTTPS resources with file_get_contents for PHP 5.3+", "homepage": "https://github.com/padraic/file_get_contents", "keywords": [ "download", "file_get_contents", "http", "https", "ssl", "tls" ], "support": { "issues": "https://github.com/padraic/file_get_contents/issues", "source": "https://github.com/humbug/file_get_contents/tree/1.0.4" }, "time": "2015-04-22T18:45:00+00:00" }, { "name": "padraic/phar-updater", "version": "v1.0.6", "source": { "type": "git", "url": "https://github.com/humbug/phar-updater.git", "reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/humbug/phar-updater/zipball/d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1", "reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1", "shasum": "" }, "require": { "padraic/humbug_get_contents": "^1.0", "php": ">=5.3.3" }, "require-dev": { "phpunit/phpunit": "~4.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0-dev" } }, "autoload": { "psr-4": { "Humbug\\SelfUpdate\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", "homepage": "http://blog.astrumfutura.com" } ], "description": "A thing to make PHAR self-updating easy and secure.", "keywords": [ "humbug", "phar", "self-update", "update" ], "support": { "issues": "https://github.com/humbug/phar-updater/issues", "source": "https://github.com/humbug/phar-updater/tree/1.0" }, "abandoned": true, "time": "2018-03-30T12:52:15+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": "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.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { "ext-filter": "*", "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.3", "webmozart/assert": "^1.9.1" }, "require-dev": { "mockery/mockery": "~1.3.2", "psalm/phar": "^4.8" }, "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": "account@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.3.0" }, "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc", "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, "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.8.0" }, "time": "2024-01-11T11:49:22+00:00" }, { "name": "phpstan/phpdoc-parser", "version": "1.25.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240", "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "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/1.25.0" }, "time": "2024-01-04T17:06:16+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.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { "php": ">=7.0.0", "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": "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/tree/1.0.2" }, "time": "2023-04-10T20:10:41+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.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", "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.0" }, "time": "2021-07-14T16:46:02+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.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/console/zipball/0254811a143e6bc6c8deea08b589a7e68a37f625", "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625", "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.2" }, "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": "2023-12-10T16:15:48+00:00" }, { "name": "symfony/deprecation-contracts", "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } }, "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.4.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": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/event-dispatcher", "version": "v6.4.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", "reference": "e95216850555cd55e71b857eb9d6c2674124603a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e95216850555cd55e71b857eb9d6c2674124603a", "reference": "e95216850555cd55e71b857eb9d6c2674124603a", "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.2" }, "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": "2023-12-27T22:16:42+00:00" }, { "name": "symfony/event-dispatcher-contracts", "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, "type": "library", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } }, "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.4.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": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/filesystem", "version": "v6.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/filesystem/zipball/952a8cb588c3bc6ce76f6023000fb932f16a6e59", "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59", "shasum": "" }, "require": { "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "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.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": "2023-07-26T17:27:13+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.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { "ext-ctype": "*" }, "suggest": { "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-iconv", "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/6de50471469b8c9afc38164452ab2b6170ee71c1", "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { "ext-iconv": "*" }, "suggest": { "ext-iconv": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-idn", "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", "shasum": "" }, "require": { "php": ">=7.1", "symfony/polyfill-intl-normalizer": "^1.10", "symfony/polyfill-php72": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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": "2023-01-26T09:30:37+00:00" }, { "name": "symfony/polyfill-intl-normalizer", "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { "ext-mbstring": "*" }, "suggest": { "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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": "2023-07-28T09:04:16+00:00" }, { "name": "symfony/polyfill-php72", "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", "shasum": "" }, "require": { "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, "autoload": { "files": [ "bootstrap.php" ], "psr-4": { "Symfony\\Polyfill\\Php72\\": "" } }, "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.28.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": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/process", "version": "v6.4.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", "reference": "c4b1ef0bc80533d87a2e969806172f1c2a980241" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/process/zipball/c4b1ef0bc80533d87a2e969806172f1c2a980241", "reference": "c4b1ef0bc80533d87a2e969806172f1c2a980241", "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.2" }, "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": "2023-12-22T16:42:54+00:00" }, { "name": "symfony/service-contracts", "version": "v3.4.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", "shasum": "" }, "require": { "php": ">=8.1", "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } }, "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.4.1" }, "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": "2023-12-26T14:02:43+00:00" }, { "name": "symfony/string", "version": "v7.0.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/string/zipball/cc78f14f91f5e53b42044d0620961c48028ff9f5", "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5", "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/error-handler": "^6.4|^7.0", "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.0.2" }, "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": "2023-12-10T16:54:46+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.1", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", "reference": "b56450eed252f6801410d810c8e1727224ae0743" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", "reference": "b56450eed252f6801410d810c8e1727224ae0743", "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": "http://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.1" }, "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": "2022-03-08T17:03:00+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/stringy", "version": "6.5.3", "source": { "type": "git", "url": "https://github.com/voku/Stringy.git", "reference": "c453c88fbff298f042c836ef44306f8703b2d537" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/voku/Stringy/zipball/c453c88fbff298f042c836ef44306f8703b2d537", "reference": "c453c88fbff298f042c836ef44306f8703b2d537", "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" }, "require-dev": { "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" }, "type": "library", "autoload": { "files": [ "src/Create.php" ], "psr-4": { "Stringy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "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": [ "UTF", "helpers", "manipulation", "methods", "multibyte", "string", "utf-8", "utility", "utils" ], "support": { "issues": "https://github.com/voku/Stringy/issues", "source": "https://github.com/voku/Stringy" }, "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/stringy", "type": "tidelift" } ], "time": "2022-03-28T14:52:20+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": "doctrine/instantiator", "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9 || ^11", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^0.16 || ^1", "phpstan/phpstan": "^1.4", "phpstan/phpstan-phpunit": "^1", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "vimeo/psalm": "^4.30 || ^5.4" }, "type": "library", "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", "homepage": "https://ocramius.github.io/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", "source": "https://github.com/doctrine/instantiator/tree/1.5.0" }, "funding": [ { "url": "https://www.doctrine-project.org/sponsorship.html", "type": "custom" }, { "url": "https://www.patreon.com/phpdoctrine", "type": "patreon" }, { "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", "type": "tidelift" } ], "time": "2022-12-30T00:15:36+00:00" }, { "name": "jakub-onderka/php-parallel-lint", "version": "v0.9.2", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Parallel-Lint.git", "reference": "2ead2e4043ab125bee9554f356e0a86742c2d4fa" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/JakubOnderka/PHP-Parallel-Lint/zipball/2ead2e4043ab125bee9554f356e0a86742c2d4fa", "reference": "2ead2e4043ab125bee9554f356e0a86742c2d4fa", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { "jakub-onderka/php-console-highlighter": "~0.3", "nette/tester": "~1.3" }, "suggest": { "jakub-onderka/php-console-highlighter": "Highlight syntax in code snippet" }, "bin": [ "parallel-lint" ], "type": "library", "autoload": { "classmap": [ "./" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-2-Clause" ], "authors": [ { "name": "Jakub Onderka", "email": "jakub.onderka@gmail.com" } ], "description": "This tool check syntax of PHP files about 20x faster than serial check.", "homepage": "https://github.com/JakubOnderka/PHP-Parallel-Lint", "support": { "issues": "https://github.com/JakubOnderka/PHP-Parallel-Lint/issues", "source": "https://github.com/JakubOnderka/PHP-Parallel-Lint/tree/master" }, "abandoned": "php-parallel-lint/php-parallel-lint", "time": "2015-12-15T10:42:16+00:00" }, { "name": "myclabs/deep-copy", "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "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", "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.11.1" }, "funding": [ { "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", "type": "tidelift" } ], "time": "2023-03-08T13:26:56+00:00" }, { "name": "phar-io/manifest", "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { "ext-dom": "*", "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.3" }, "time": "2021-07-20T11:28:43+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": "phpunit/php-code-coverage", "version": "7.0.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", "reference": "819f92bba8b001d4363065928088de22f25a3a48" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/819f92bba8b001d4363065928088de22f25a3a48", "reference": "819f92bba8b001d4363065928088de22f25a3a48", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", "php": ">=7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", "phpunit/php-token-stream": "^3.1.3 || ^4.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1.3" }, "require-dev": { "phpunit/phpunit": "^8.2.2" }, "suggest": { "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "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": "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", "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.15" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2021-07-26T12:20:09+00:00" }, { "name": "phpunit/php-file-iterator", "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "^8.5" }, "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": "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", "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2021-12-02T12:42:26+00:00" }, { "name": "phpunit/php-text-template", "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { "php": ">=5.3.3" }, "type": "library", "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", "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" }, "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.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": "Utility class for timing", "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ "timer" ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T08:20:02+00:00" }, { "name": "phpunit/php-token-stream", "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", "shasum": "" }, "require": { "ext-tokenizer": "*", "php": "^7.3 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "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": "Wrapper around PHP's tokenizer extension.", "homepage": "https://github.com/sebastianbergmann/php-token-stream/", "keywords": [ "tokenizer" ], "support": { "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "abandoned": true, "time": "2020-08-04T08:28:15+00:00" }, { "name": "phpunit/phpunit", "version": "8.5.36", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", "reference": "9652df58e06a681429d8cfdaec3c43d6de581d5a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9652df58e06a681429d8cfdaec3c43d6de581d5a", "reference": "9652df58e06a681429d8cfdaec3c43d6de581d5a", "shasum": "" }, "require": { "doctrine/instantiator": "^1.3.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.0", "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.2", "phpunit/php-code-coverage": "^7.0.12", "phpunit/php-file-iterator": "^2.0.4", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^2.1.2", "sebastian/comparator": "^3.0.5", "sebastian/diff": "^3.0.2", "sebastian/environment": "^4.2.3", "sebastian/exporter": "^3.1.5", "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", "sebastian/resource-operations": "^2.0.1", "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files", "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage", "phpunit/php-invoker": "To allow enforcing time limits" }, "bin": [ "phpunit" ], "type": "library", "extra": { "branch-alias": { "dev-master": "8.5-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": "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/8.5.36" }, "funding": [ { "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { "url": "https://github.com/sebastianbergmann", "type": "github" }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], "time": "2023-12-01T16:52:15+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", "shasum": "" }, "require": { "php": ">=5.6" }, "require-dev": { "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-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", "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T08:15:22+00:00" }, { "name": "sebastian/comparator", "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dc7ceb4a24aede938c7af2a9ed1de09609ca770", "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770", "shasum": "" }, "require": { "php": ">=7.1", "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.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": "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", "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.5" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2022-09-14T12:31:48+00:00" }, { "name": "sebastian/diff", "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6296a0c086dd0117c1b78b059374d7fcbe7545ae", "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "^7.5 || ^8.0", "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.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", "source": "https://github.com/sebastianbergmann/diff/tree/3.0.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2023-05-07T05:30:20+00:00" }, { "name": "sebastian/environment", "version": "4.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "^7.5" }, "suggest": { "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.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": "http://www.github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", "hhvm" ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T07:53:42+00:00" }, { "name": "sebastian/exporter", "version": "3.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/73a9676f2833b9a7c36968f9d882589cd75511e6", "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6", "shasum": "" }, "require": { "php": ">=7.0", "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.1.x-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": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.5" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2022-09-14T06:00:17+00:00" }, { "name": "sebastian/global-state", "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", "reference": "66783ce213de415b451b904bfef9dda0cf9aeae0" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/66783ce213de415b451b904bfef9dda0cf9aeae0", "reference": "66783ce213de415b451b904bfef9dda0cf9aeae0", "shasum": "" }, "require": { "php": ">=7.2", "sebastian/object-reflector": "^1.1.1", "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-dom": "*", "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.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": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2023-08-02T09:23:32+00:00" }, { "name": "sebastian/object-enumerator", "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", "shasum": "" }, "require": { "php": ">=7.0", "sebastian/object-reflector": "^1.1.1", "sebastian/recursion-context": "^3.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0.x-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", "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T07:40:27+00:00" }, { "name": "sebastian/object-reflector", "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", "shasum": "" }, "require": { "php": ">=7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.1-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", "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T07:37:18+00:00" }, { "name": "sebastian/recursion-context", "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", "shasum": "" }, "require": { "php": ">=7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0.x-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": "http://www.github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T07:34:24+00:00" }, { "name": "sebastian/resource-operations", "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", "shasum": "" }, "require": { "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { "issues": "https://github.com/sebastianbergmann/resource-operations/issues", "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T07:30:19+00:00" }, { "name": "sebastian/type", "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", "shasum": "" }, "require": { "php": ">=7.2" }, "require-dev": { "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.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", "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" } ], "time": "2020-11-30T07:25:11+00:00" }, { "name": "sebastian/version", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, "require": { "php": ">=5.6" }, "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": "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", "source": "https://github.com/sebastianbergmann/version/tree/master" }, "time": "2016-10-03T07:35:21+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": "theseer/tokenizer", "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "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.2" }, "funding": [ { "url": "https://github.com/theseer", "type": "github" } ], "time": "2023-11-20T00:12:19+00:00" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": { "bit3/git-php": 20 }, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=7.0" }, "platform-dev": [], "plugin-api-version": "2.3.0" } 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 = Utils\Updater::init($this->getVersion()); if ($updater->hasUpdate()) { $newVersion = $updater->getStrategy()->getCurrentRemoteSemver($updater); $oldVersion = $updater->getStrategy()->getCurrentLocalSemver(); $io->writeln("! [NOTE] A new version of the fw-installer is available.\n!"); $io->writeln("! New Version: {$newVersion}"); $io->writeln("!\n! Current Version: {$oldVersion}"); $io->writeln("!\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]]; }, $commandComnfig['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]]; }, $commandComnfig['options']); } $commands[$commandName] = $command; } } } } } 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); } } 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 * @return int Process exit code */ protected function task(string $name, array $options = [], $message = null, $halt = true) { $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 ]); // 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; } } 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 `: requires prompting the user for an app idea // * the new way: run `fw install `: 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, $version, $installDir, $config); 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); $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 $version = null, string $installDir, Config $rootConfig) { $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; } $this->task('download', [ 'provider' => $provider, 'version' => $typeInfo['version'], '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); } $this->task('git-clone', [ 'dir' => $installDir, 'url' => $url ], 'Cloning app from repository'); $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', []), 'Incompatability 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(); } } } io); } } 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"); } } command = $c; $this->io = $io; $this->input = $input; } /** * Updates the FW installer to the latest version */ public function execute() { $updater = Updater::init($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} (SHA1)." . 'Run `fw self-update --rollback` to revert to the previous version' ); exit(0); } else { $this->io->success('No updated 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); } } } 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', [ 'url' => $availableVersions[$versionToUse], '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() { $client = new Client(); $result = $client->get(self::API_REPO . 'downloads/')->getBody(); $data = json_decode(Psr7\Utils::copyToString($result), true); return array_reduce($data['values'], function (array $carry, array $version) { $matches = []; if (preg_match('/^fw-api-(?P[0-9\.\-A-Za-z]+).zip$/', $version['name'], $matches)) { $carry[$matches['version']] = $version['links']['self']['href']; } return $carry; }, []); } } io, $this->context, $this->registry); if ($this->input->getOption('undo')) { $task->undo(); } else { $task->run(); } $this->context->save(); } } 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; } $this->task('download', [ 'provider' => $provider, 'version' => $typeInfo['version'], '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']}'"); } } ['/', '-', '\\', '|'], '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() ? "Complete!" : "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; } } 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; } } (git@|https:\/\/)(?P[\w\.@]+)(\/|:))(?P[\w,\-,\_]+)\/(?P[\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 $version, StreamInterface $stream); abstract public function publish(string $version, StreamInterface $stream); } 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('user') && $this->credentials->has('pass')) { $requestOpts['auth'] = [$this->credentials->get('user'), $this->credentials->get('pass')]; } $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('user') && $this->credentials->has('pass')) { $requestOpts['auth'] = [$this->credentials->get('user'), $this->credentials->get('pass')]; } $client = new Client(); $client->post($url, $requestOpts); } public static function login(SymfonyStyle $io) { $user = $io->ask('Username', '', function ($user) { if (!$user) { throw new \RuntimeException('You must supply a username'); } return $user; }); $pass = $io->askHidden('Password', function ($pass) { if (!$pass) { throw new \RuntimeException('You must supply a password'); } return $pass; }); $creds = SystemConfig::load(self::CREDENTIALS_FILE); $creds->set('user', $user)->set('pass', $pass)->save(); } } owner = $owner; $this->repo = $repo; $this->credentials = SystemConfig::load(self::CREDENTIALS_FILE); } // TODO: Implement more of 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; } } 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 $this->subTask('download', [ 'provider' => $provider, 'version' => $addonInfo['version'], '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]); } } public function undo() { } } 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() { } } 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'); } } 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); } } validateOptions(['dir', 'url']); $repo = new GitRepository($this->options['dir']); $repo->cloneRepository()->execute($this->options['url']); } public function undo() { } } 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); } } * @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); } } 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 = '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; } } } 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: {$this->deps['api']}\n" . " Installed: {$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: {$version}\n" . " Installed: {$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; } } 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("An error occurred: {$message}"); $file = $error->getFile() ?: 'N/A'; $output->writeln("File: {$file}"); $line = $error->getLine() ?: 'N/A'; $output->writeln("Line Number: {$line}"); $output->writeln('Additional Information:'); if ($command != null) { $output->writeln('Command: ' . $command->getName() . ''); } else { $output->writeln('Command: NULL'); } $output->writeln('Arguments:'); foreach ($input->getArguments() as $key => $value) { if ($key == 'command') { continue; } $output->writeln(" {$key}: {$value}"); } $output->writeln('Options:'); foreach ($input->getOptions() as $key => $value) { $value = $value ?: false; $output->writeln(" {$key}: {$value}"); } $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); } } 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)); } } currentSemverVersion = $currentVersion; } public function getCurrentLocalSemver() { return $this->currentSemverVersion; } public function getCurrentRemoteSemver(Updater $updater) { /** Switch remote request errors to HttpRequestExceptions */ set_error_handler(array($updater, 'throwHttpRequestException')); $version = humbug_get_contents($this->semverUrl); restore_error_handler(); if ($version === false) { throw new HttpRequestException(sprintf( 'Request to URL failed: %s', $this->getVersionUrl() )); } else if (empty($version)) { throw new HttpRequestException( 'Version request returned empty response.' ); } return rtrim($version); } public function setSemverUrl($semverUrl) { $this->semverUrl = $semverUrl; } } 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 compatibile 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); } } 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; } } strategy->getCurrentRemoteSemver($this); $oldSemver = $this->strategy->getCurrentLocalSemver($this); return (!empty($this->newVersion) && Comparator::greaterThan($newSemver, $oldSemver)); } public static function init($currentVersion) { if (!self::$updater) { $updater = new self(null, false); $strategy = new FWStrategy($currentVersion); $strategy->setPharUrl(self::$pharUrl); $strategy->setVersionUrl(self::$shaUrl); $strategy->setSemverUrl(self::$versionUrl); $updater->setStrategyObject($strategy); self::$updater = $updater; } return self::$updater; } } 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); } } 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'); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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; } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathspec) { $this->arguments[] = $pathspec; } } return $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 */ 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); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $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(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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(); } } * * 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 * @author Christian Schiffler * @copyright 2014 Tristan Lins * @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 { } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 */ 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; } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathspec) { $this->arguments[] = $pathspec; } } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $refspecs */ $refspecs = \func_get_args(); \array_shift($refspecs); foreach ($refspecs as $refspec) { $this->arguments[] = $refspec; } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathspec) { $this->arguments[] = $pathspec; } } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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 $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; } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $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(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @author Idris Dose * @copyright 2014-2022 Tristan Lins * @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 $refspecs */ $refspecs = \func_get_args(); \array_shift($refspecs); foreach ($refspecs as $refspec) { $this->arguments[] = $refspec; } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $refspecs */ $refspecs = \func_get_args(); \array_shift($refspecs); foreach ($refspecs as $refspec) { $this->arguments[] = $refspec; } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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; } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathSpec) { $this->arguments[] = $pathSpec; } } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Radek Crlik * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 $args */ $args = \func_get_args(); foreach ($args as $arg) { $this->arguments[] = $arg; } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathspec) { $this->arguments[] = $pathspec; } } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathSpec) { $this->arguments[] = $pathSpec; } } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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(); } } * * 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 * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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 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(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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: * * array( * '<pathspec>' => array( * 'index' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"], * 'worktree' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"], * ) * ) * * * @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: * * array( * '<pathspec>' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"], * ) * * * @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: * * array( * '<pathspec>' => [false | "M" | "A" | "D" | "R" | "C" | "U" | "?" | "!"], * ) * * * @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 $args */ $args = \func_get_args(); if (\count($args)) { $this->arguments[] = '--'; foreach ($args as $pathspec) { $this->arguments[] = $pathspec; } } return (string) $this->run(); } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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; } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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; } } * * 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 * @author Christian Schiffler * @author Sven Baumann * @copyright 2014-2018 Tristan Lins * @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() ); } } * * 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 * @author Christian Schiffler * @author David Molineus * @author Aaron Rubin * @author Matthew Gamble * @author Ahmad Marzouq * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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); } } * * 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 * @author Christian Schiffler * @author Matthew Gamble * @author Sven Baumann * @copyright 2014-2022 Tristan Lins * @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'); } } $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/lib/Doctrine/Deprecations/Deprecation.php', 'Doctrine\\Deprecations\\PHPUnit\\VerifyDeprecations' => $vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations/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\\FWStrategy' => $baseDir . '/src/Utils/FWStrategy.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', 'Humbug\\FileGetContents' => $vendorDir . '/padraic/humbug_get_contents/src/Humbug/FileGetContents.php', 'Humbug\\SelfUpdate\\Exception\\ExceptionInterface' => $vendorDir . '/padraic/phar-updater/src/Exception/ExceptionInterface.php', 'Humbug\\SelfUpdate\\Exception\\FilesystemException' => $vendorDir . '/padraic/phar-updater/src/Exception/FilesystemException.php', 'Humbug\\SelfUpdate\\Exception\\HttpRequestException' => $vendorDir . '/padraic/phar-updater/src/Exception/HttpRequestException.php', 'Humbug\\SelfUpdate\\Exception\\InvalidArgumentException' => $vendorDir . '/padraic/phar-updater/src/Exception/InvalidArgumentException.php', 'Humbug\\SelfUpdate\\Exception\\JsonParsingException' => $vendorDir . '/padraic/phar-updater/src/Exception/JsonParsingException.php', 'Humbug\\SelfUpdate\\Exception\\NoSignatureException' => $vendorDir . '/padraic/phar-updater/src/Exception/NoSignatureException.php', 'Humbug\\SelfUpdate\\Exception\\RuntimeException' => $vendorDir . '/padraic/phar-updater/src/Exception/RuntimeException.php', 'Humbug\\SelfUpdate\\Strategy\\GithubStrategy' => $vendorDir . '/padraic/phar-updater/src/Strategy/GithubStrategy.php', 'Humbug\\SelfUpdate\\Strategy\\ShaStrategy' => $vendorDir . '/padraic/phar-updater/src/Strategy/ShaStrategy.php', 'Humbug\\SelfUpdate\\Strategy\\StrategyInterface' => $vendorDir . '/padraic/phar-updater/src/Strategy/StrategyInterface.php', 'Humbug\\SelfUpdate\\Updater' => $vendorDir . '/padraic/phar-updater/src/Updater.php', 'Humbug\\SelfUpdate\\VersionParser' => $vendorDir . '/padraic/phar-updater/src/VersionParser.php', 'JakubOnderka\\PhpConsoleColor\\ConsoleColor' => $vendorDir . '/jakub-onderka/php-console-color/src/ConsoleColor.php', 'JakubOnderka\\PhpConsoleColor\\InvalidStyleException' => $vendorDir . '/jakub-onderka/php-console-color/src/InvalidStyleException.php', 'JakubOnderka\\PhpConsoleHighlighter\\Highlighter' => $vendorDir . '/jakub-onderka/php-console-highlighter/src/JakubOnderka/PhpConsoleHighlighter/Highlighter.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\\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\\ConstExpr\\QuoteAwareConstExprStringNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.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\\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\\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\\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\\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\\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', '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 . '/voku/stringy/src/CollectionStringy.php', 'Stringy\\StaticStringy' => $vendorDir . '/voku/stringy/src/StaticStringy.php', 'Stringy\\Stringy' => $vendorDir . '/voku/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\\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\\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\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.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', 'Symfony\\Polyfill\\Php72\\Php72' => $vendorDir . '/symfony/polyfill-php72/Php72.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\\Factory\\StaticMethod' => $vendorDir . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.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\\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\\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\\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\\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\\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\\PositiveInteger' => $vendorDir . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.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', ); $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php', 'b46ad4fe52f4d1899a2951c7e6ea56b0' => $vendorDir . '/voku/portable-utf8/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', 'd9d39f82a605ebe5918f683dd402334c' => $vendorDir . '/padraic/humbug_get_contents/src/function.php', 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', '65380ab4d81167209b0a4fac46641984' => $vendorDir . '/voku/arrayy/src/Create.php', 'e59173834a401a678a2c28192c24218d' => $vendorDir . '/bennerinformatics/php-path/path.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', 'b45b351e6b6f7487d819961fef2fda77' => $vendorDir . '/jakeasmith/http_build_url/src/http_build_url.php', 'c88a6f0dbb89a32bf4e283d3a7d626ab' => $vendorDir . '/voku/stringy/src/Create.php', '940abd8fb01ee76a36b44f35dcf9783b' => $vendorDir . '/weew/helpers-array/src/array.php', ); array($vendorDir . '/jakub-onderka/php-console-highlighter/src'), ); array($vendorDir . '/voku/anti-xss/src/voku/helper', $vendorDir . '/voku/email-check/src/voku/helper', $vendorDir . '/voku/urlify/src/voku/helper'), 'voku\\' => array($vendorDir . '/voku/portable-ascii/src/voku', $vendorDir . '/voku/portable-utf8/src/voku', $vendorDir . '/voku/stop-words/src/voku'), 'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/reflection-docblock/src', $vendorDir . '/phpdocumentor/type-resolver/src'), 'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), '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 . '/voku/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'), 'PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'), 'JakubOnderka\\PhpConsoleColor\\' => array($vendorDir . '/jakub-onderka/php-console-color/src'), 'Humbug\\SelfUpdate\\' => array($vendorDir . '/padraic/phar-updater/src'), 'Humbug\\' => array($vendorDir . '/padraic/humbug_get_contents/src/Humbug'), '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/lib/Doctrine/Deprecations'), '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'), ); setClassMapAuthoritative(true); $loader->register(true); $filesToLoad = \Composer\Autoload\ComposerStaticInited339c982da4f06016c503b85aa8cb2d::$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; } } __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php', 'b46ad4fe52f4d1899a2951c7e6ea56b0' => __DIR__ . '/..' . '/voku/portable-utf8/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', 'd9d39f82a605ebe5918f683dd402334c' => __DIR__ . '/..' . '/padraic/humbug_get_contents/src/function.php', 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', '65380ab4d81167209b0a4fac46641984' => __DIR__ . '/..' . '/voku/arrayy/src/Create.php', 'e59173834a401a678a2c28192c24218d' => __DIR__ . '/..' . '/bennerinformatics/php-path/path.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', 'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php', 'c88a6f0dbb89a32bf4e283d3a7d626ab' => __DIR__ . '/..' . '/voku/stringy/src/Create.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\\Php72\\' => 23, '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, 'PHPStan\\PhpDocParser\\' => 21, ), 'J' => array ( 'JakubOnderka\\PhpConsoleColor\\' => 29, ), 'H' => array ( 'Humbug\\SelfUpdate\\' => 18, 'Humbug\\' => 7, ), '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/anti-xss/src/voku/helper', 1 => __DIR__ . '/..' . '/voku/email-check/src/voku/helper', 2 => __DIR__ . '/..' . '/voku/urlify/src/voku/helper', ), 'voku\\' => array ( 0 => __DIR__ . '/..' . '/voku/portable-ascii/src/voku', 1 => __DIR__ . '/..' . '/voku/portable-utf8/src/voku', 2 => __DIR__ . '/..' . '/voku/stop-words/src/voku', ), 'phpDocumentor\\Reflection\\' => array ( 0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src', 1 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src', 2 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', ), 'Webmozart\\Assert\\' => array ( 0 => __DIR__ . '/..' . '/webmozart/assert/src', ), 'Symfony\\Polyfill\\Php72\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', ), '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__ . '/..' . '/voku/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', ), 'PHPStan\\PhpDocParser\\' => array ( 0 => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src', ), 'JakubOnderka\\PhpConsoleColor\\' => array ( 0 => __DIR__ . '/..' . '/jakub-onderka/php-console-color/src', ), 'Humbug\\SelfUpdate\\' => array ( 0 => __DIR__ . '/..' . '/padraic/phar-updater/src', ), 'Humbug\\' => array ( 0 => __DIR__ . '/..' . '/padraic/humbug_get_contents/src/Humbug', ), '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/lib/Doctrine/Deprecations', ), '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 $prefixesPsr0 = array ( 'J' => array ( 'JakubOnderka\\PhpConsoleHighlighter' => array ( 0 => __DIR__ . '/..' . '/jakub-onderka/php-console-highlighter/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/lib/Doctrine/Deprecations/Deprecation.php', 'Doctrine\\Deprecations\\PHPUnit\\VerifyDeprecations' => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations/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\\FWStrategy' => __DIR__ . '/../..' . '/src/Utils/FWStrategy.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', 'Humbug\\FileGetContents' => __DIR__ . '/..' . '/padraic/humbug_get_contents/src/Humbug/FileGetContents.php', 'Humbug\\SelfUpdate\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/ExceptionInterface.php', 'Humbug\\SelfUpdate\\Exception\\FilesystemException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/FilesystemException.php', 'Humbug\\SelfUpdate\\Exception\\HttpRequestException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/HttpRequestException.php', 'Humbug\\SelfUpdate\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/InvalidArgumentException.php', 'Humbug\\SelfUpdate\\Exception\\JsonParsingException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/JsonParsingException.php', 'Humbug\\SelfUpdate\\Exception\\NoSignatureException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/NoSignatureException.php', 'Humbug\\SelfUpdate\\Exception\\RuntimeException' => __DIR__ . '/..' . '/padraic/phar-updater/src/Exception/RuntimeException.php', 'Humbug\\SelfUpdate\\Strategy\\GithubStrategy' => __DIR__ . '/..' . '/padraic/phar-updater/src/Strategy/GithubStrategy.php', 'Humbug\\SelfUpdate\\Strategy\\ShaStrategy' => __DIR__ . '/..' . '/padraic/phar-updater/src/Strategy/ShaStrategy.php', 'Humbug\\SelfUpdate\\Strategy\\StrategyInterface' => __DIR__ . '/..' . '/padraic/phar-updater/src/Strategy/StrategyInterface.php', 'Humbug\\SelfUpdate\\Updater' => __DIR__ . '/..' . '/padraic/phar-updater/src/Updater.php', 'Humbug\\SelfUpdate\\VersionParser' => __DIR__ . '/..' . '/padraic/phar-updater/src/VersionParser.php', 'JakubOnderka\\PhpConsoleColor\\ConsoleColor' => __DIR__ . '/..' . '/jakub-onderka/php-console-color/src/ConsoleColor.php', 'JakubOnderka\\PhpConsoleColor\\InvalidStyleException' => __DIR__ . '/..' . '/jakub-onderka/php-console-color/src/InvalidStyleException.php', 'JakubOnderka\\PhpConsoleHighlighter\\Highlighter' => __DIR__ . '/..' . '/jakub-onderka/php-console-highlighter/src/JakubOnderka/PhpConsoleHighlighter/Highlighter.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\\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\\ConstExpr\\QuoteAwareConstExprStringNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.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\\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\\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\\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\\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\\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', '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__ . '/..' . '/voku/stringy/src/CollectionStringy.php', 'Stringy\\StaticStringy' => __DIR__ . '/..' . '/voku/stringy/src/StaticStringy.php', 'Stringy\\Stringy' => __DIR__ . '/..' . '/voku/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\\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\\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\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.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', 'Symfony\\Polyfill\\Php72\\Php72' => __DIR__ . '/..' . '/symfony/polyfill-php72/Php72.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\\Factory\\StaticMethod' => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.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\\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\\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\\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\\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\\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\\PositiveInteger' => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.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 = ComposerStaticInited339c982da4f06016c503b85aa8cb2d::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInited339c982da4f06016c503b85aa8cb2d::$prefixDirsPsr4; $loader->prefixesPsr0 = ComposerStaticInited339c982da4f06016c503b85aa8cb2d::$prefixesPsr0; $loader->classMap = ComposerStaticInited339c982da4f06016c503b85aa8cb2d::$classMap; }, null, ClassLoader::class); } } * Jordi Boggiano * * 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 * @author Jordi Boggiano * @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 */ private $vendorDir; // PSR-4 /** * @var array[] * @psalm-var array> */ private $prefixLengthsPsr4 = array(); /** * @var array[] * @psalm-var array> */ private $prefixDirsPsr4 = array(); /** * @var array[] * @psalm-var array */ private $fallbackDirsPsr4 = array(); // PSR-0 /** * @var array[] * @psalm-var array> */ private $prefixesPsr0 = array(); /** * @var array[] * @psalm-var array */ private $fallbackDirsPsr0 = array(); /** @var bool */ private $useIncludePath = false; /** * @var string[] * @psalm-var array */ private $classMap = array(); /** @var bool */ private $classMapAuthoritative = false; /** * @var bool[] * @psalm-var array */ private $missingClasses = array(); /** @var ?string */ private $apcuPrefix; /** * @var self[] */ private static $registeredLoaders = array(); /** * @param ?string $vendorDir */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; self::initializeIncludeClosure(); } /** * @return string[] */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); } /** * @return array[] * @psalm-return array> */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } /** * @return array[] * @psalm-return array */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } /** * @return array[] * @psalm-return array */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } /** * @return string[] Array of classname => path * @psalm-return array */ public function getClassMap() { return $this->classMap; } /** * @param string[] $classMap Class to filename map * @psalm-param array $classMap * * @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 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) { if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( (array) $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, (array) $paths ); } return; } $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { $this->prefixesPsr0[$first][$prefix] = (array) $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( (array) $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], (array) $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 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) { if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( (array) $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, (array) $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] = (array) $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( (array) $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], (array) $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 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 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 indexed by their corresponding vendor directories. * * @return 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": "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.2", "version_normalized": "1.1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", "phpstan/phpstan": "1.4.10 || 1.10.15", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "psalm/plugin-phpunit": "0.18.4", "psr/log": "^1 || ^2 || ^3", "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, "time": "2023-09-27T20:04:15+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" } }, "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.2" }, "install-path": "../doctrine/deprecations" }, { "name": "guzzlehttp/guzzle", "version": "7.8.1", "version_normalized": "7.8.1.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.5.3 || ^2.0.1", "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", "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": "*", "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.36 || ^9.6.15", "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": "2023-12-03T20:35:24+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.8.1" }, "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.0.2", "version_normalized": "2.0.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "time": "2023-12-03T20:19:20+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.0.2" }, "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.6.2", "version_normalized": "2.6.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "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", "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, "time": "2023-12-03T20:05:35+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.6.2" }, "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": "jakub-onderka/php-console-color", "version": "v0.2", "version_normalized": "0.2.0.0", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", "shasum": "" }, "require": { "php": ">=5.4.0" }, "require-dev": { "jakub-onderka/php-code-style": "1.0", "jakub-onderka/php-parallel-lint": "1.0", "jakub-onderka/php-var-dump-check": "0.*", "phpunit/phpunit": "~4.3", "squizlabs/php_codesniffer": "1.*" }, "time": "2018-09-29T17:23:10+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { "JakubOnderka\\PhpConsoleColor\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-2-Clause" ], "authors": [ { "name": "Jakub Onderka", "email": "jakub.onderka@gmail.com" } ], "support": { "issues": "https://github.com/JakubOnderka/PHP-Console-Color/issues", "source": "https://github.com/JakubOnderka/PHP-Console-Color/tree/master" }, "abandoned": "php-parallel-lint/php-console-color", "install-path": "../jakub-onderka/php-console-color" }, { "name": "jakub-onderka/php-console-highlighter", "version": "v0.3.2", "version_normalized": "0.3.2.0", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", "shasum": "" }, "require": { "jakub-onderka/php-console-color": "~0.1", "php": ">=5.3.0" }, "require-dev": { "jakub-onderka/php-code-style": "~1.0", "jakub-onderka/php-parallel-lint": "~0.5", "jakub-onderka/php-var-dump-check": "~0.1", "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~1.5" }, "time": "2015-04-20T18:58:01+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-0": { "JakubOnderka\\PhpConsoleHighlighter": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Jakub Onderka", "email": "acci@acci.cz", "homepage": "http://www.acci.cz/" } ], "support": { "issues": "https://github.com/JakubOnderka/PHP-Console-Highlighter/issues", "source": "https://github.com/JakubOnderka/PHP-Console-Highlighter/tree/master" }, "abandoned": "php-parallel-lint/php-console-highlighter", "install-path": "../jakub-onderka/php-console-highlighter" }, { "name": "padraic/humbug_get_contents", "version": "1.0.4", "version_normalized": "1.0.4.0", "source": { "type": "git", "url": "https://github.com/humbug/file_get_contents.git", "reference": "66797199019d0cb4529cb8d29c6f0b4c5085b53a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/humbug/file_get_contents/zipball/66797199019d0cb4529cb8d29c6f0b4c5085b53a", "reference": "66797199019d0cb4529cb8d29c6f0b4c5085b53a", "shasum": "" }, "require": { "php": ">=5.3" }, "require-dev": { "phpunit/phpunit": "~4.0" }, "time": "2015-04-22T18:45:00+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.0-dev" } }, "installation-source": "dist", "autoload": { "files": [ "src/function.php" ], "psr-4": { "Humbug\\": "src/Humbug/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", "homepage": "http://blog.astrumfutura.com" } ], "description": "Secure wrapper for accessing HTTPS resources with file_get_contents for PHP 5.3+", "homepage": "https://github.com/padraic/file_get_contents", "keywords": [ "download", "file_get_contents", "http", "https", "ssl", "tls" ], "support": { "issues": "https://github.com/padraic/file_get_contents/issues", "source": "https://github.com/humbug/file_get_contents/tree/1.0.4" }, "install-path": "../padraic/humbug_get_contents" }, { "name": "padraic/phar-updater", "version": "v1.0.6", "version_normalized": "1.0.6.0", "source": { "type": "git", "url": "https://github.com/humbug/phar-updater.git", "reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/humbug/phar-updater/zipball/d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1", "reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1", "shasum": "" }, "require": { "padraic/humbug_get_contents": "^1.0", "php": ">=5.3.3" }, "require-dev": { "phpunit/phpunit": "~4.0" }, "time": "2018-03-30T12:52:15+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "1.0-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "Humbug\\SelfUpdate\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", "homepage": "http://blog.astrumfutura.com" } ], "description": "A thing to make PHAR self-updating easy and secure.", "keywords": [ "humbug", "phar", "self-update", "update" ], "support": { "issues": "https://github.com/humbug/phar-updater/issues", "source": "https://github.com/humbug/phar-updater/tree/1.0" }, "abandoned": true, "install-path": "../padraic/phar-updater" }, { "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": "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.3.0", "version_normalized": "5.3.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { "ext-filter": "*", "php": "^7.2 || ^8.0", "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.3", "webmozart/assert": "^1.9.1" }, "require-dev": { "mockery/mockery": "~1.3.2", "psalm/phar": "^4.8" }, "time": "2021-10-19T17:43:47+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": "account@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.3.0" }, "install-path": "../phpdocumentor/reflection-docblock" }, { "name": "phpdocumentor/type-resolver", "version": "1.8.0", "version_normalized": "1.8.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc", "reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, "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-01-11T11:49:22+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.8.0" }, "install-path": "../phpdocumentor/type-resolver" }, { "name": "phpstan/phpdoc-parser", "version": "1.25.0", "version_normalized": "1.25.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240", "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.5", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, "time": "2024-01-04T17:06:16+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/1.25.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.0.2", "version_normalized": "1.0.2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { "php": ">=7.0.0", "psr/http-message": "^1.0 || ^2.0" }, "time": "2023-04-10T20:10:41+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": "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/tree/1.0.2" }, "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.0", "version_normalized": "3.0.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", "shasum": "" }, "require": { "php": ">=8.0.0" }, "time": "2021-07-14T16:46:02+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.0" }, "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.2", "version_normalized": "6.4.2.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/console/zipball/0254811a143e6bc6c8deea08b589a7e68a37f625", "reference": "0254811a143e6bc6c8deea08b589a7e68a37f625", "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": "2023-12-10T16:15:48+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.2" }, "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/console" }, { "name": "symfony/deprecation-contracts", "version": "v3.4.0", "version_normalized": "3.4.0.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { "php": ">=8.1" }, "time": "2023-05-23T14:45:45+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } }, "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.4.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.2", "version_normalized": "6.4.2.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", "reference": "e95216850555cd55e71b857eb9d6c2674124603a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e95216850555cd55e71b857eb9d6c2674124603a", "reference": "e95216850555cd55e71b857eb9d6c2674124603a", "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": "2023-12-27T22:16:42+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.2" }, "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" }, { "name": "symfony/event-dispatcher-contracts", "version": "v3.4.0", "version_normalized": "3.4.0.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, "time": "2023-05-23T14:45:45+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } }, "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.4.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.0", "version_normalized": "6.4.0.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/filesystem/zipball/952a8cb588c3bc6ce76f6023000fb932f16a6e59", "reference": "952a8cb588c3bc6ce76f6023000fb932f16a6e59", "shasum": "" }, "require": { "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "time": "2023-07-26T17:27:13+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.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/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.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { "ext-ctype": "*" }, "suggest": { "ext-ctype": "For best performance" }, "time": "2023-01-26T09:26:14+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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/polyfill-ctype" }, { "name": "symfony/polyfill-iconv", "version": "v1.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/6de50471469b8c9afc38164452ab2b6170ee71c1", "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { "ext-iconv": "*" }, "suggest": { "ext-iconv": "For best performance" }, "time": "2023-01-26T09:26:14+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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/polyfill-iconv" }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" }, "time": "2023-01-26T09:26:14+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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/polyfill-intl-grapheme" }, { "name": "symfony/polyfill-intl-idn", "version": "v1.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", "shasum": "" }, "require": { "php": ">=7.1", "symfony/polyfill-intl-normalizer": "^1.10", "symfony/polyfill-php72": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, "time": "2023-01-26T09:30:37+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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/polyfill-intl-idn" }, { "name": "symfony/polyfill-intl-normalizer", "version": "v1.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" }, "time": "2023-01-26T09:26:14+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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/polyfill-intl-normalizer" }, { "name": "symfony/polyfill-mbstring", "version": "v1.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { "ext-mbstring": "*" }, "suggest": { "ext-mbstring": "For best performance" }, "time": "2023-07-28T09:04:16+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/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.28.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/polyfill-mbstring" }, { "name": "symfony/polyfill-php72", "version": "v1.28.0", "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", "shasum": "" }, "require": { "php": ">=7.1" }, "time": "2023-01-26T09:26:14+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, "installation-source": "dist", "autoload": { "files": [ "bootstrap.php" ], "psr-4": { "Symfony\\Polyfill\\Php72\\": "" } }, "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.28.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/polyfill-php72" }, { "name": "symfony/process", "version": "v6.4.2", "version_normalized": "6.4.2.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", "reference": "c4b1ef0bc80533d87a2e969806172f1c2a980241" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/process/zipball/c4b1ef0bc80533d87a2e969806172f1c2a980241", "reference": "c4b1ef0bc80533d87a2e969806172f1c2a980241", "shasum": "" }, "require": { "php": ">=8.1" }, "time": "2023-12-22T16:42:54+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.2" }, "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/process" }, { "name": "symfony/service-contracts", "version": "v3.4.1", "version_normalized": "3.4.1.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", "shasum": "" }, "require": { "php": ">=8.1", "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" }, "time": "2023-12-26T14:02:43+00:00", "type": "library", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } }, "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.4.1" }, "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.0.2", "version_normalized": "7.0.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/string/zipball/cc78f14f91f5e53b42044d0620961c48028ff9f5", "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5", "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/error-handler": "^6.4|^7.0", "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": "2023-12-10T16:54:46+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.0.2" }, "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/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.1", "version_normalized": "2.0.1.0", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", "reference": "b56450eed252f6801410d810c8e1727224ae0743" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743", "reference": "b56450eed252f6801410d810c8e1727224ae0743", "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": "2022-03-08T17:03:00+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": "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.1" }, "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/stringy", "version": "6.5.3", "version_normalized": "6.5.3.0", "source": { "type": "git", "url": "https://github.com/voku/Stringy.git", "reference": "c453c88fbff298f042c836ef44306f8703b2d537" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/voku/Stringy/zipball/c453c88fbff298f042c836ef44306f8703b2d537", "reference": "c453c88fbff298f042c836ef44306f8703b2d537", "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" }, "require-dev": { "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" }, "time": "2022-03-28T14:52:20+00:00", "type": "library", "installation-source": "dist", "autoload": { "files": [ "src/Create.php" ], "psr-4": { "Stringy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "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": [ "UTF", "helpers", "manipulation", "methods", "multibyte", "string", "utf-8", "utility", "utils" ], "support": { "issues": "https://github.com/voku/Stringy/issues", "source": "https://github.com/voku/Stringy" }, "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/stringy", "type": "tidelift" } ], "install-path": "../voku/stringy" }, { "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": [] } array( 'name' => 'linformatics/fw-installer', 'pretty_version' => '1.0.9', 'version' => '1.0.9.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, ), '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.2', 'version' => '1.1.2.0', 'reference' => '4f2d4f2836e7ec4e7a8625e75c6aa916004db931', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/guzzle' => array( 'pretty_version' => '7.8.1', 'version' => '7.8.1.0', 'reference' => '41042bc7ab002487b876a0683fc8dce04ddce104', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/promises' => array( 'pretty_version' => '2.0.2', 'version' => '2.0.2.0', 'reference' => 'bbff78d96034045e58e13dedd6ad91b5d1253223', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/promises', 'aliases' => array(), 'dev_requirement' => false, ), 'guzzlehttp/psr7' => array( 'pretty_version' => '2.6.2', 'version' => '2.6.2.0', 'reference' => '45b30f99ac27b5ca93cb4831afe16285f57b8221', '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( 'pretty_version' => 'v0.2', 'version' => '0.2.0.0', 'reference' => 'd5deaecff52a0d61ccb613bb3804088da0307191', 'type' => 'library', 'install_path' => __DIR__ . '/../jakub-onderka/php-console-color', 'aliases' => array(), 'dev_requirement' => false, ), 'jakub-onderka/php-console-highlighter' => array( 'pretty_version' => 'v0.3.2', 'version' => '0.3.2.0', 'reference' => '7daa75df45242c8d5b75a22c00a201e7954e4fb5', 'type' => 'library', 'install_path' => __DIR__ . '/../jakub-onderka/php-console-highlighter', 'aliases' => array(), 'dev_requirement' => false, ), 'linformatics/fw-installer' => array( 'pretty_version' => '1.0.9', 'version' => '1.0.9.0', 'reference' => NULL, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), 'padraic/humbug_get_contents' => array( 'pretty_version' => '1.0.4', 'version' => '1.0.4.0', 'reference' => '66797199019d0cb4529cb8d29c6f0b4c5085b53a', 'type' => 'library', 'install_path' => __DIR__ . '/../padraic/humbug_get_contents', 'aliases' => array(), 'dev_requirement' => false, ), 'padraic/phar-updater' => array( 'pretty_version' => 'v1.0.6', 'version' => '1.0.6.0', 'reference' => 'd01d3b8f26e541ac9b9eeba1e18d005d852f7ff1', 'type' => 'library', 'install_path' => __DIR__ . '/../padraic/phar-updater', '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, ), '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.3.0', 'version' => '5.3.0.0', 'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock', 'aliases' => array(), 'dev_requirement' => false, ), 'phpdocumentor/type-resolver' => array( 'pretty_version' => '1.8.0', 'version' => '1.8.0.0', 'reference' => 'fad452781b3d774e3337b0c0b245dd8e5a4455fc', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'aliases' => array(), 'dev_requirement' => false, ), 'phpstan/phpdoc-parser' => array( 'pretty_version' => '1.25.0', 'version' => '1.25.0.0', 'reference' => 'bd84b629c8de41aa2ae82c067c955e06f1b00240', '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.0.2', 'version' => '1.0.2.0', 'reference' => 'e616d01114759c4c489f93b099585439f795fe35', '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.0', 'version' => '3.0.0.0', 'reference' => 'fe5ea303b0887d5caefd3d431c3e61ad47037001', '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.2', 'version' => '6.4.2.0', 'reference' => '0254811a143e6bc6c8deea08b589a7e68a37f625', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/deprecation-contracts' => array( 'pretty_version' => 'v3.4.0', 'version' => '3.4.0.0', 'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/event-dispatcher' => array( 'pretty_version' => 'v6.4.2', 'version' => '6.4.2.0', 'reference' => 'e95216850555cd55e71b857eb9d6c2674124603a', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/event-dispatcher-contracts' => array( 'pretty_version' => 'v3.4.0', 'version' => '3.4.0.0', 'reference' => 'a76aed96a42d2b521153fb382d418e30d18b59df', '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.0', 'version' => '6.4.0.0', 'reference' => '952a8cb588c3bc6ce76f6023000fb932f16a6e59', '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.28.0', 'version' => '1.28.0.0', 'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-iconv' => array( 'pretty_version' => 'v1.28.0', 'version' => '1.28.0.0', 'reference' => '6de50471469b8c9afc38164452ab2b6170ee71c1', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-iconv', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-grapheme' => array( 'pretty_version' => 'v1.28.0', 'version' => '1.28.0.0', 'reference' => '875e90aeea2777b6f135677f618529449334a612', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-idn' => array( 'pretty_version' => 'v1.28.0', 'version' => '1.28.0.0', 'reference' => 'ecaafce9f77234a6a449d29e49267ba10499116d', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( 'pretty_version' => 'v1.28.0', 'version' => '1.28.0.0', 'reference' => '8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( 'pretty_version' => 'v1.28.0', 'version' => '1.28.0.0', 'reference' => '42292d99c55abe617799667f454222c54c60e229', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-php72' => array( 'pretty_version' => 'v1.28.0', 'version' => '1.28.0.0', 'reference' => '70f4aebd92afca2f865444d30a4d2151c13c3179', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php72', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/process' => array( 'pretty_version' => 'v6.4.2', 'version' => '6.4.2.0', 'reference' => 'c4b1ef0bc80533d87a2e969806172f1c2a980241', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/service-contracts' => array( 'pretty_version' => 'v3.4.1', 'version' => '3.4.1.0', 'reference' => 'fe07cbc8d837f60caf7018068e350cc5163681a0', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/string' => array( 'pretty_version' => 'v7.0.2', 'version' => '7.0.2.0', 'reference' => 'cc78f14f91f5e53b42044d0620961c48028ff9f5', '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.1', 'version' => '2.0.1.0', 'reference' => 'b56450eed252f6801410d810c8e1727224ae0743', '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( 'pretty_version' => '6.5.3', 'version' => '6.5.3.0', 'reference' => 'c453c88fbff298f042c836ef44306f8703b2d537', 'type' => 'library', 'install_path' => __DIR__ . '/../voku/stringy', 'aliases' => array(), 'dev_requirement' => false, ), '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, ), ), ); * Jordi Boggiano * * 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 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}|array{}|null */ private static $installed; /** * @var bool|null */ private static $canGetVendors; /** * @var array[] * @psalm-var array}> */ 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 */ 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 */ 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 || empty($installed['versions'][$packageName]['dev_requirement']); } } 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($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} */ 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}> */ 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} $data */ public static function reload($data) { self::$installed = $data; self::$installedByVendor = array(); } /** * @return array[] * @psalm-return list}> */ private static function getInstalled() { if (null === self::$canGetVendors) { self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); } $installed = array(); if (self::$canGetVendors) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } } } } 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 = require __DIR__ . '/installed.php'; } else { self::$installed = array(); } } $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. = 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; } } trigger_error( 'Composer detected issues in your platform: ' . implode(' ', $issues), E_USER_ERROR ); } * * 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)); } } * * 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( $provider); } * * 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; } } * * 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(); } * * 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 '[]'; } } * * 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) . ']'; } } * * 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; } } * * 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 */ 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(\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('{(?< ,]) *(? 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' . $versionRegex . ') +- +(?P' . $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; } } } 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)); } } } 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); } } 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; } } > 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 ); } } 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(); } } } 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; } } 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; } } 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; } } 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); } } |null */ private static $type; /** @var LoggerInterface|null */ private static $logger; /** @var array */ private static $ignoredPackages = []; /** @var array */ private static $triggeredDeprecations = []; /** @var array */ 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 $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 ?? 0; self::$type |= self::TYPE_TRACK_DEPRECATIONS; } public static function enableWithTriggerError(): void { self::$type = self::$type ?? 0; self::$type |= self::TYPE_TRIGGER_ERROR; } public static function enableWithPsrLogger(LoggerInterface $logger): void { self::$type = self::$type ?? 0; 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 */ public static function getTriggeredDeprecations(): array { return self::$triggeredDeprecations; } /** * @return int-mask-of */ 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; } } */ private $doctrineDeprecationsExpectations = []; /** @var array */ 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 */ public function enableDeprecationTracking(): void { Deprecation::enableTrackingDeprecations(); } /** * @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 ) ); } } } truncateAt = $truncateAt; } /** * Returns a summarized message body. */ public function summarize(MessageInterface $message): ?string { return $this->truncateAt === null ? \GuzzleHttp\Psr7\Message::bodySummary($message) : \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt); } } '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 \GuzzleHttp\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.'); } } 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); } } 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 */ 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() ); } } } */ 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; } 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}"); } } } 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'); } } } 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; } } 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; } } 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; } } 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 = $request->getUri(); $uri = static::obfuscateUri($uri); // Client Error: `GET /` resulted in a `404 Not Found` response: // ... (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); } /** * Obfuscates URI if there is a username and a password present */ private static function obfuscateUri(UriInterface $uri): UriInterface { $userInfo = $uri->getUserInfo(); if (false !== ($pos = \strpos($userInfo, ':'))) { return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***'); } return $uri; } /** * 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; } } maxHandles = $maxHandles; } public function create(RequestInterface $request, array $options): EasyHandle { 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; } public function release(EasyHandle $easy): void { $resource = $easy->handle; unset($easy->handle); if (\count($this->handles) >= $this->maxHandles) { \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] = \curl_version()['version']; $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 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 ) ); } $message = \sprintf( 'cURL error %s: %s (%s)', $ctx['errno'], $ctx['error'], 'see https://curl.haxx.se/libcurl/c/libcurl-errors.html' ); $uriString = (string) $easy->request->getUri(); if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) { $message .= \sprintf(' for %s', $uriString); } // 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); } /** * @return array */ 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 ($version == 1.1) { $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; } elseif ($version == 2.0) { $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0; } 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 acceptable encodings we need // to overwrite this implicit header with an empty one. $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'])) { if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) { if (!defined('CURL_SSLVERSION_TLSv1_0')) { throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL'); } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0; } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) { if (!defined('CURL_SSLVERSION_TLSv1_1')) { throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL'); } $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1; } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) { if (!defined('CURL_SSLVERSION_TLSv1_2')) { 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 (!defined('CURL_SSLVERSION_TLSv1_3')) { 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) { \curl_close($handle); unset($this->handles[$id]); } } } 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); } } An array of delay times, indexed by handle id in `addRequest`. * * @see CurlMultiHandler::addRequest */ private $delays = []; /** * @var array 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 ); } } } // 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) { } $this->processMessages(); } /** * 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); \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; } } 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); } } |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); } } } withoutHeader('Expect'); // Append a content-length header if body size is zero to match // cURL's behavior. if (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, &$http_response_header, $contextResource, $context, $options, $request) { $resource = @\fopen((string) $uri, 'r', false, $contextResource); $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); } }; } } 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).')'; } } >>>>>>>\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); } } 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 $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. * * @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests. * * @param LoggerInterface $logger Logs messages. * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings. * @param string $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); }; }; } } $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 \GuzzleHttp\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; }; } } } 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 if you're not using HTTP/1.1 or HTTP/2.0 if ($expect === false || $request->getProtocolVersion() < 1.1) { 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'; } } } 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; } } 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); } } 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; } } 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'); } } 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); } } } 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]); } } $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); } ); } } 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; } } 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 } } 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; } } 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); } } } } 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 } } 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; } } 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; } } * while ($eventLoop->isRunning()) { * GuzzleHttp\Promise\Utils::queue()->run(); * } * * * @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 $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 { $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; }); } } 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 : []; } } 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 : []; } } 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(); } } 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)); } } */ private $methods; /** * @param array $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 $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); } } ]+>|[^=]+/', $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; } } 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); } } 15 + 32]); $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource)); } } 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)); } } 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 ''; } } 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 ); } } 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]); } if (count($value) === 0) { throw new \InvalidArgumentException('Header value can not be an empty array.'); } 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) ); } } } '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; } } 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; } } 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); } } } '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. */ public static function build(array $params, $encoding = PHP_QUERY_RFC3986): 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'); } $qs = ''; foreach ($params as $k => $v) { $k = $encoder((string) $k); if (!is_array($v)) { $qs .= $k; $v = is_bool($v) ? (int) $v : $v; if ($v !== null) { $qs .= '='.$encoder((string) $v); } $qs .= '&'; } else { foreach ($v as $vv) { $qs .= $k; $vv = is_bool($vv) ? (int) $vv : $vv; if ($vv !== null) { $qs .= '='.$encoder((string) $vv); } $qs .= '&'; } } } return $qs ? (string) substr($qs, 0, -1) : ''; } } 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.'); } } } '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.'); } } } @,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m"; public const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)"; } 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; } } 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; } } 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'); } } 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 * } */ public function stream_stat(): array { 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, ]; } } 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 (false === in_array($error, UploadedFile::ERRORS, true)) { 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('Cannot retrieve stream due to upload 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; } } 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-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'); } } } } 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 } } 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 } } 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 } } $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; } /** * 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 $ex \RuntimeException */ 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 $ex \RuntimeException */ 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'); } } =' ) ) { 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 "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'), ); } } 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"; } 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)); } else if ($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]); } /** * @return bool */ public function isSupported() { if (DIRECTORY_SEPARATOR === '\\') { 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 { return function_exists('posix_isatty') && @posix_isatty(STDOUT); } } /** * @return bool */ public function are256ColorsSupported() { if (DIRECTORY_SEPARATOR === '\\') { 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"; } } isSupportedForce = $isSupported; } public function isSupported() { return $this->isSupportedForce; } public function setAre256ColorsSupported($are256ColorsSupported) { $this->are256ColorsSupportedForce = $are256ColorsSupported; } public function are256ColorsSupported() { return $this->are256ColorsSupportedForce; } } class ConsoleColorTest extends \PHPUnit_Framework_TestCase { /** @var ConsoleColorWithForceSupport */ private $uut; protected function setUp() { $this->uut = new ConsoleColorWithForceSupport(); } public function testNone() { $output = $this->uut->apply('none', 'text'); $this->assertEquals("text", $output); } public function testBold() { $output = $this->uut->apply('bold', 'text'); $this->assertEquals("\033[1mtext\033[0m", $output); } public function testBoldColorsAreNotSupported() { $this->uut->setIsSupported(false); $output = $this->uut->apply('bold', 'text'); $this->assertEquals("text", $output); } public function testBoldColorsAreNotSupportedButAreForced() { $this->uut->setIsSupported(false); $this->uut->setForceStyle(true); $output = $this->uut->apply('bold', 'text'); $this->assertEquals("\033[1mtext\033[0m", $output); } public function testDark() { $output = $this->uut->apply('dark', 'text'); $this->assertEquals("\033[2mtext\033[0m", $output); } public function testBoldAndDark() { $output = $this->uut->apply(array('bold', 'dark'), 'text'); $this->assertEquals("\033[1;2mtext\033[0m", $output); } public function test256ColorForeground() { $output = $this->uut->apply('color_255', 'text'); $this->assertEquals("\033[38;5;255mtext\033[0m", $output); } public function test256ColorWithoutSupport() { $this->uut->setAre256ColorsSupported(false); $output = $this->uut->apply('color_255', 'text'); $this->assertEquals("text", $output); } public function test256ColorBackground() { $output = $this->uut->apply('bg_color_255', 'text'); $this->assertEquals("\033[48;5;255mtext\033[0m", $output); } public function test256ColorForegroundAndBackground() { $output = $this->uut->apply(array('color_200', 'bg_color_255'), 'text'); $this->assertEquals("\033[38;5;200;48;5;255mtext\033[0m", $output); } public function testSetOwnTheme() { $this->uut->setThemes(array('bold_dark' => array('bold', 'dark'))); $output = $this->uut->apply(array('bold_dark'), 'text'); $this->assertEquals("\033[1;2mtext\033[0m", $output); } public function testAddOwnTheme() { $this->uut->addTheme('bold_own', 'bold'); $output = $this->uut->apply(array('bold_own'), 'text'); $this->assertEquals("\033[1mtext\033[0m", $output); } public function testAddOwnThemeArray() { $this->uut->addTheme('bold_dark', array('bold', 'dark')); $output = $this->uut->apply(array('bold_dark'), 'text'); $this->assertEquals("\033[1;2mtext\033[0m", $output); } public function testOwnWithStyle() { $this->uut->addTheme('bold_dark', array('bold', 'dark')); $output = $this->uut->apply(array('bold_dark', 'italic'), 'text'); $this->assertEquals("\033[1;2;3mtext\033[0m", $output); } public function testHasAndRemoveTheme() { $this->assertFalse($this->uut->hasTheme('bold_dark')); $this->uut->addTheme('bold_dark', array('bold', 'dark')); $this->assertTrue($this->uut->hasTheme('bold_dark')); $this->uut->removeTheme('bold_dark'); $this->assertFalse($this->uut->hasTheme('bold_dark')); } public function testApplyInvalidArgument() { $this->setExpectedException('\InvalidArgumentException'); $this->uut->apply(new stdClass(), 'text'); } public function testApplyInvalidStyleName() { $this->setExpectedException('\JakubOnderka\PhpConsoleColor\InvalidStyleException'); $this->uut->apply('invalid', 'text'); } public function testApplyInvalid256Color() { $this->setExpectedException('\JakubOnderka\PhpConsoleColor\InvalidStyleException'); $this->uut->apply('color_2134', 'text'); } public function testThemeInvalidStyle() { $this->setExpectedException('\JakubOnderka\PhpConsoleColor\InvalidStyleException'); $this->uut->addTheme('invalid', array('invalid')); } public function testForceStyle() { $this->assertFalse($this->uut->isStyleForced()); $this->uut->setForceStyle(true); $this->assertTrue($this->uut->isStyleForced()); } public function testGetPossibleStyles() { $this->assertInternalType('array', $this->uut->getPossibleStyles()); $this->assertNotEmpty($this->uut->getPossibleStyles()); } } getCodeSnippet($fileContent, 3);getWholeFile($fileContent);getWholeFileWithLineNumbers($fileContent); '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', ); /** * @param ConsoleColor $color */ 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 \JakubOnderka\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); $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 \JakubOnderka\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 \JakubOnderka\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)) { switch ($token[0]) { case T_INLINE_HTML: $newType = self::TOKEN_HTML; break; case T_COMMENT: case T_DOC_COMMENT: $newType = self::TOKEN_COMMENT; break; case T_ENCAPSED_AND_WHITESPACE: case T_CONSTANT_ENCAPSED_STRING: $newType = self::TOKEN_STRING; break; case T_WHITESPACE: break; case T_OPEN_TAG: case T_OPEN_TAG_WITH_ECHO: case T_CLOSE_TAG: case T_STRING: case T_VARIABLE: // Constants case T_DIR: case T_FILE: case T_METHOD_C: case T_DNUMBER: case T_LNUMBER: case T_NS_C: case T_LINE: case T_CLASS_C: case T_FUNC_C: //case T_TRAIT_C: $newType = self::TOKEN_DEFAULT; break; default: // Compatibility with PHP 5.3 if (defined('T_TRAIT_C') && $token[0] === T_TRAIT_C) { $newType = self::TOKEN_DEFAULT; } else { $newType = self::TOKEN_KEYWORD; } } } 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 $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 \JakubOnderka\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 \JakubOnderka\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 $snippet; } }getMock('\JakubOnderka\PhpConsoleColor\ConsoleColor'); $mock->expects($this->any()) ->method('apply') ->will($this->returnCallback(function ($style, $text) { return "<$style>$text"; })); $mock->expects($this->any()) ->method('hasTheme') ->will($this->returnValue(true)); return $mock; } protected function setUp() { $this->uut = new Highlighter($this->getConsoleColorMock()); } protected function compare($original, $expected) { $output = $this->uut->getWholeFile($original); $this->assertEquals($expected, $output); } public function testVariable() { $this->compare( << echo \$a; EOL ); } public function testInteger() { $this->compare( << echo 43; EOL ); } public function testFloat() { $this->compare( << echo 43.3; EOL ); } public function testHex() { $this->compare( << echo 0x43; EOL ); } public function testBasicFunction() { $this->compare( << function plus(\$a, \$b) { return \$a + \$b; } EOL ); } public function testStringNormal() { $this->compare( << echo 'Ahoj světe'; EOL ); } public function testStringDouble() { $this->compare( << echo "Ahoj světe"; EOL ); } public function testInstanceof() { $this->compare( << \$a instanceof stdClass; EOL ); } /* * Constants */ public function testConstant() { $constants = array( '__FILE__', '__LINE__', '__CLASS__', '__FUNCTION__', '__METHOD__', '__TRAIT__', '__DIR__', '__NAMESPACE__' ); foreach ($constants as $constant) { $this->compare( << $constant; EOL ); } } /* * Comments */ public function testComment() { $this->compare( << /* Ahoj */ EOL ); } public function testDocComment() { $this->compare( << /** Ahoj */ EOL ); } public function testInlineComment() { $this->compare( << // Ahoj EOL ); } public function testHashComment() { $this->compare( << # Ahoj EOL ); } public function testEmpty() { $this->compare( '' , '' ); } }get($filename, $context); } elseif (FileGetContents::hasNextRequestHeaders()) { if ($context === null) { $context = stream_context_create(); } $context = FileGetContents::setHttpHeaders($context); } $return = file_get_contents($filename, $use_include_path, $context); if (isset($http_response_header)) { FileGetContents::setLastResponseHeaders($http_response_header); } return $return; } } if (!function_exists('humbug_get_headers')) { function humbug_get_headers() { return FileGetContents::getLastResponseHeaders(); } } if (!function_exists('humbug_set_headers')) { function humbug_set_headers(array $headers) { return FileGetContents::setNextRequestHeaders($headers); } } array()); protected static $lastResponseHeaders; protected static $nextRequestHeaders; public function __construct() { $this->checkConfig(); $options = $this->getTlsStreamContextDefaults(null); $this->options = array_replace_recursive($this->options, $options); } public function get($filename, $context = null) { $context = $this->getStreamContext($filename); self::setHttpHeaders($context); $result = file_get_contents($filename, null, $context); self::setLastResponseHeaders($http_response_header); return $result; } public static function setLastResponseHeaders($headers) { self::$lastResponseHeaders = $headers; } public static function getLastResponseHeaders() { return self::$lastResponseHeaders; } public static function setNextRequestHeaders(array $headers) { self::$nextRequestHeaders = $headers; } public static function hasNextRequestHeaders() { return !empty(self::$nextRequestHeaders); } public static function getNextRequestHeaders() { $return = self::$nextRequestHeaders; self::$nextRequestHeaders = null; return $return; } public static function setHttpHeaders($context) { $headers = self::getNextRequestHeaders(); if (!empty($headers)) { $options = stream_context_get_options($context); if (!isset($options['http'])) { $options['http'] = array('header'=>array()); } elseif (!isset($options['http']['header'])) { $options['http']['header'] = array(); } elseif (is_string($options['http']['header'])) { $options['http']['header'] = explode("\r\n", $options['http']['header']); } $headers = empty($options['http']['headers']) ? $headers : array_merge($options['http']['headers'], $headers); stream_context_set_option( $context, 'http', 'header', $headers ); } return $context; } protected function checkConfig() { if (!extension_loaded('openssl')) { throw new \RuntimeException( 'The openssl extension is not loaded but is required for secure HTTPS connections' ); } } protected function getStreamContext($url) { $host = parse_url($url, PHP_URL_HOST); if (PHP_VERSION_ID < 50600) { $this->options['ssl']['CN_match'] = $host; $this->options['ssl']['SNI_server_name'] = $host; } return $this->getMergedStreamContext($url); } protected function getTlsStreamContextDefaults($cafile) { $ciphers = implode(':', array( 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-AES256-GCM-SHA384', 'DHE-RSA-AES128-GCM-SHA256', 'DHE-DSS-AES128-GCM-SHA256', 'kEDH+AESGCM', 'ECDHE-RSA-AES128-SHA256', 'ECDHE-ECDSA-AES128-SHA256', 'ECDHE-RSA-AES128-SHA', 'ECDHE-ECDSA-AES128-SHA', 'ECDHE-RSA-AES256-SHA384', 'ECDHE-ECDSA-AES256-SHA384', 'ECDHE-RSA-AES256-SHA', 'ECDHE-ECDSA-AES256-SHA', 'DHE-RSA-AES128-SHA256', 'DHE-RSA-AES128-SHA', 'DHE-DSS-AES128-SHA256', 'DHE-RSA-AES256-SHA256', 'DHE-DSS-AES256-SHA', 'DHE-RSA-AES256-SHA', 'AES128-GCM-SHA256', 'AES256-GCM-SHA384', 'AES128-SHA256', 'AES256-SHA256', 'AES128-SHA', 'AES256-SHA', 'AES', 'CAMELLIA', 'DES-CBC3-SHA', '!aNULL', '!eNULL', '!EXPORT', '!DES', '!RC4', '!MD5', '!PSK', '!aECDH', '!EDH-DSS-DES-CBC3-SHA', '!EDH-RSA-DES-CBC3-SHA', '!KRB5-DES-CBC3-SHA', '!ADH' )); $options = array( 'ssl' => array( 'ciphers' => $ciphers, 'verify_peer' => true, 'verify_depth' => 7, 'SNI_enabled' => true, ) ); if (!$cafile) { $cafile = self::getSystemCaRootBundlePath(); } if (is_dir($cafile)) { $options['ssl']['capath'] = $cafile; } elseif ($cafile) { $options['ssl']['cafile'] = $cafile; } else { throw new \RuntimeException('A valid cafile could not be located locally.'); } if (version_compare(PHP_VERSION, '5.4.13') >= 0) { $options['ssl']['disable_compression'] = true; } return $options; } /** * function copied from Composer\Util\StreamContextFactory::getContext * * This function is part of Composer. * * (c) Nils Adermann * Jordi Boggiano * * @param string $url URL the context is to be used for * @return resource Default context * @throws \\RuntimeException if https proxy required and OpenSSL uninstalled */ protected function getMergedStreamContext($url) { $options = $this->options; // Handle system proxy if (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy'])) { // Some systems seem to rely on a lowercased version instead... $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']); } if (!empty($proxy)) { $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : ''; $proxyURL .= isset($proxy['host']) ? $proxy['host'] : ''; if (isset($proxy['port'])) { $proxyURL .= ":" . $proxy['port']; } elseif ('http://' == substr($proxyURL, 0, 7)) { $proxyURL .= ":80"; } elseif ('https://' == substr($proxyURL, 0, 8)) { $proxyURL .= ":443"; } // http(s):// is not supported in proxy $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) { throw new \RuntimeException('You must enable the openssl extension to use a proxy over https'); } $options['http'] = array( 'proxy' => $proxyURL, ); // enabled request_fulluri unless it is explicitly disabled switch (parse_url($url, PHP_URL_SCHEME)) { case 'http': // default request_fulluri to true $reqFullUriEnv = getenv('HTTP_PROXY_REQUEST_FULLURI'); if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) { $options['http']['request_fulluri'] = true; } break; case 'https': // default request_fulluri to true $reqFullUriEnv = getenv('HTTPS_PROXY_REQUEST_FULLURI'); if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) { $options['http']['request_fulluri'] = true; } break; } if (isset($proxy['user'])) { $auth = urldecode($proxy['user']); if (isset($proxy['pass'])) { $auth .= ':' . urldecode($proxy['pass']); } $auth = base64_encode($auth); $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; } } return stream_context_create($options); } /** * This method was adapted from Sslurp. * https://github.com/EvanDotPro/Sslurp * * (c) Evan Coury * * For the full copyright and license information, please see below: * * Copyright (c) 2013, Evan Coury * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ public static function getSystemCaRootBundlePath() { static $found = null; if ($found !== null) { return $found; } // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. $envCertFile = getenv('SSL_CERT_FILE'); if ($envCertFile && is_readable($envCertFile) && self::validateCaFile(file_get_contents($envCertFile))) { // Possibly throw exception instead of ignoring SSL_CERT_FILE if it's invalid? return $envCertFile; } $caBundlePaths = array( '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) '/usr/ssl/certs/ca-bundle.crt', // Cygwin '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? '/etc/ssl/cert.pem', // OpenBSD ); $found = null; $configured = ini_get('openssl.cafile'); if ($configured && strlen($configured) > 0 && is_readable($caBundle) && self::validateCaFile(file_get_contents($caBundle))) { $found = true; $caBundle = $configured; } else { foreach ($caBundlePaths as $caBundle) { if (@is_readable($caBundle) && self::validateCaFile(file_get_contents($caBundle))) { $found = true; break; } } if (!$found) { foreach ($caBundlePaths as $caBundle) { $caBundle = dirname($caBundle); if (is_dir($caBundle) && glob($caBundle.'/*')) { $found = true; break; } } } } if ($found) { $found = $caBundle; } return $found; } protected static function validateCaFile($contents) { // assume the CA is valid if php is vunerable to // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html if ( PHP_VERSION_ID <= 50327 || (PHP_VERSION_ID >= 50400 && PHP_VERSION_ID < 50422) || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50506) ) { return !empty($contents); } return (bool) openssl_x509_parse($contents); } } = 50600) { $this->markTestSkipped('Under PHP 5.6+ no requests will be modified.'); } if (null === self::$result) { $result = humbug_get_contents('https://howsmyssl.com/a/check'); self::$result = json_decode($result, true); } } public function teardown() { @unlink(sys_get_temp_dir() . '/humbug.tmp'); } public function testRating() { $this->assertEquals('Improvable', self::$result['rating']); } public function testTlsCompression() { $this->assertFalse(self::$result['tls_compression_supported']); } public function testSslNotUsed() { $this->assertEquals(stripos(self::$result['tls_version'], 'tls 1.'), 0); } public function testBeastVulnerability() { $this->assertFalse(self::$result['beast_vuln']); } public function testInsecureCipherSuites() { $this->assertEmpty(self::$result['insecure_cipher_suites']); } public function testUnknownCipherSuites() { $this->assertFalse(self::$result['unknown_cipher_suite_supported']); } public function testFileGetContentsWillPassThrough() { file_put_contents(sys_get_temp_dir() . '/humbug.tmp', ($expected = uniqid()), LOCK_EX); $this->assertEquals(file_get_contents(sys_get_temp_dir() . '/humbug.tmp'), $expected); } public function testCanGetResponseHeaders() { humbug_set_headers(['Accept-Language: da\r\n']); humbug_get_contents('http://padraic.github.io'); $this->assertTrue(count(humbug_get_headers()) > 0); } public function testCanSetRequestHeaders() { humbug_set_headers(array( 'Accept-Language: da', 'User-Agent: Humbug' )); $out = humbug_get_contents('http://myhttp.info/'); $this->assertEquals(1, preg_match('%'.preg_quote('Accept languageda').'%', $out)); $this->assertEquals(1, preg_match('%'.preg_quote('User agentHumbug').'%', $out)); } }remoteUrl); restore_error_handler(); if (false === $result) { throw new HttpRequestException(sprintf( 'Request to URL failed: %s', $this->remoteUrl )); } file_put_contents($updater->getTempPharFile(), $result); } /** * Retrieve the current version available remotely. * * @param Updater $updater * @return string|bool */ public function getCurrentRemoteVersion(Updater $updater) { /** Switch remote request errors to HttpRequestExceptions */ set_error_handler(array($updater, 'throwHttpRequestException')); $packageUrl = $this->getApiUrl(); $package = json_decode(humbug_get_contents($packageUrl), true); restore_error_handler(); if (null === $package || json_last_error() !== JSON_ERROR_NONE) { throw new JsonParsingException( 'Error parsing JSON package data' . (function_exists('json_last_error_msg') ? ': ' . json_last_error_msg() : '') ); } $versions = array_keys($package['packages'][$this->getPackageName()]); $versionParser = new VersionParser($versions); if ($this->getStability() === self::STABLE) { $this->remoteVersion = $versionParser->getMostRecentStable(); } elseif ($this->getStability() === self::UNSTABLE) { $this->remoteVersion = $versionParser->getMostRecentUnstable(); } else { $this->remoteVersion = $versionParser->getMostRecentAll(); } /** * Setup remote URL if there's an actual version to download */ if (!empty($this->remoteVersion)) { $this->remoteUrl = $this->getDownloadUrl($package); } return $this->remoteVersion; } /** * Retrieve the current version of the local phar file. * * @param Updater $updater * @return string */ public function getCurrentLocalVersion(Updater $updater) { return $this->localVersion; } /** * Set version string of the local phar * * @param string $version */ public function setCurrentLocalVersion($version) { $this->localVersion = $version; } /** * Set Package name * * @param string $name */ public function setPackageName($name) { $this->packageName = $name; } /** * Get Package name * * @return string */ public function getPackageName() { return $this->packageName; } /** * Set phar file's name * * @param string $name */ public function setPharName($name) { $this->pharName = $name; } /** * Get phar file's name * * @return string */ public function getPharName() { return $this->pharName; } /** * Set target stability * * @param string $stability */ public function setStability($stability) { if ($stability !== self::STABLE && $stability !== self::UNSTABLE && $stability !== self::ANY) { throw new InvalidArgumentException( 'Invalid stability value. Must be one of "stable", "unstable" or "any".' ); } $this->stability = $stability; } /** * Get target stability * * @return string */ public function getStability() { return $this->stability; } protected function getApiUrl() { return sprintf(self::API_URL, $this->getPackageName()); } protected function getDownloadUrl(array $package) { $baseUrl = preg_replace( '{\.git$}', '', $package['packages'][$this->getPackageName()][$this->remoteVersion]['source']['url'] ); $downloadUrl = sprintf( '%s/releases/download/%s/%s', $baseUrl, $this->remoteVersion, $this->getPharName() ); return $downloadUrl; } } getPharUrl()); restore_error_handler(); if (false === $result) { throw new HttpRequestException(sprintf( 'Request to URL failed: %s', $this->getPharUrl() )); } file_put_contents($updater->getTempPharFile(), $result); } /** * Retrieve the current version available remotely. * * @param Updater $updater * @return string|bool */ public function getCurrentRemoteVersion(Updater $updater) { /** Switch remote request errors to HttpRequestExceptions */ set_error_handler(array($updater, 'throwHttpRequestException')); $version = humbug_get_contents($this->getVersionUrl()); restore_error_handler(); if (false === $version) { throw new HttpRequestException(sprintf( 'Request to URL failed: %s', $this->getVersionUrl() )); } if (empty($version)) { throw new HttpRequestException( 'Version request returned empty response.' ); } if (!preg_match('%^[a-z0-9]{40}%', $version, $matches)) { throw new HttpRequestException( 'Version request returned incorrectly formatted response.' ); } return $matches[0]; } /** * Retrieve the current version of the local phar file. * * @param Updater $updater * @return string */ public function getCurrentLocalVersion(Updater $updater) { return sha1_file($updater->getLocalPharFile()); } /** * Set URL to phar file * * @param string $url */ public function setPharUrl($url) { if (!$this->validateAllowedUrl($url)) { throw new InvalidArgumentException( sprintf('Invalid url passed as argument: %s.', $url) ); } $this->pharUrl = $url; } /** * Get URL for phar file * * @return string */ public function getPharUrl() { return $this->pharUrl; } /** * Set URL to version file * * @param string $url */ public function setVersionUrl($url) { if (!$this->validateAllowedUrl($url)) { throw new InvalidArgumentException( sprintf('Invalid url passed as argument: %s.', $url) ); } $this->versionUrl = $url; } /** * Get URL for version file * * @return string */ public function getVersionUrl() { return $this->versionUrl; } protected function validateAllowedUrl($url) { if (filter_var($url, FILTER_VALIDATE_URL) && in_array(parse_url($url, PHP_URL_SCHEME), array('http', 'https', 'file'))) { return true; } return false; } } setLocalPharFile($localPharFile); if (!is_bool($hasPubKey)) { throw new InvalidArgumentException( 'Constructor parameter $hasPubKey must be boolean or null.' ); } else { $this->hasPubKey = $hasPubKey; } if ($this->hasPubKey) { $this->setLocalPubKeyFile(); } $this->setTempDirectory(); $this->setStrategy($strategy); } /** * Check for update * * @return bool */ public function hasUpdate() { $this->newVersionAvailable = $this->newVersionAvailable(); return $this->newVersionAvailable; } /** * Perform an update * * @return bool */ public function update() { if ($this->newVersionAvailable === false || (!is_bool($this->newVersionAvailable) && !$this->hasUpdate())) { return false; } $this->backupPhar(); $this->downloadPhar(); $this->replacePhar(); return true; } /** * Perform an rollback to previous version * * @return bool */ public function rollback() { if (!$this->restorePhar()) { return false; } return true; } /** * @param string $strategy */ public function setStrategy($strategy) { switch ($strategy) { case self::STRATEGY_GITHUB: $this->strategy = new GithubStrategy; break; default: $this->strategy = new ShaStrategy; break; } } public function setStrategyObject(StrategyInterface $strategy) { $this->strategy = $strategy; } public function getStrategy() { return $this->strategy; } /** * Set backup extension for old phar versions * * @param string $extension */ public function setBackupExtension($extension) { $this->backupExtension = $extension; } /** * Get backup extension for old phar versions * * @return string */ public function getBackupExtension() { return $this->backupExtension; } public function getLocalPharFile() { return $this->localPharFile; } public function getLocalPharFileBasename() { return $this->localPharFileBasename; } public function getLocalPubKeyFile() { return $this->localPubKeyFile; } public function getTempDirectory() { return $this->tempDirectory; } public function getTempPharFile() { return $this->getTempDirectory() . '/' . sprintf('%s.phar.temp', $this->getLocalPharFileBasename()); } public function getNewVersion() { return $this->newVersion; } public function getOldVersion() { return $this->oldVersion; } /** * Set backup path for old phar versions * * @param string $filePath */ public function setBackupPath($filePath) { $path = realpath(dirname($filePath)); if (!is_dir($path)) { throw new FilesystemException(sprintf( 'The backup directory does not exist: %s.', $path )); } if (!is_writable($path)) { throw new FilesystemException(sprintf( 'The backup directory is not writeable: %s.', $path )); } $this->backupPath = $filePath; } /** * Get backup path for old phar versions * * @return string */ public function getBackupPath() { return $this->backupPath; } /** * Set path for the backup phar to rollback/restore from * * @param string $filePath */ public function setRestorePath($filePath) { $path = realpath(dirname($filePath)); if (!file_exists($path)) { throw new FilesystemException(sprintf( 'The restore phar does not exist: %s.', $path )); } if (!is_readable($path)) { throw new FilesystemException(sprintf( 'The restore file is not readable: %s.', $path )); } $this->restorePath = $filePath; } /** * Get path for the backup phar to rollback/restore from * * @return string */ public function getRestorePath() { return $this->restorePath; } public function throwRuntimeException($errno, $errstr) { if (E_USER_DEPRECATED === $errno) { return; } throw new RuntimeException($errstr); } public function throwHttpRequestException($errno, $errstr) { if (E_USER_DEPRECATED === $errno) { return; } throw new HttpRequestException($errstr); } protected function hasPubKey() { return $this->hasPubKey; } protected function newVersionAvailable() { $this->newVersion = $this->strategy->getCurrentRemoteVersion($this); $this->oldVersion = $this->strategy->getCurrentLocalVersion($this); if (!empty($this->newVersion) && ($this->newVersion !== $this->oldVersion)) { return true; } return false; } protected function backupPhar() { $result = copy($this->getLocalPharFile(), $this->getBackupPharFile()); if ($result === false) { $this->cleanupAfterError(); throw new FilesystemException(sprintf( 'Unable to backup %s to %s.', $this->getLocalPharFile(), $this->getBackupPharFile() )); } } protected function downloadPhar() { $this->strategy->download($this); if (!file_exists($this->getTempPharFile())) { throw new FilesystemException( 'Creation of download file failed.' ); } if ($this->getStrategy() instanceof ShaStrategy) { $tmpVersion = sha1_file($this->getTempPharFile()); if ($tmpVersion !== $this->getNewVersion()) { $this->cleanupAfterError(); throw new HttpRequestException(sprintf( 'Download file appears to be corrupted or outdated. The file ' . 'received does not have the expected SHA-1 hash: %s.', $this->getNewVersion() )); } } try { $this->validatePhar($this->getTempPharFile()); } catch (\Exception $e) { restore_error_handler(); $this->cleanupAfterError(); throw $e; } } protected function replacePhar() { rename($this->getTempPharFile(), $this->getLocalPharFile()); } protected function restorePhar() { $backup = $this->getRestorePharFile(); if (!file_exists($backup)) { throw new RuntimeException(sprintf( 'The backup file does not exist: %s.', $backup )); } $this->validatePhar($backup); return rename($backup, $this->getLocalPharFile()); } protected function getBackupPharFile() { if (null !== $this->getBackupPath()) { return $this->getBackupPath(); } return $this->getTempDirectory() . '/' . sprintf('%s%s', $this->getLocalPharFileBasename(), $this->getBackupExtension()); } protected function getRestorePharFile() { if (null !== $this->getRestorePath()) { return $this->getRestorePath(); } return $this->getTempDirectory() . '/' . sprintf('%s%s', $this->getLocalPharFileBasename(), $this->getBackupExtension() ); } protected function getTempPubKeyFile() { return $this->getTempDirectory() . '/' . sprintf('%s.phar.temp.pubkey', $this->getLocalPharFileBasename()); } protected function setLocalPharFile($localPharFile) { if (!is_null($localPharFile)) { $localPharFile = realpath($localPharFile); } else { $localPharFile = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; } if (!file_exists($localPharFile)) { throw new RuntimeException(sprintf( 'The set phar file does not exist: %s.', $localPharFile )); } if (!is_writable($localPharFile)) { throw new FilesystemException(sprintf( 'The current phar file is not writeable and cannot be replaced: %s.', $localPharFile )); } $this->localPharFile = $localPharFile; $this->localPharFileBasename = basename($localPharFile, '.phar'); } protected function setLocalPubKeyFile() { $localPubKeyFile = $this->getLocalPharFile() . '.pubkey'; if (!file_exists($localPubKeyFile)) { throw new RuntimeException(sprintf( 'The phar pubkey file does not exist: %s.', $localPubKeyFile )); } $this->localPubKeyFile = $localPubKeyFile; } protected function setTempDirectory() { $tempDirectory = dirname($this->getLocalPharFile()); if (!is_writable($tempDirectory)) { throw new FilesystemException(sprintf( 'The directory is not writeable: %s.', $tempDirectory )); } $this->tempDirectory = $tempDirectory; } protected function validatePhar($phar) { $phar = realpath($phar); if ($this->hasPubKey()) { copy($this->getLocalPubKeyFile(), $phar . '.pubkey'); } chmod($phar, fileperms($this->getLocalPharFile())); /** Switch invalid key errors to RuntimeExceptions */ set_error_handler(array($this, 'throwRuntimeException')); $phar = new \Phar($phar); $signature = $phar->getSignature(); if ($this->hasPubKey() && strtolower($signature['hash_type']) !== 'openssl') { throw new NoSignatureException( 'The downloaded phar file has no OpenSSL signature.' ); } restore_error_handler(); if ($this->hasPubKey()) { @unlink($phar . '.pubkey'); } unset($phar); } protected function cleanupAfterError() { //@unlink($this->getBackupPharFile()); @unlink($this->getTempPharFile()); @unlink($this->getTempPubKeyFile()); } } versions = $versions; } /** * Get the most recent stable numbered version from versions passed to * constructor (if any) * * @return string */ public function getMostRecentStable() { return $this->selectRecentStable(); } /** * Get the most recent unstable numbered version from versions passed to * constructor (if any) * * @return string */ public function getMostRecentUnStable() { return $this->selectRecentUnstable(); } /** * Get the most recent stable or unstable numbered version from versions passed to * constructor (if any) * * @return string */ public function getMostRecentAll() { return $this->selectRecentAll(); } /** * Checks if given version string represents a stable numbered version * * @param string $version * @return bool */ public function isStable($version) { return $this->stable($version); } /** * Checks if given version string represents a 'pre-release' version, i.e. * it's unstable but not development level. * * @param string $version * @return bool */ public function isPreRelease($version) { return !$this->stable($version) && !$this->development($version); } /** * Checks if given version string represents an unstable or dev-level * numbered version * * @param string $version * @return bool */ public function isUnstable($version) { return !$this->stable($version); } /** * Checks if given version string represents a dev-level numbered version * * @param string $version * @return bool */ public function isDevelopment($version) { return $this->development($version); } private function selectRecentStable() { $candidates = array(); foreach ($this->versions as $version) { if (!$this->stable($version)) { continue; } $candidates[] = $version; } if (empty($candidates)) { return false; } return $this->findMostRecent($candidates); } private function selectRecentUnstable() { $candidates = array(); foreach ($this->versions as $version) { if ($this->stable($version) || $this->development($version)) { continue; } $candidates[] = $version; } if (empty($candidates)) { return false; } return $this->findMostRecent($candidates); } private function selectRecentAll() { $candidates = array(); foreach ($this->versions as $version) { if ($this->development($version)) { continue; } $candidates[] = $version; } if (empty($candidates)) { return false; } return $this->findMostRecent($candidates); } private function findMostRecent(array $candidates) { $candidate = null; $tracker = null; foreach ($candidates as $version) { if (version_compare($candidate, $version, '<')) { $candidate = $version; } } return $candidate; } private function stable($version) { $version = preg_replace('{#.+$}i', '', $version); if ($this->development($version)) { return false; } preg_match('{'.$this->modifier.'$}i', strtolower($version), $match); if (!empty($match[3])) { return false; } if (!empty($match[1])) { if ('beta' === $match[1] || 'b' === $match[1] || 'alpha' === $match[1] || 'a' === $match[1] || 'rc' === $match[1]) { return false; } } return true; } private function development($version) { if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) { return true; } if (1 == preg_match("/-\d+-[a-z0-9]{8,}$/", $version)) { return true; } return false; } } tmp = sys_get_temp_dir(); $this->files = __DIR__ . '/_files'; $this->updater = new Updater($this->files . '/test.phar', false, Updater::STRATEGY_GITHUB); } public function teardown() { $this->deleteTempPhars(); } public function testConstruction() { $updater = new Updater(null, false, Updater::STRATEGY_GITHUB); $this->assertTrue( $updater->getStrategy() instanceof GithubStrategy ); } public function testSetCurrentLocalVersion() { $this->updater->getStrategy()->setCurrentLocalVersion('1.0'); $this->assertEquals( '1.0', $this->updater->getStrategy()->getCurrentLocalVersion($this->updater) ); } public function testSetPharName() { $this->updater->getStrategy()->setPharName('foo.phar'); $this->assertEquals( 'foo.phar', $this->updater->getStrategy()->getPharName() ); } public function testSetPackageName() { $this->updater->getStrategy()->setPackageName('foo/bar'); $this->assertEquals( 'foo/bar', $this->updater->getStrategy()->getPackageName() ); } public function testSetStability() { $this->assertEquals( 'stable', $this->updater->getStrategy()->getStability() ); $this->updater->getStrategy()->setStability('unstable'); $this->assertEquals( 'unstable', $this->updater->getStrategy()->getStability() ); } public function testSetStabilityThrowsExceptionOnInvalidStabilityValue() { $this->setExpectedException( 'Humbug\\SelfUpdate\\Exception\\InvalidArgumentException' ); $this->updater->getStrategy()->setStability('foo'); } /** * @runInSeparateProcess */ public function testUpdatePhar() { if (!extension_loaded('openssl')) { $this->markTestSkipped('This test requires the openssl extension to run.'); } $this->createTestPharAndKey(); $this->assertEquals('old', $this->getPharOutput($this->tmp . '/old.phar')); $updater = new Updater($this->tmp . '/old.phar'); $updater->setStrategyObject(new GithubTestStrategy); $updater->getStrategy()->setPharName('new.phar'); $updater->getStrategy()->setPackageName('humbug/test-phar'); $updater->getStrategy()->setCurrentLocalVersion('1.0.0'); $this->assertTrue($updater->update()); $this->assertEquals('new', $this->getPharOutput($this->tmp . '/old.phar')); } /** * Helpers */ private function getPharOutput($path) { return exec('php ' . escapeshellarg($path)); } private function deleteTempPhars() { @unlink($this->tmp . '/old.phar'); @unlink($this->tmp . '/old.phar.pubkey'); @unlink($this->tmp . '/releases/download/1.0.1/new.phar'); @unlink($this->tmp . '/releases/download/1.0.1/new.phar.pubkey'); @unlink($this->tmp . '/old.1c7049180abee67826d35ce308c38272242b64b8.phar'); @unlink($this->tmp . '/packages.json'); } private function createTestPharAndKey() { copy($this->files.'/build/old.phar', $this->tmp.'/old.phar'); chmod($this->tmp.'/old.phar', 0755); copy( $this->files.'/build/old.phar.pubkey', $this->tmp.'/old.phar.pubkey' ); @mkdir($this->tmp.'/releases/download/1.0.1', 0755, true); copy($this->files.'/build/new.phar', $this->tmp.'/releases/download/1.0.1/new.phar'); file_put_contents($this->tmp . '/packages.json', json_encode(array( 'packages' => array( 'humbug/test-phar' => array( '1.0.1' => array( 'source' => array( 'url' => 'file://' . $this->tmp . '.git' ) ), '1.0.0' => array( ) ) ) ))); } } class GithubTestStrategy extends GithubStrategy { protected function getApiUrl() { return 'file://' . sys_get_temp_dir() . '/packages.json'; } } tmp = sys_get_temp_dir(); $this->files = __DIR__ . '/_files'; $this->updater = new Updater($this->files . '/test.phar'); } public function teardown() { $this->deleteTempPhars(); } public function testConstruction() { // with key $updater = new Updater($this->files . '/test.phar'); $this->assertEquals($updater->getLocalPharFile(), $this->files . '/test.phar'); $this->assertEquals($updater->getLocalPubKeyFile(), $this->files . '/test.phar.pubkey'); // without key $updater = new Updater($this->files . '/test.phar', false); $this->assertEquals($updater->getLocalPharFile(), $this->files . '/test.phar'); $this->assertNull($updater->getLocalPubKeyFile()); // no name - detect running console app $updater = new Updater(null, false); $this->assertStringEndsWith( 'phpunit.phar', basename($updater->getLocalPharFile(), '.phar') . '.phar' ); } public function testConstructorThrowsExceptionIfPubKeyNotExistsButFlagTrue() { $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\RuntimeException'); $updater = new Updater($this->files . '/test-nopubkey.phar'); } public function testConstructorAncilliaryValues() { $this->assertEquals($this->updater->getLocalPharFileBasename(), 'test'); $this->assertEquals($this->updater->getTempDirectory(), $this->files); } public function testSetPharUrlWithUrl() { $this->updater->getStrategy()->setPharUrl('http://www.example.com'); $this->assertEquals($this->updater->getStrategy()->getPharUrl(), 'http://www.example.com'); $this->updater->getStrategy()->setPharUrl('https://www.example.com'); $this->assertEquals($this->updater->getStrategy()->getPharUrl(), 'https://www.example.com'); } public function testSetPharUrlThrowsExceptionOnInvalidUrl() { $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\InvalidArgumentException'); $this->updater->getStrategy()->setPharUrl('silly:///home/padraic'); } public function testSetVersionUrlWithUrl() { $this->updater->getStrategy()->setVersionUrl('http://www.example.com'); $this->assertEquals($this->updater->getStrategy()->getVersionUrl(), 'http://www.example.com'); $this->updater->getStrategy()->setVersionUrl('https://www.example.com'); $this->assertEquals($this->updater->getStrategy()->getVersionUrl(), 'https://www.example.com'); } public function testSetVersionUrlThrowsExceptionOnInvalidUrl() { $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\InvalidArgumentException'); $this->updater->getStrategy()->setVersionUrl('silly:///home/padraic'); } public function testCanDetectNewRemoteVersionAndStoreVersions() { $this->updater->getStrategy()->setVersionUrl('file://' . $this->files . '/good.version'); $this->assertTrue($this->updater->hasUpdate()); $this->assertEquals('da39a3ee5e6b4b0d3255bfef95601890afd80709', $this->updater->getOldVersion()); $this->assertEquals('1af1b9c94dea1ff337587bfa9109f1dad1ec7b9b', $this->updater->getNewVersion()); } public function testThrowsExceptionOnEmptyRemoteVersion() { $this->setExpectedException( 'Humbug\\SelfUpdate\\Exception\\HttpRequestException', 'Version request returned empty response' ); $this->updater->getStrategy()->setVersionUrl('file://' . $this->files . '/empty.version'); $this->assertTrue($this->updater->hasUpdate()); } public function testThrowsExceptionOnInvalidRemoteVersion() { $this->setExpectedException( 'Humbug\\SelfUpdate\\Exception\\HttpRequestException', 'Version request returned incorrectly formatted response' ); $this->updater->getStrategy()->setVersionUrl('file://' . $this->files . '/bad.version'); $this->assertTrue($this->updater->hasUpdate()); } /** * @runInSeparateProcess */ public function testUpdatePhar() { if (!extension_loaded('openssl')) { $this->markTestSkipped('This test requires the openssl extension to run.'); } $this->createTestPharAndKey(); $this->assertEquals('old', $this->getPharOutput($this->tmp . '/old.phar')); $updater = new Updater($this->tmp . '/old.phar'); $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/new.phar'); $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/new.version'); $this->assertTrue($updater->update()); $this->assertEquals('new', $this->getPharOutput($this->tmp . '/old.phar')); } /** * @runInSeparateProcess */ public function testUpdatePharFailsIfCurrentPublicKeyEmpty() { //$this->markTestSkipped('Segmentation fault at present under PHP'); copy($this->files . '/build/badkey.phar', $this->tmp . '/old.phar'); chmod($this->tmp . '/old.phar', 0755); copy($this->files . '/build/badkey.phar.pubkey', $this->tmp . '/old.phar.pubkey'); $updater = new Updater($this->tmp . '/old.phar'); $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/new.phar'); $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/new.version'); $this->setExpectedException('UnexpectedValueException'); $updater->update(); } /** * @runInSeparateProcess */ public function testUpdatePharFailsIfCurrentPublicKeyInvalid() { $this->markTestIncomplete('Segmentation fault at present under PHP'); /** Should be similar to testUpdatePharFailsIfCurrentPublicKeyEmpty with corrupt or truncated public key */ } /** * @runInSeparateProcess */ public function testUpdatePharFailsOnExpectedSignatureMismatch() { if (!extension_loaded('openssl')) { $this->markTestSkipped('This test requires the openssl extension to run.'); } $this->createTestPharAndKey(); $this->assertEquals('old', $this->getPharOutput($this->tmp . '/old.phar')); /** Signature check should fail with invalid signature by a different privkey */ $this->setExpectedException('UnexpectedValueException'); $updater = new Updater($this->tmp . '/old.phar'); $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/badsig.phar'); $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/badsig.version'); $updater->update(); } /** * @runInSeparateProcess */ public function testUpdatePharFailsIfDownloadPharIsUnsignedWhenExpected() { $this->createTestPharAndKey(); $updater = new Updater($this->tmp . '/old.phar'); $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/nosig.phar'); $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/nosig.version'); /** If newly download phar lacks an expected signature, an exception should be thrown */ $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\RuntimeException'); $updater->update(); } public function testSetBackupPathSetsThePathWhenTheDirectoryExistsAndIsWriteable() { $this->createTestPharAndKey(); $updater = new Updater($this->tmp . '/old.phar'); $updater->setBackupPath($this->tmp . '/backup.phar'); $res = $updater->getBackupPath(); $this->assertEquals($this->tmp . '/backup.phar', $res); } public function testSetRestorePathSetsThePathWhenTheDirectoryExistsAndIsWriteable() { $this->createTestPharAndKey(); $updater = new Updater($this->tmp . '/old.phar'); $updater->setRestorePath($this->tmp . '/backup.phar'); $res = $updater->getRestorePath(); $this->assertEquals($this->tmp . '/backup.phar', $res); } /** * Custom Strategies */ public function testCanSetCustomStrategyObjects() { $this->updater->setStrategyObject(new FooStrategy); $this->assertTrue($this->updater->getStrategy() instanceof FooStrategy); } /** * Helpers */ private function getPharOutput($path) { return exec('php ' . escapeshellarg($path)); } private function deleteTempPhars() { @unlink($this->tmp . '/old.phar'); @unlink($this->tmp . '/old.phar.pubkey'); @unlink($this->tmp . '/old.1c7049180abee67826d35ce308c38272242b64b8.phar'); } private function createTestPharAndKey() { copy($this->files.'/build/old.phar', $this->tmp.'/old.phar'); chmod($this->tmp.'/old.phar', 0755); copy( $this->files.'/build/old.phar.pubkey', $this->tmp.'/old.phar.pubkey' ); } } class FooStrategy implements StrategyInterface { public function download(Updater $updater) { } public function getCurrentRemoteVersion(Updater $updater) { } public function getCurrentLocalVersion(Updater $updater) { } } assertSame(false, $parser->getMostRecentStable()); } public function testShouldSelectMostRecentVersionFromStandardSelection() { $versions = array('1.0.0', '1.0.1', '1.1.0'); $parser = new VersionParser($versions); $this->assertSame('1.1.0', $parser->getMostRecentStable()); } public function testShouldSelectMostRecentVersionFromMixedSelection() { $versions = array('1.0.0', '1.0.1', '1.1.0', '1.2.0a', '1.2.0b', '1.1.0rc'); $parser = new VersionParser($versions); $this->assertSame('1.1.0', $parser->getMostRecentStable()); } public function testShouldSelectMostRecentVersionFromPrefixedSelection() { $versions = array('v1.0.0', 'v1.0.1', 'v1.1.0'); $parser = new VersionParser($versions); $this->assertSame('v1.1.0', $parser->getMostRecentStable()); } public function testShouldSelectMostRecentVersionFromPartlyPrefixedSelection() { $versions = array('v1.0.0', 'v1.0.1', '1.1.0'); $parser = new VersionParser($versions); $this->assertSame('1.1.0', $parser->getMostRecentStable()); } public function testShouldSelectMostRecentVersionFromPatchLevels() { $versions = array('1.0.0', '1.0.0-pl2', '1.0.0-pl3', '1.0.0-pl1'); $parser = new VersionParser($versions); $this->assertSame('1.0.0-pl3', $parser->getMostRecentStable()); } public function testShouldSelectMostRecentVersionFromPatchLevels2() { $versions = array('1.0.0', '1.0.0pl2', '1.0.0pl3', '1.0.0pl1'); $parser = new VersionParser($versions); $this->assertSame('1.0.0pl3', $parser->getMostRecentStable()); } // Unstable public function testShouldSelectNothingFromUnstablesIfUnstableRequested() { $versions = array('1.0.0', '1.0.1', '1.1.0'); $parser = new VersionParser($versions); $this->assertSame(false, $parser->getMostRecentUnstable()); } public function testShouldSelectNothingFromStablesOrDevsIfUnstableRequested() { $versions = array('1.0.0', '1.0.1', '1.1.0-dev', 'dev-1.1.1'); $parser = new VersionParser($versions); $this->assertSame(false, $parser->getMostRecentUnstable()); } public function testShouldSelectMostRecentUnstableVersionFromStandardSelection() { $versions = array('1.0.0a', '1.0.0alpha', '1.0.0-dev', 'dev-1.0.0', '1.0.0b', '1.0.0beta', '1.0.0rc', '1.0.0RC'); $parser = new VersionParser($versions); $this->assertSame('1.0.0rc', $parser->getMostRecentUnstable()); } public function testShouldSelectMostRecentUnstableVersionFromMixedSelection() { $versions = array('1.0.0', '1.0.1', '1.1.0', '1.2.0a', '1.2.0b', '1.1.0rc'); $parser = new VersionParser($versions); $this->assertSame('1.2.0b', $parser->getMostRecentUnstable()); } public function testShouldSelectMostRecentUnstableVersionFromPrefixedSelection() { $versions = array('v1.0.0b', 'v1.0.1', 'v1.1.0'); $parser = new VersionParser($versions); $this->assertSame('v1.0.0b', $parser->getMostRecentUnstable()); } public function testShouldSelectMostRecentUnstableVersionFromPartlyPrefixedSelection() { $versions = array('v1.0.0b', 'v1.0.0a', '1.1.0a'); $parser = new VersionParser($versions); $this->assertSame('1.1.0a', $parser->getMostRecentUnstable()); } public function testShouldSelectMostRecentUnstableFromVaryingNumeralCounts() { $versions = array('1.0-dev', '1.0.0-alpha1'); $parser = new VersionParser($versions); $this->assertSame('1.0.0-alpha1', $parser->getMostRecentUnstable()); } // All versions (ignoring stability) public function testShouldSelectMostRecentIgnoringStabilityExceptDevFromPrefixedSelection() { $versions = array('v1.0.0b', 'v1.0.1', 'v1.1.0a', 'v1.2.0-dev'); $parser = new VersionParser($versions); $this->assertSame('v1.1.0a', $parser->getMostRecentAll()); } // Basic Version Category Checks public function testIsStable() { $parser = new VersionParser; $this->assertTrue($parser->isStable('1.0.0')); $this->assertFalse($parser->isStable('1.0.0b')); $this->assertFalse($parser->isStable('1.0.0-dev')); $this->assertFalse($parser->isStable('1.0.0-alpha1-5-g5b46ad8')); } public function testIsPreRelease() { $parser = new VersionParser; $this->assertFalse($parser->isPreRelease('1.0.0')); $this->assertTrue($parser->isPreRelease('1.0.0b')); $this->assertFalse($parser->isPreRelease('1.0.0-dev')); $this->assertFalse($parser->isPreRelease('1.0.0-alpha1-5-g5b46ad8')); } public function testIsUnstable() { $parser = new VersionParser; $this->assertFalse($parser->isUnstable('1.0.0')); $this->assertTrue($parser->isUnstable('1.0.0b')); $this->assertTrue($parser->isUnstable('1.0.0-dev')); $this->assertTrue($parser->isUnstable('1.0.0-alpha1-5-g5b46ad8')); } public function testIsDevelopment() { $parser = new VersionParser; $this->assertFalse($parser->isDevelopment('1.0.0')); $this->assertFalse($parser->isDevelopment('1.0.0b')); $this->assertTrue($parser->isDevelopment('1.0.0-dev')); $this->assertTrue($parser->isDevelopment('1.0.0-alpha1-5-g5b46ad8')); } } 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); } } 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; } } 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; } } 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 Description\Formatter for the formatting of the body and tags. */ class Description { /** @var string */ private $bodyTemplate; /** @var Tag[] */ private $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 ($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(); } } 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); } } getFilePath(); $file = $this->getExampleFileContents($filename); if (!$file) { 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) { 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 && 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, '"') ); } } 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 ? $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; } } 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> An array with a tag as a key, and an * FQCN to a class that handles it as an array value. */ private $tagHandlerMappings = [ 'author' => Author::class, 'covers' => Covers::class, 'deprecated' => Deprecated::class, // 'example' => '\phpDocumentor\Reflection\DocBlock\Tags\Example', 'link' => LinkTag::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, 'throw' => Throws::class, 'throws' => Throws::class, 'uses' => Uses::class, 'var' => Var_::class, 'version' => Version::class, ]; /** * @var array> An array with a anotation s a key, and an * FQCN to a class that handles it as an array value. */ private $annotationMappings = []; /** * @var ReflectionParameter[][] a lazy-loading cache containing parameters * for each tagHandler that has been used. */ private $tagHandlerParameterCache = []; /** @var FqsenResolver */ private $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 $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> $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; } public function registerTagHandler(string $tagName, string $handler): void { Assert::stringNotEmpty($tagName); Assert::classExists($handler); Assert::implementsInterface($handler, Tag::class); if (strpos($tagName, '\\') && $tagName[0] !== '\\') { throw new InvalidArgumentException( 'A namespaced tag must have a leading backslash as it must be fully qualified' ); } $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' ); } if (count($matches) < 3) { $matches[] = ''; } 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) ); 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 */ private function findHandlerClassName(string $tagName, TypeContext $context): string { $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(); } } } if (isset($locator[$typeHint])) { $arguments[] = $locator[$typeHint]; continue; } $parameterName = $parameter->getName(); if (isset($locator[$parameterName])) { $arguments[] = $locator[$parameterName]; continue; } $arguments[] = null; } return $arguments; } /** * Retrieves a series of ReflectionParameter objects for the static 'create' method of the given * tag handler class name. * * @param class-string $handlerClassName * * @return ReflectionParameter[] */ private function fetchParametersForHandlerFactoryMethod(string $handlerClassName): array { 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 aliasses) 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; } } $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, string $handler): void; } 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); } } 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); } } 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 : ''); } } version = $version; $this->description = $description; } /** * @return static */ public static function create( ?string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): self { if (empty($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 : ''); } } 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 ($matches[1] !== '') { $filePath = $matches[1]; } else { $fileUri = $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); } } 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; } } getName() . ' ' . $tag); } } 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.' ); } } } 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'); $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); $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; } } 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 : ''); } } * @var array> */ private $arguments; /** @var bool */ private $isStatic; /** @var Type */ private $returnType; /** * @param array> $arguments * @phpstan-param array $arguments */ public function __construct( string $methodName, array $arguments = [], ?Type $returnType = null, bool $static = false, ?Description $description = null ) { Assert::stringNotEmpty($methodName); if ($returnType === null) { $returnType = new Void_(); } $this->methodName = $methodName; $this->arguments = $this->filterArguments($arguments); $this->returnType = $returnType; $this->isStatic = $static; $this->description = $description; } public static function create( string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): ?self { 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. then optionally a word with underscores followed by () and // whitespace : as method name as used by phpDocumentor // 5. then a word with underscores, followed by ( and any character // until a ) and whitespace : as method name with signature // 6. 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+ )? # Method name ([\w_]+) # Arguments (?: \(([^\)]*)\) )? \s* # Description (.*) $/sux', $body, $matches ) ) { return null; } [, $static, $returnType, $methodName, $argumentLines, $description] = $matches; $static = $static === 'static'; if ($returnType === '') { $returnType = 'void'; } $returnType = $typeResolver->resolve($returnType, $context); $description = $descriptionFactory->create($description, $context); /** @phpstan-var array $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); } /** * Retrieves the method name. */ public function getMethodName(): string { return $this->methodName; } /** * @return array> * @phpstan-return array */ public function getArguments(): array { return $this->arguments; } /** * 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 __toString(): string { $arguments = []; foreach ($this->arguments as $argument) { $arguments[] = $argument['type'] . ' $' . $argument['name']; } $argumentStr = '(' . implode(', ', $arguments) . ')'; if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $static = $this->isStatic ? 'static' : ''; $returnType = (string) $this->returnType; $methodName = $this->methodName; return $static . ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '') . ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $methodName : '') . $argumentStr . ($description !== '' ? ' ' . $description : ''); } /** * @param mixed[][]|string[] $arguments * @phpstan-param array $arguments * * @return mixed[][] * @phpstan-return array */ 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; } } name = 'param'; $this->variableName = $variableName; $this->type = $type; $this->isVariadic = $isVariadic; $this->description = $description; $this->isReference = $isReference; } public static function create( string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): self { 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) { $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; } } name = 'property'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } public static function create( string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): self { 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 : ''); } } name = 'property-read'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } public static function create( string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): self { 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 : ''); } } name = 'property-write'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } public static function create( string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): self { 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 : ''); } } fqsen = $fqsen; } /** * @return string string representation of the referenced fqsen */ public function __toString(): string { return (string) $this->fqsen; } } uri = $uri; } public function __toString(): string { return $this->uri; } } name = 'return'; $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); } public function __toString(): string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $type = $this->type ? '' . $this->type : 'mixed'; return $type . ($description !== '' ? ' ' . $description : ''); } } 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 : ''); } } version = $version; $this->description = $description; } public static function create( ?string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): ?self { if (empty($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) { $description = $this->description->render(); } else { $description = ''; } $version = (string) $this->version; return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : ''); } } 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 : ''); } } 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; } } $description = trim(substr($body, strlen($type))); return [$type, $description]; } } 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); } public function __toString(): string { if ($this->description) { $description = $this->description->render(); } else { $description = ''; } $type = (string) $this->type; return $type . ($description !== '' ? ($type !== '' ? ' ' : '') . $description : ''); } } 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 : ''); } } name = 'var'; $this->variableName = $variableName; $this->type = $type; $this->description = $description; } public static function create( string $body, ?TypeResolver $typeResolver = null, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): self { 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) { $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 : ''); } } version = $version; $this->description = $description; } public static function create( ?string $body, ?DescriptionFactory $descriptionFactory = null, ?TypeContext $context = null ): ?self { if (empty($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 : ''); } } 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; } } descriptionFactory = $descriptionFactory; $this->tagFactory = $tagFactory; } /** * Factory method for easy instantiation. * * @param array> $additionalTags */ public static function createInstance(array $additionalTags = []): self { $fqsenResolver = new FqsenResolver(); $tagFactory = new StandardTagFactory($fqsenResolver); $descriptionFactory = new DescriptionFactory($tagFactory); $tagFactory->addService($descriptionFactory); $tagFactory->addService(new TypeResolver($fqsenResolver)); $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 $handler */ public function registerTagHandler(string $tagName, string $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 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; } } > $additionalTags */ public static function createInstance(array $additionalTags = []): DocBlockFactory; /** * @param string|object $docblock */ public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock; } 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)); } } 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) . '}'; } } 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; } } 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); } } value = $value; } public function getValue(): float { return $this->value; } public function underlyingType(): Type { return new Float_(); } public function __toString(): string { return (string) $this->value; } } 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 . '>'; } } value = $value; } public function getValue(): int { return $this->value; } public function underlyingType(): Type { return new Integer(); } public function __toString(): string { return (string) $this->value; } } valueType instanceof Mixed_) { return 'list'; } return 'list<' . $this->valueType . '>'; } } valueType instanceof Mixed_) { return 'non-empty-list'; } return 'non-empty-list<' . $this->valueType . '>'; } } 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); } } List of recognized keywords and unto which Value Object they map * @psalm-var array> */ private array $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, '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 */ private FqsenResolver $fqsenResolver; /** @psalm-readonly */ private TypeParser $typeParser; /** @psalm-readonly */ private Lexer $lexer; /** * Initializes this TypeResolver with the means to create and resolve Fqsen objects. */ public function __construct(?FqsenResolver $fqsenResolver = null) { $this->fqsenResolver = $fqsenResolver ?: new FqsenResolver(); $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: return new ArrayShape( ...array_map( fn (ArrayShapeItemNode $item) => new ArrayShapeItem( (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 = $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 = $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 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( fn (TypeNode $genericType) => $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( fn (TypeNode $genericType) => $this->createType($genericType, $context), $type->genericTypes ) ) ); } } private function createFromCallable(CallableTypeNode $type, Context $context): Callable_ { return new Callable_( array_map( function (CallableTypeParameterNode $param) use ($context) { 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 $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( fn (TypeNode $node) => $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; } } 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 . '[]'; } } */ abstract class AggregatedType implements Type, IteratorAggregate { /** * @psalm-allow-private-mutation * @var array */ private array $types = []; private string $token; /** * @param array $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 */ 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; } } 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; } } 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'; } } 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 . '>'; } } ` * 2. `ACollectionObject` * * - 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 { private ?Fqsen $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 . '>'; } } $types */ public function __construct(array $types) { parent::__construct($types, '|'); } } Fully Qualified Namespace. * @psalm-var array */ private array $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 $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 */ public function getNamespaceAliases(): array { return $this->namespaceAliases; } } $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 $class */ $class = $constant->getDeclaringClass(); return $this->createFromReflectionClass($class); } /** * @phpstan-param ReflectionClass $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 $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 $tokens * * @return string[] * @psalm-return array */ 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 $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 $tokens * * @return string[] * @psalm-return array * * @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; } } 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 . ')'; } } 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 . '>'; } } $types */ public function __construct(array $types) { parent::__construct($types, '&'); } } keyType) { return 'iterable<' . $this->keyType . ',' . $this->valueType . '>'; } if ($this->valueType instanceof Mixed_) { return 'iterable'; } return 'iterable<' . $this->valueType . '>'; } } 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(); } } 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'; } } 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; } } items = $items; } public function __toString(): string { return '[' . implode(', ', $this->items) . ']'; } } value = $value; } public function __toString(): string { return $this->value; } } value = $value; } public function __toString(): string { return $this->value; } } value = $value; } public function __toString(): string { return $this->value; } } className = $className; $this->name = $name; } public function __toString(): string { if ($this->className === '') { return $this->name; } return "{$this->className}::{$this->name}"; } } 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)); } } 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 | (? */ private $attributes = []; /** * @param mixed $value */ public function setAttribute(string $key, $value): void { $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; } } Visitors */ private $visitors = []; /** @var bool Whether traversal should be stopped */ private $stopTraversal; /** * @param list $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))); } } } setAttribute(Attribute::ORIGINAL_NODE, $originalNode); return $node; } } $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; } 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}"); } } 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}"); } } 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}"); } } description = $description; } public function __toString(): string { return trim($this->description); } } */ public $arguments; /** * @param list $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 . ')'; } } key = $key; $this->value = $value; } public function __toString(): string { if ($this->key === null) { return (string) $this->value; } return $this->key . '=' . $this->value; } } */ public $items; /** * @param list $items */ public function __construct(array $items) { $this->items = $items; } public function __toString(): string { $items = implode(', ', $this->items); return '{' . $items . '}'; } } key = $key; $this->value = $value; } public function __toString(): string { if ($this->key === null) { return (string) $this->value; } return $this->key . '=' . $this->value; } } annotation = $annotation; $this->description = $description; } public function __toString(): string { return trim("{$this->annotation} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } value = $value; } public function __toString(): string { return $this->value; } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } 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; } } 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}"; } } 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}"; } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->parameterName = $parameterName; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->parameterName} {$this->description}"); } } 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}"); } } children = $children; } /** * @return PhpDocTagNode[] */ public function getTags(): array { return array_filter($this->children, static function (PhpDocChildNode $child): bool { return $child instanceof PhpDocTagNode; }); } /** * @return PhpDocTagNode[] */ public function getTagsByName(string $tagName): array { return array_filter($this->getTags(), static function (PhpDocTagNode $tag) use ($tagName): bool { return $tag->name === $tagName; }); } /** * @return VarTagValueNode[] */ public function getVarTagValues(string $tagName = '@var'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof VarTagValueNode; } ); } /** * @return ParamTagValueNode[] */ public function getParamTagValues(string $tagName = '@param'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof ParamTagValueNode; } ); } /** * @return TypelessParamTagValueNode[] */ public function getTypelessParamTagValues(string $tagName = '@param'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof TypelessParamTagValueNode; } ); } /** * @return TemplateTagValueNode[] */ public function getTemplateTagValues(string $tagName = '@template'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof TemplateTagValueNode; } ); } /** * @return ExtendsTagValueNode[] */ public function getExtendsTagValues(string $tagName = '@extends'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof ExtendsTagValueNode; } ); } /** * @return ImplementsTagValueNode[] */ public function getImplementsTagValues(string $tagName = '@implements'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof ImplementsTagValueNode; } ); } /** * @return UsesTagValueNode[] */ public function getUsesTagValues(string $tagName = '@use'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof UsesTagValueNode; } ); } /** * @return ReturnTagValueNode[] */ public function getReturnTagValues(string $tagName = '@return'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof ReturnTagValueNode; } ); } /** * @return ThrowsTagValueNode[] */ public function getThrowsTagValues(string $tagName = '@throws'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof ThrowsTagValueNode; } ); } /** * @return MixinTagValueNode[] */ public function getMixinTagValues(string $tagName = '@mixin'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof MixinTagValueNode; } ); } /** * @return RequireExtendsTagValueNode[] */ public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof RequireExtendsTagValueNode; } ); } /** * @return RequireImplementsTagValueNode[] */ public function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof RequireImplementsTagValueNode; } ); } /** * @return DeprecatedTagValueNode[] */ public function getDeprecatedTagValues(): array { return array_filter( array_column($this->getTagsByName('@deprecated'), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof DeprecatedTagValueNode; } ); } /** * @return PropertyTagValueNode[] */ public function getPropertyTagValues(string $tagName = '@property'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof PropertyTagValueNode; } ); } /** * @return PropertyTagValueNode[] */ public function getPropertyReadTagValues(string $tagName = '@property-read'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof PropertyTagValueNode; } ); } /** * @return PropertyTagValueNode[] */ public function getPropertyWriteTagValues(string $tagName = '@property-write'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof PropertyTagValueNode; } ); } /** * @return MethodTagValueNode[] */ public function getMethodTagValues(string $tagName = '@method'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof MethodTagValueNode; } ); } /** * @return TypeAliasTagValueNode[] */ public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof TypeAliasTagValueNode; } ); } /** * @return TypeAliasImportTagValueNode[] */ public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof TypeAliasImportTagValueNode; } ); } /** * @return AssertTagValueNode[] */ public function getAssertTagValues(string $tagName = '@phpstan-assert'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof AssertTagValueNode; } ); } /** * @return AssertTagPropertyValueNode[] */ public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof AssertTagPropertyValueNode; } ); } /** * @return AssertTagMethodValueNode[] */ public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof AssertTagMethodValueNode; } ); } /** * @return SelfOutTagValueNode[] */ public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $value instanceof SelfOutTagValueNode; } ); } /** * @return ParamOutTagValueNode[] */ public function getParamOutTypeTagValues(string $tagName = '@param-out'): array { return array_filter( array_column($this->getTagsByName($tagName), 'value'), static function (PhpDocTagValueNode $value): bool { return $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 */"; } } name = $name; $this->value = $value; } public function __toString(): string { if ($this->value instanceof DoctrineTagValueNode) { return (string) $this->value; } return trim("{$this->name} {$this->value}"); } } text = $text; } public function __toString(): string { return $this->text; } } type = $type; $this->propertyName = $propertyName; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->propertyName} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim($this->type . ' ' . $this->description); } } name = $name; $this->bound = $bound; $this->default = $default; $this->description = $description; } public function __toString(): string { $bound = $this->bound !== null ? " of {$this->bound}" : ''; $default = $this->default !== null ? " = {$this->default}" : ''; return trim("{$this->name}{$bound}{$default} {$this->description}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } 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}" : '') ); } } alias = $alias; $this->type = $type; } public function __toString(): string { return trim("{$this->alias} {$this->type}"); } } 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}"); } } type = $type; $this->description = $description; } public function __toString(): string { return trim("{$this->type} {$this->description}"); } } type = $type; $this->variableName = $variableName; $this->description = $description; } public function __toString(): string { return trim("$this->type " . trim("{$this->variableName} {$this->description}")); } } 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; } } items = $items; $this->sealed = $sealed; $this->kind = $kind; } public function __toString(): string { $items = $this->items; if (! $this->sealed) { $items[] = '...'; } return $this->kind . '{' . implode(', ', $items) . '}'; } } 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 . '[]'; } } identifier = $identifier; $this->parameters = $parameters; $this->returnType = $returnType; } public function __toString(): string { $returnType = $this->returnType; if ($returnType instanceof self) { $returnType = "({$returnType})"; } $parameters = implode(', ', $this->parameters); return "{$this->identifier}({$parameters}): {$returnType}"; } } 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; } } 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 ); } } 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 ); } } constExpr = $constExpr; } public function __toString(): string { return $this->constExpr->__toString(); } } 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) . '>'; } } name = $name; } public function __toString(): string { return $this->name; } } 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)) . ')'; } } 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*'; } } type = $type; } public function __toString(): string { return '?' . $this->type; } } 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; } } items = $items; } public function __toString(): string { $items = $this->items; return 'object{' . implode(', ', $items) . '}'; } } type = $type; $this->offset = $offset; } public function __toString(): string { if ( $this->type instanceof CallableTypeNode || $this->type instanceof ConstTypeNode || $this->type instanceof NullableTypeNode ) { return '(' . $this->type . ')[' . $this->offset . ']'; } return $this->type . '[' . $this->offset . ']'; } } 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)) . ')'; } } '\'&\'', 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_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; /** @var bool */ private $parseDoctrineAnnotations; /** @var string|null */ private $regexp; public function __construct(bool $parseDoctrineAnnotations = false) { $this->parseDoctrineAnnotations = $parseDoctrineAnnotations; } /** * @return list */ 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_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_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_WILDCARD => '\\*', ]; if ($this->parseDoctrineAnnotations) { $patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*'; $patterns[self::TOKEN_DOCTRINE_ANNOTATION_STRING] = '"(?:""|[^"])*+"'; } // anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL $patterns[self::TOKEN_OTHER] = '(?:(?!\\*/)[^\\s])++'; foreach ($patterns as $type => &$pattern) { $pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')'; } return '~' . implode('|', $patterns) . '~Asi'; } } unescapeStrings = $unescapeStrings; $this->quoteAwareConstExprString = $quoteAwareConstExprString; $this->useLinesAttributes = $usedAttributes['lines'] ?? false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; $this->parseDoctrineStrings = false; } /** * @internal */ public function toDoctrine(): self { $self = new self( $this->unescapeStrings, $this->quoteAwareConstExprString, [ 'lines' => $this->useLinesAttributes, 'indexes' => $this->useIndexAttributes, ] ); $self->parseDoctrineStrings = true; return $self; } public function parse(TokenIterator $tokens, bool $trimStrings = false): 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 = $tokens->currentTokenValue(); $type = $tokens->currentTokenType(); if ($trimStrings) { if ($this->unescapeStrings) { $value = StringUnescaper::unescapeString($value); } else { $value = substr($value, 1, -1); } } $tokens->next(); if ($this->quoteAwareConstExprString) { return $this->enrichWithAttributes( $tokens, new Ast\ConstExpr\QuoteAwareConstExprStringNode( $value, $type === Lexer::TOKEN_SINGLE_QUOTED_STRING ? Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED : Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED ), $startLine, $startIndex ); } return $this->enrichWithAttributes( $tokens, new Ast\ConstExpr\ConstExprStringNode($value), $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->useLinesAttributes) { $node->setAttribute(Ast\Attribute::START_LINE, $startLine); $node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->useIndexAttributes) { $node->setAttribute(Ast\Attribute::START_INDEX, $startIndex); $node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken()); } return $node; } } 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; } } typeParser = $typeParser; $this->constantExprParser = $constantExprParser; $this->doctrineConstantExprParser = $constantExprParser->toDoctrine(); $this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription; $this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes; $this->parseDoctrineAnnotations = $parseDoctrineAnnotations; $this->useLinesAttributes = $usedAttributes['lines'] ?? false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; $this->textBetweenTagsBelongsToDescription = $textBetweenTagsBelongsToDescription; } public function parse(TokenIterator $tokens): Ast\PhpDoc\PhpDocNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $children = []; if ($this->parseDoctrineAnnotations) { 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; } } } else { if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { $children[] = $this->parseChild($tokens); while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) { $children[] = $this->parseChild($tokens); } } } 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(); return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0); } return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode(array_values($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->useLinesAttributes) { $tag->setAttribute(Ast\Attribute::START_LINE, $startLine); $tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->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_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; if ($this->textBetweenTagsBelongsToDescription) { $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 ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { $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)) { break; } if ($this->textBetweenTagsBelongsToDescription) { 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_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END]; if ($this->textBetweenTagsBelongsToDescription) { $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 ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) { $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)) { 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 ($this->textBetweenTagsBelongsToDescription) { 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': $tagValue = $this->parseParamTagValue($tokens); break; case '@var': case '@phpstan-var': case '@psalm-var': $tagValue = $this->parseVarTagValue($tokens); break; case '@return': case '@phpstan-return': case '@psalm-return': $tagValue = $this->parseReturnTagValue($tokens); break; case '@throws': case '@phpstan-throws': $tagValue = $this->parseThrowsTagValue($tokens); break; case '@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 '@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': $tagValue = $this->parsePropertyTagValue($tokens); break; case '@method': case '@phpstan-method': case '@psalm-method': $tagValue = $this->parseMethodTagValue($tokens); break; case '@template': case '@phpstan-template': case '@psalm-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->parseTemplateTagValue($tokens, true); break; case '@extends': case '@phpstan-extends': 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': $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': $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 ($this->parseDoctrineAnnotations) { if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) { $tagValue = $this->parseDoctrineTagValue($tokens, $tag); } else { $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens)); } break; } $tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens)); break; } $tokens->dropSavePoint(); } catch (ParserException $e) { $tokens->rollback(); $tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens), $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 */ 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, true); 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 = new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($tokens->currentTokenValue())); $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, true); 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); if ($type !== null) { return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference); } return new Ast\PhpDoc\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference); } 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 parseDeprecatedTagValue(TokenIterator $tokens): Ast\PhpDoc\DeprecatedTagValueNode { $description = $this->parseOptionalDescription($tokens); 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); return new Ast\PhpDoc\PropertyTagValueNode($type, $parameterName, $description); } private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTagValueNode { $isStatic = $tokens->tryConsumeTokenValue('static'); $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); $returnTypeOrMethodName = $this->typeParser->parse($tokens); if ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) { $returnType = $returnTypeOrMethodName; $methodName = $tokens->currentTokenValue(); $tokens->next(); } elseif ($returnTypeOrMethodName instanceof Ast\Type\IdentifierTypeNode) { $returnType = $isStatic ? $this->typeParser->enrichWithAttributes($tokens, new Ast\Type\IdentifierTypeNode('static'), $startLine, $startIndex) : 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->parseTemplateTagValue($tokens, false), $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); 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 parseTemplateTagValue(TokenIterator $tokens, bool $parseDescription): Ast\PhpDoc\TemplateTagValueNode { $name = $tokens->currentTokenValue(); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) { $bound = $this->typeParser->parse($tokens); } else { $bound = null; } if ($tokens->tryConsumeTokenValue('=')) { $default = $this->typeParser->parse($tokens); } else { $default = null; } if ($parseDescription) { $description = $this->parseOptionalDescription($tokens); } else { $description = ''; } return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default); } 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); 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 psalm-type syntax $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL); if ($this->preserveTypeAliasesWithInvalidTypes) { $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); return new Ast\PhpDoc\TypeAliasTagValueNode( $alias, $this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex) ); } } $type = $this->typeParser->parse($tokens); return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type); } 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); 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); 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); 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; } private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken = false): 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 ( $this->requireWhitespaceBeforeDescription && !$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; } } '\\', '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') { 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"; } } */ private $tokens; /** @var int */ private $index; /** @var int[] */ private $savePoints = []; /** @var list */ private $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS]; /** @var string|null */ private $newline = null; /** * @param list $tokens */ public function __construct(array $tokens, int $index = 0) { $this->tokens = $tokens; $this->index = $index; $this->skipIrrelevantTokens(); } /** * @return list */ 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->index++; $this->skipIrrelevantTokens(); } /** * @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->index++; $this->skipIrrelevantTokens(); } /** @phpstan-impure */ public function tryConsumeTokenValue(string $tokenValue): bool { if ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) { return false; } $this->index++; $this->skipIrrelevantTokens(); return true; } /** @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->index++; $this->skipIrrelevantTokens(); return 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; } public function dropSavePoint(): void { array_pop($this->savePoints); } public function rollback(): void { $index = array_pop($this->savePoints); assert($index !== null); $this->index = $index; } /** * @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); } } constExprParser = $constExprParser; $this->quoteAwareConstExprString = $quoteAwareConstExprString; $this->useLinesAttributes = $usedAttributes['lines'] ?? false; $this->useIndexAttributes = $usedAttributes['indexes'] ?? false; } /** @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); if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) { $type = $this->parseUnion($tokens, $type); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) { $type = $this->parseIntersection($tokens, $type); } } return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex); } /** * @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->useLinesAttributes) { $type->setAttribute(Ast\Attribute::START_LINE, $startLine); $type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine()); } if ($this->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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); 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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $type = $this->subParse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $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; } $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); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $type); } elseif (in_array($type->name, ['array', '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(); if ($this->constExprParser === null) { throw new ParserException( $currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine ); } try { $constExpr = $this->constExprParser->parse($tokens, true); if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { throw new ParserException( $currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine ); } return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex); } 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); } 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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $types[] = $this->parseAtomic($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } 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); } 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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $types[] = $this->parseAtomic($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } 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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $ifType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_NULLABLE); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $ifType = $this->parse($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_COLON); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $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 = ''; $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); $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->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); // trailing comma case if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) { break; } $isFirst = false; [$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } $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]; } /** @phpstan-impure */ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $identifier): Ast\Type\TypeNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $parameters = []; if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { $parameters[] = $this->parseCallableParameter($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) { break; } $parameters[] = $this->parseCallableParameter($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } } $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); } /** @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, ['array', '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(); if ($this->constExprParser === null) { throw new ParserException( $currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine ); } try { $constExpr = $this->constExprParser->parse($tokens, true); if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { throw new ParserException( $currentTokenValue, $currentTokenType, $currentTokenOffset, Lexer::TOKEN_IDENTIFIER, null, $currentTokenLine ); } $type = new Ast\Type\ConstTypeNode($constExpr); if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) { $type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes( $tokens, $type, $startLine, $startIndex )); } 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): Ast\Type\TypeNode { try { $tokens->pushSavePoint(); $type = $this->parseCallable($tokens, $identifier); $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; do { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { return new Ast\Type\ArrayShapeNode($items, true, $kind); } if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) { $sealed = false; $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA); break; } $items[] = $this->parseArrayShapeItem($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET); return new Ast\Type\ArrayShapeNode($items, $sealed, $kind); } /** @phpstan-impure */ private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShapeItemNode { $startLine = $tokens->currentTokenLine(); $startIndex = $tokens->currentTokenIndex(); 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\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)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); } $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); } $tokens->next(); } else { $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } return $this->enrichWithAttributes( $tokens, $key, $startLine, $startIndex ); } /** * @phpstan-impure */ private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNode { $tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET); $items = []; do { $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) { return new Ast\Type\ObjectShapeNode($items); } $items[] = $this->parseObjectShapeItem($tokens); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)); $tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL); $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(); $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)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'")); } $tokens->next(); } elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) { if ($this->quoteAwareConstExprString) { $key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED); } else { $key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"')); } $tokens->next(); } else { $key = new Ast\Type\IdentifierTypeNode($tokens->currentTokenValue()); $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); } return $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex); } } type = $type; $this->old = $old; $this->new = $new; } } 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, 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> $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; } } */ private $differ; /** * Map From "{$class}->{$subNode}" to string that should be inserted * between elements of this list subnode * * @var array */ private $listInsertionMap = [ PhpDocNode::class . '->children' => "\n * ", UnionTypeNode::class . '->types' => '|', IntersectionTypeNode::class . '->types' => '&', ArrayShapeNode::class . '->items' => ', ', ObjectShapeNode::class . '->items' => ', ', CallableTypeNode::class . '->parameters' => ', ', GenericTypeNode::class . '->genericTypes' => ', ', ConstExprArrayNode::class . '->items' => ', ', MethodTagValueNode::class . '->parameters' => ', ', DoctrineArray::class . '->items' => ', ', DoctrineAnnotation::class . '->arguments' => ', ', ]; /** * [$find, $extraLeft, $extraRight] * * @var array */ private $emptyListInsertionMap = [ CallableTypeNode::class . '->parameters' => ['(', '', ''], ArrayShapeNode::class . '->items' => ['{', '', ''], ObjectShapeNode::class . '->items' => ['{', '', ''], DoctrineArray::class . '->items' => ['{', '', ''], DoctrineAnnotation::class . '->arguments' => ['(', '', ''], ]; /** @var array>> */ private $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, ConstTypeNode::class, NullableTypeNode::class, ], ]; /** @var array>> */ private $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 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; } 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(function (MethodTagValueParameterNode $parameter): string { return $this->print($parameter); }, $node->parameters)); $description = $node->description !== '' ? " {$node->description}" : ''; $templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateTag): string { return $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 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 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) { $bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : ''; $default = $node->default !== null ? ' = ' . $this->printType($node->default) : ''; return trim("{$node->name}{$bound}{$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(function (ArrayShapeItemNode $item): string { return $this->printType($item); }, $node->items); if (! $node->sealed) { $items[] = '...'; } return $node->kind . '{' . implode(', ', $items) . '}'; } 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 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); } $parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode): string { return $this->print($parameterNode); }, $node->parameters)); return "{$node->identifier}({$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(function (ObjectShapeItemNode $item): string { return $this->printType($item); }, $node->items); return 'object{' . implode(', ', $items) . '}'; } 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); } 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 ConstTypeNode || $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; $newNode = $diffElem->new; $originalNode = $diffElem->old; if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { $beforeFirstKeepOrReplace = false; if (!$newNode instanceof Node || !$originalNode instanceof Node) { return null; } $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); $itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX); if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) { throw new LogicException(); } $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 .= '('; } $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($newNode), $this->parenthesesListMap[$mapKey], true) && !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], true); $addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos); if ($addParentheses) { $result .= '('; } $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); if ($addParentheses) { $result .= ')'; } $tokenIndex = $itemEndPos + 1; } elseif ($diffType === DiffElem::TYPE_ADD) { if ($insertStr === null) { return null; } if (!$newNode instanceof Node) { return null; } if ($insertStr === ', ' && $isMultiline) { $insertStr = ','; $insertNewline = true; } if ($beforeFirstKeepOrReplace) { // Will be inserted at the next "replace" or "keep" element $delayedAdd[] = $newNode; continue; } $itemEndPos = $tokenIndex - 1; if ($insertNewline) { $result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent); } else { $result .= $insertStr; } $parenthesesNeeded = isset($this->parenthesesListMap[$mapKey]) && in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true); if ($parenthesesNeeded) { $result .= '('; } $result .= $this->printNodeFormatPreserving($newNode, $originalTokens); if ($parenthesesNeeded) { $result .= ')'; } $tokenIndex = $itemEndPos + 1; } elseif ($diffType === DiffElem::TYPE_REMOVE) { if (!$originalNode instanceof Node) { return null; } $itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX); $itemEndPos = $originalNode->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 Node[] $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(?[\\x09\\x20]*)\*(?\\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']; } 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); } } 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; } 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; } * [user-info@]host[:port] * * * 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; } logger = $logger; } } 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. * * @param string|\Stringable $message * @param array $context * * @return void */ public function alert(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::ALERT, $message, $context); } /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * * @param string|\Stringable $message * @param array $context * * @return void */ 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. * * @param string|\Stringable $message * @param array $context * * @return void */ 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. * * @param string|\Stringable $message * @param array $context * * @return void */ public function warning(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::WARNING, $message, $context); } /** * Normal but significant events. * * @param string|\Stringable $message * @param array $context * * @return void */ public function notice(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::NOTICE, $message, $context); } /** * Interesting events. * * Example: User logs in, SQL logs. * * @param string|\Stringable $message * @param array $context * * @return void */ public function info(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::INFO, $message, $context); } /** * Detailed debug information. * * @param string|\Stringable $message * @param array $context * * @return void */ public function debug(string|\Stringable $message, array $context = []): void { $this->log(LogLevel::DEBUG, $message, $context); } /** * Logs with an arbitrary level. * * @param mixed $level * @param string|\Stringable $message * @param array $context * * @return void * * @throws \Psr\Log\InvalidArgumentException */ abstract public function log($level, string|\Stringable $message, array $context = []): void; } logger) { }` * blocks. */ class NullLogger extends AbstractLogger { /** * Logs with an arbitrary level. * * @param mixed $level * @param string|\Stringable $message * @param array $context * * @return void * * @throws \Psr\Log\InvalidArgumentException */ public function log($level, string|\Stringable $message, array $context = []): void { // noop } } '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; } } * * 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 */ 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); } } $this->configureIO($input, $output); try { $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 %s', $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('%s', 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('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { $messages[] = sprintf(' %s %s', 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('Exception trace:', 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 %s:%s', $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 '.$this->defaultCommand.' 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 (mb_strwidth($line.$char, 'utf8') <= $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); } } } * * 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); } } * * 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 */ 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)); } } * * 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 */ 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))))); } } * * 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 */ 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('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', 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('Install the proctitle PECL to be able to change the process title.'); } } 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 $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 $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 $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)); } } } * * 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 */ #[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> $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([ '', ''.date('Y-m-d H:i:s').'', 'Input: ("|" indicates the cursor position)', ' '.(string) $completionInput, 'Command:', ' '.(string) implode(' ', $_SERVER['argv']), '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") 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 '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' command.'); $suggestions->suggestOptions($command->getDefinition()->getOptions()); } else { $this->log([ ' Completing using the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' class.', ' Completing '.$completionInput->getCompletionType().' for '.$completionInput->getCompletionName().'', ]); if (null !== $compval = $completionInput->getCompletionValue()) { $this->log(' Current value: '.$compval.''); } $command->complete($completionInput, $suggestions); } } /** @var CompletionOutputInterface $completionOutput */ $completionOutput = new $completionOutput(); $this->log('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(' No suggestions were provided'); } $completionOutput->write($suggestions, $output); } catch (\Throwable $e) { $this->log([ '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); } } * * 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 */ #[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(<<%command.name% command dumps the shell completion script required to use shell autocompletion (currently, {$supportedShells} completion are supported). Static installation ------------------- Dump the script to a global completion file and restart your shell: %command.full_name% {$shell} | sudo tee {$completionFile} Or dump the script to a local file and source it: %command.full_name% {$shell} > completion.sh # source the file whenever you use the project source completion.sh # or add this line at the end of your "{$rcFile}" file: source /path/to/completion.sh Dynamic installation -------------------- Add this to the end of your shell configuration file (e.g. "{$rcFile}"): 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('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); } else { $output->writeln(sprintf('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; } } * * 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 */ 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 %command.name% command displays help for a given command: %command.full_name% list You can also output the help in other formats by using the --format option: %command.full_name% --format=xml list To display the list of available commands, please use the list 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; } } * * 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 */ 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 $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 $suggestedValues The values used for input completion */ public function addOption(string $name, string|array $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; } } * * 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 */ 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 %command.name% command lists all commands: %command.full_name% You can also display the commands for a specific namespace: %command.full_name% test You can also output the information in other formats by using the --format option: %command.full_name% --format=xml It's also possible to get raw list of commands (useful for embedding command runner): %command.full_name% --raw 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; } } * * 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 */ 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; } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; /** * Interface for command reacting to signal. * * @author Grégoire Pineau */ interface SignalableCommandInterface { /** * Returns the list of signals to subscribe. */ public function getSubscribedSignals(): array; /** * The method will be called when the application is signaled. * * @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 */); } * * 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 */ 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 */ public array $arguments; /** @var array */ public array $options; /** @var array */ 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 $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 = parent::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; } } } * * 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 */ 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; } * * 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 */ 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); } } * * 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 */ 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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; /** * An input specialized for shell completion. * * This input allows unfinished option names or values and exposes what kind of * completion is expected. * * @author Wouter de Jong */ final class CompletionInput extends ArgvInput { public const TYPE_ARGUMENT_VALUE = 'argument_value'; public const TYPE_OPTION_VALUE = 'option_value'; public const TYPE_OPTION_NAME = 'option_name'; public const TYPE_NONE = 'none'; private 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)([\'"]?)(.+?)(?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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion; use Symfony\Component\Console\Input\InputOption; /** * Stores all completion suggestions for the current input. * * @author Wouter de Jong */ final class CompletionSuggestions { private 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 $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; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion\Output; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; /** * @author Wouter de Jong */ class BashCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void { $values = $suggestions->getValueSuggestions(); foreach ($suggestions->getOptionSuggestions() as $option) { $values[] = '--'.$option->getName(); if ($option->isNegatable()) { $values[] = '--no-'.$option->getName(); } } $output->writeln(implode("\n", $values)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion\Output; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; /** * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion. * * @author Wouter de Jong */ interface CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void; } * * 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 */ 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)); } } * * 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 */ 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"); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion; /** * Represents a single suggested value. * * @author Wouter de Jong */ class Suggestion 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(); } } * * 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 */ 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, ]; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Output\OutputInterface; /** * @author Pierre du Plessis */ final class Cursor { private 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]; } } * * 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 */ 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 = []; } } * * 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(); } } * * 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 */ 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); } } * * 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 * * @internal */ class ApplicationDescription { public const GLOBAL_NAMESPACE = '_global'; private Application $application; private ?string $namespace; private bool $showHidden; private array $namespaces; /** * @var array */ private array $commands; /** * @var array */ 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; } } * * 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 * * @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; } * * 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 */ interface DescriptorInterface { /** * @return void */ public function describe(OutputInterface $output, object $object, array $options = []); } * * 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 * * @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' => false, ] : [ '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; } } * * 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 * * @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() ?: '')."`\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'; } } * * 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 { //

private string $partChar = '='; //

private string $chapterChar = '-'; //

private string $sectionChar = '~'; //

private string $subsectionChar = '.'; //

private string $subsubsectionChar = '^'; //
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() ?: ''."\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; } } * * 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 * * @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(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); $this->writeText(sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after 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(' [default: %s]', $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(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()), $default, $option->isArray() ? ' (multiple values allowed)' : '' ), $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('Arguments:', $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('Options:', $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('Description:', $options); $this->writeText("\n"); $this->writeText(' '.$description); $this->writeText("\n\n"); } $this->writeText('Usage:', $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('Help:', $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("Usage:\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('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $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(' '.$namespace['id'].'', $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(' %s%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 $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; } } * * 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 * * @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; } } * * 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 */ 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; } } * * 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 */ 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); } } * * 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 */ 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; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Event; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * @author marie */ final class ConsoleSignalEvent extends ConsoleEvent { private 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; } } * * 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 * @author Jules Pietri */ 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; } } * * 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 * @author Robin Chalas */ 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; } } * * 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 */ 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; } } * * 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 */ interface ExceptionInterface extends \Throwable { } * * 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 */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } * * 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 */ class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface { } * * 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 */ class LogicException extends \LogicException implements ExceptionInterface { } * * 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ý */ class MissingInputException extends RuntimeException implements ExceptionInterface { } * * 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 */ class NamespaceNotFoundException extends CommandNotFoundException { } * * 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 */ 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, ); } } * * 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 */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * @author Tien Xuan Vo */ final class NullOutputFormatter implements OutputFormatterInterface { private 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 } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * @author Tien Xuan Vo */ final class NullOutputFormatterStyle implements OutputFormatterStyleInterface { 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 } } * * 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 function Symfony\Component\String\b; /** * Formatter class for console output. * * @author Konstantin Kudryashov * @author Roland Franssen */ 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; } // add the text up to the next tag $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); $offset = $pos + \strlen($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(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) { $prefix = substr($text, 0, $i = $width - $currentLineLength)."\n"; $text = substr($text, $i); } 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 $line) { $currentLineLength += \strlen($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)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); } } * * 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 */ 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; } * * 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 */ 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); } } * * 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 */ 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; } * * 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 */ 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; } } * * 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 */ 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); } * * 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 */ 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 %s %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 %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = true; } $message .= str_replace("\n", sprintf("\n%s %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 %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = true; } $message .= str_replace("\n", sprintf("\n%s %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 %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } $message = sprintf("%s%s %s %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(' ', self::COLORS[$this->started[$id]['border']]); } public function getName(): string { return 'debug_formatter'; } } * * 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 */ 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); } } * * 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 */ 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); } } * * 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 */ 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', $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', $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'; } } * * 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 */ 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)) { return (new UnicodeString($string))->width(false); } 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 (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; } } * * 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 */ 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(); } * * 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 * * @implements \IteratorAggregate */ class HelperSet implements \IteratorAggregate { /** @var array */ 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); } } * * 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 */ abstract class InputAwareHelper extends Helper implements InputAwareInterface { protected $input; /** * @return void */ public function setInput(InputInterface $input) { $this->input = $input; } } * * 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 * * @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); } } * * 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 * * @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('%s', $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'; } } * * 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 * @author Chris Jones */ 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]; } 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 (!$this->step) { 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 $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 */ 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); 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); } } * * 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 */ 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 */ 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 */ 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)), ]; } } * * 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 */ 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] %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->getMessage().''; } $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 (\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(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).''); $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; } if (\function_exists('stream_isatty')) { return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); } if (\function_exists('posix_isatty')) { return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); } if (!\function_exists('shell_exec')) { return self::$stdinIsInteractive = true; } return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } /** * 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 (\PHP_EOL === "{$ret}{$char}") { break; } $ret .= $char; } 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; } } * * 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 */ 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(' %s:', $text); break; case $question instanceof ConfirmationQuestion: $text = sprintf(' %s (yes/no) [%s]:', $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(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: $text = sprintf(' %s [%s]:', $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 'Ctrl+Z then Enter'; } return 'Ctrl+D'; } } * * 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 * @author Саша Стаменковић * @author Abdellatif Ait boudad * @author Max Grigorian * @author Dany Maillard */ 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] ?? ''); $parts = explode("\n", $cell); foreach ($parts as $idx => $part) { if ($headers && !$containsColspan) { if (0 === $idx) { $rows[] = [sprintf( '%s: %s', str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), $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 if (false !== $encoding = mb_detect_encoding($cell, null, true)) { $width += \strlen($cell) - mb_strwidth($cell, $encoding); } $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, '')) { $content = str_replace('', '', $content); $width -= \strlen(''); } } $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; if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); } if (!str_contains($cell ?? '', "\n")) { continue; } $escaped = implode("\n", array_map(OutputFormatter::escapeTrailingBackslash(...), explode("\n", $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; $lines = explode("\n", str_replace("\n", "\n", $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")) { $lines = explode("\n", str_replace("\n", "\n", $cell)); $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), '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 */ 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)); } } * * 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 */ 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']; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Yewhen Khoptynskyi */ class TableCellStyle { public const DEFAULT_ALIGN = 'left'; private const TAG_OPTIONS = [ 'fg', 'bg', 'options', ]; private const ALIGN_MAP = [ 'left' => \STR_PAD_RIGHT, 'center' => \STR_PAD_BOTH, 'right' => \STR_PAD_LEFT, ]; private 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']; } } * * 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)(); } } * * 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 */ class TableSeparator extends TableCell { public function __construct(array $options = []) { parent::__construct('', $options); } } * * 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 * @author Саша Стаменковић * @author Dany Maillard */ 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 = ' %s '; private string $footerTitleFormat = ' %s '; private string $cellHeaderFormat = '%s'; 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. * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ * 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 ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ * * * @return $this */ public function setHorizontalBorderChars(string $outside, string $inside = null): static { $this->horizontalOutsideBorderChar = $outside; $this->horizontalInsideBorderChar = $inside ?? $outside; return $this; } /** * Sets vertical border characters. * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ * ║ 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 ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ * * * @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: * * 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 * * * @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; } } * * 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 * * @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); } } * * 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 */ 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; } } * * 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 */ 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; } } * * 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 */ 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|null|float $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 $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 $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 $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; } } * * 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 */ interface InputAwareInterface { /** * Sets the Console Input. * * @return void */ public function setInput(InputInterface $input); } * * 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 */ 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 */ 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 */ 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; } } * * 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 * * @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 */ 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 */ 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); } * * 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 */ 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|null|float $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 $suggestedValues The values used for input completion * * @throws InvalidArgumentException If option mode is invalid or incompatible */ public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $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 (empty($shortcut)) { $shortcut = null; } if (null !== $shortcut) { if (\is_array($shortcut)) { $shortcut = implode('|', $shortcut); } $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-')); $shortcuts = array_filter($shortcuts); $shortcut = implode('|', $shortcuts); if (empty($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 $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() ; } } * * 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 */ 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(); } * * 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 */ class StringInput extends ArgvInput { /** * @deprecated since Symfony 6.1 */ public const REGEX_STRING = '([^\s]+?)(?:\s|(?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; } } * * 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 * * @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', $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); } } * * 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 */ final class RunCommandContext { public function __construct( public readonly RunCommandMessage $message, public readonly int $exitCode, public readonly string $output, ) { } } * * 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 */ 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; } } * * 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; /** * @author Kevin Bond */ 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 (\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()); } } * * 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 * @author Julien Boudry */ 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); } } } * * 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 */ 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; } } } * * 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 */ 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')); } } * * 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 */ interface ConsoleOutputInterface extends OutputInterface { /** * Gets the OutputInterface for errors. */ public function getErrorOutput(): OutputInterface; /** * @return void */ public function setErrorOutput(OutputInterface $error); public function section(): ConsoleSectionOutput; } * * 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 * @author Gabriel Ostrolucký */ 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))); } } * * 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 * @author Tobias Schultze */ 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 } } * * 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 */ 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); } * * 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 */ 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; } * * 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 */ 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 (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { return false; } if (\DIRECTORY_SEPARATOR === '\\' && \function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support($this->stream) ) { return true; } return 'Hyper' === getenv('TERM_PROGRAM') || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || str_starts_with((string) getenv('TERM'), 'xterm') || stream_isatty($this->stream); } } * * 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é */ 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); } } * * 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 */ 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 $choices The list of available choices * @param mixed $default The default answer to return */ public function __construct(string $question, array $choices, mixed $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); } /** * Returns available choices. */ 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); }; } } * * 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 */ 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; }; } } * * 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 */ 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|null|float $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 $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ў?Ba98B;CB2Ȟ:B2֞:B2Ӟ:BRich;BPELMoO  8 @`?@"P@ Pp!8!@ .text   `.rdata @@.data0@.rsrc @@@.relocP"@Bj$@xj @eEPV @EЃPV @MX @eEP5H @L @YY5\ @EP5` @D @YYP @MMT @3H; 0@uh@l3@$40@5h3@40@h$0@h(0@h 0@ @00@}jYjh"@3ۉ]dp]俀3@SVW0 @;t;u3Fuh4 @3F|3@;u j\Y;|3@u,5|3@h @h @YYtE5<0@|3@;uh @h @lYY|3@9]uSW8 @93@th3@Yt SjS3@$0@ @5$0@5(0@5 0@ 80@9,0@u7P @E MPQYYËeE80@39,0@uPh @9<0@u @E80@øMZf9@t3M<@@8PEuH t uՃv39xtv39j,0@p @jl @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@f01@f,1@f%(1@f-$1@X1@EL1@EP1@E\1@0@P1@L0@@0@ D0@0@0@ @0@j?Yj @h!@$ @=0@ujYh ( @P, @ËUE8csmu*xu$@= t=!t="t=@u3]hH@ @3% @jh("@b53@5 @YEu u @YgjYe53@։E53@YYEEPEPu5l @YPUEu֣3@uփ3@E EjYËUuNYH]ËV!@!@W;stЃ;r_^ËV"@"@W;stЃ;r_^% @̋UMMZf9t3]ËA<8PEu3ҹ f9H‹]̋UEH<ASVq3WDv} H ;r X;r B(;r3_^[]̋UjhH"@he@dPSVW0@1E3PEdeEh@*tUE-@Ph@Pt;@$ЃEMd Y_^[]ËE3=‹ËeE3Md Y_^[]% @% @he@d5D$l$l$+SVW0@1E3PeuEEEEdËMd Y__^[]QËUuuu uh@h0@]ËVhh3V t VVVVV^3ËU0@eeSWN@;t t У0@`VEP< @u3u @3 @3 @3EP @E3E3;uO@ u 50@։50@^_[%t @%x @%| @% @% @% @% @% @% @Pd5D$ +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@@MoOl!@0@0@bad allocationH0@!@RSDSьJ!LZc:\users\seld\documents\visual studio 2010\Projects\hiddeninp\Release\hiddeninp.pdbe@@:@@@@"d"@"# $#&D H#(h ###)r)b)H)4))(((((()#$%%&d&&$('''''(((6('H(Z(t(('''''l'^'R'F'>'>(0'')GetConsoleModeSetConsoleMode;GetStdHandleKERNEL32.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@AJ?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@@ZMSVCP90.dll_amsg_exit__getmainargs,_cexit|_exitf_XcptFilterexit__initenv_initterm_initterm_e<_configthreadlocale__setusermatherr _adjust_fdiv__p__commode__p__fmodej_encode_pointer__set_app_typeK_crt_debugger_hookC?terminate@@YAXXZMSVCR90.dll_unlock__dllonexitv_lock_onexit`_decode_pointers_except_handler4_common _invoke_watson?_controlfp_sInterlockedExchange!SleepInterlockedCompareExchange-TerminateProcessGetCurrentProcess>UnhandledExceptionFilterSetUnhandledExceptionFilterIsDebuggerPresentTQueryPerformanceCounterfGetTickCountGetCurrentThreadIdGetCurrentProcessIdOGetSystemTimeAsFileTimes__CxxFrameHandler3N@D$!@ 8Ph  @(CV(4VS_VERSION_INFOStringFileInfob040904b0QFileDescriptionReads from stdin without leaking info to the terminal and outputs back to stdout6 FileVersion1, 0, 0, 08 InternalNamehiddeninputPLegalCopyrightJordi Boggiano - 2012HOriginalFilenamehiddeninput.exe: ProductNameHidden Input: ProductVersion1, 0, 0, 0DVarFileInfo$Translation  PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING@00!0/080F0L0T0^0d0n0{000000000000001#1-1@1J1O1T1v1{1111111111111112"2*23292A2M2_2j2p222222222222 333%303N3T3Z3`3f3l3s3z333333333333333334444%4;4B444444444445!5^5c5555H6M6_6}66677 7*7w7|777778 88=8E8P8V8\8b8h8n8t8z88889 $0001 1t1x12 2@2\2`2h2t20 0 * * 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 */ 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_'), \ARRAY_FILTER_USE_KEY); self::$map = array_flip($map); } return self::$map[$signal] ?? null; } } * * 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); } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * @author Grégoire Pineau */ class SingleCommandApplication extends Command { private 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; } } * * 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 */ 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(); } } * * 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 */ 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(); } * * 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 */ 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('%s', OutputFormatter::escapeTrailingBackslash($message)), sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } /** * @return void */ public function section(string $message) { $this->autoPrependBlock(); $this->writeln([ sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), sprintf('%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, ' // ', 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 $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 */ 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('%s'); 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; } } * * 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; $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]); if (!\is_resource($process)) { 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; } } * * 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 */ 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; } } } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Tester; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; /** * Eases the testing of command completion. * * @author Jérôme Tamarelle */ class CommandCompletionTester { private Command $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())); } } * * 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 * @author Robin Chalas */ 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); } } * * 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); } } * * 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 */ 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.\PHP_EOL); } rewind($stream); return $stream; } } * * 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 */ 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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\Attribute; /** * Service tag to autoconfigure event listeners. * * @author Alexander M. Turek */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class AsEventListener { public function __construct( public ?string $event = null, public ?string $method = null, public int $priority = 0, public ?string $dispatcher = null, ) { } } * * 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 */ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface { protected $logger; protected $stopwatch; /** * @var \SplObjectStorage|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->attach($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 { $this->callStack->detach($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; } } * * 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 */ 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]]; } } * * 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 */ 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) ); } } * * 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; } } * * 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 * @author Jonathan Wage * @author Roman Borschel * @author Bernhard Schussek * @author Fabien Potencier * @author Jordi Boggiano * @author Jordan Alliot * @author Nicolas Grekas */ 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]; } } * * 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 */ 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 */ 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; } * * 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 * @author Jonathan Wage * @author Roman Borschel * @author Bernhard Schussek */ 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> */ public static function getSubscribedEvents(); } * * 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 * * @implements \ArrayAccess * @implements \IteratorAggregate */ 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 */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->arguments); } } * * 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 */ 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); } } * * 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 * @author Jonathan Wage * @author Roman Borschel * @author Bernhard Schussek * @author Nicolas Grekas */ 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; } } * * 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; } * * 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 */ interface ExceptionInterface extends \Throwable { } * * 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 * @author Christian Gärtner */ 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); } } * * 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 */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } * * 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 * @author Christian Gärtner * @author Fabien Potencier */ 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; } } * * 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 */ interface IOExceptionInterface extends ExceptionInterface { /** * Returns the associated path for the exception. */ public function getPath(): ?string; } * * 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 */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } * * 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 */ 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 && null === 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)); 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) && (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. * * @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. * * @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, file_exists($filename) ? fileperms($filename) : 0666 & ~umask()); $this->rename($tmpFile, $filename, true); } finally { if (file_exists($tmpFile)) { 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; } } * * 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 * @author Thomas Schulz * @author Théo Fidry */ 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 */ 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, '://')) { $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() { } } * * 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 * * @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(); } * * 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 * * @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); } * * 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 * * @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(); } * * 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 * * @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('{}') ; } } } * * 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 * * @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('{}') ; } } } * * 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 * * @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; } } * * 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 */ 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; } } * * 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 */ 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); } } * * 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 PHP port * @author Richard Clamp Perl version * @copyright 2004-2005 Fabien Potencier * @copyright 2002 Richard Clamp * * @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] : '=='); } } * * 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 */ class AccessDeniedException extends \UnexpectedValueException { } * * 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 * * @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; } } * * 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 */ interface ExceptionInterface { /** * @return \Symfony\Component\Finder\Adapter\AdapterInterface */ public function getAdapter(); } * * 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 * * @deprecated since 2.8, to be removed in 3.0. */ class OperationNotPermitedException extends AdapterFailureException { } * * 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 * * @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; } } * * 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 */ 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(); } } * * 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 */ 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); } } * * 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 */ 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; } } * * 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 */ 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); } * * 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 */ 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); } } * * 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 PHP port * @author Richard Clamp Perl version * @copyright 2004-2005 Fabien Potencier * @copyright 2002 Richard Clamp */ 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; } } * * 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 */ 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; } } * * 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 */ 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; } } * * 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 */ 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; } } * * 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 */ 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; } } * * 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 * @author Włodzimierz Gajda */ 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, '/').'/'; } } * * 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 */ 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); } } * * 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 * * @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); } } * * 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 */ 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; } } * * 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(); } } * * 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 */ 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); } * * 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 * @author Włodzimierz Gajda */ 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, '/').'/'; } } * * 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 */ 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; } } * * 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 */ 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; } } * * 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 */ 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); } } * * 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 * * @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; } } * * 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 * * @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; } } * * 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 */ 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; } } * * 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); } } * * 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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Ctype; /** * Ctype implementation through regex. * * @internal * * @author Gert de Pagter */ final class Ctype { /** * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. * * @see https://php.net/ctype-alnum * * @param mixed $text * * @return bool */ public static function ctype_alnum($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); } /** * Returns TRUE if every character in text is a letter, FALSE otherwise. * * @see https://php.net/ctype-alpha * * @param mixed $text * * @return bool */ public static function ctype_alpha($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); } /** * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. * * @see https://php.net/ctype-cntrl * * @param mixed $text * * @return bool */ public static function ctype_cntrl($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); } /** * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. * * @see https://php.net/ctype-digit * * @param mixed $text * * @return bool */ public static function ctype_digit($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); } /** * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. * * @see https://php.net/ctype-graph * * @param mixed $text * * @return bool */ public static function ctype_graph($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); } /** * Returns TRUE if every character in text is a lowercase letter. * * @see https://php.net/ctype-lower * * @param mixed $text * * @return bool */ public static function ctype_lower($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); } /** * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. * * @see https://php.net/ctype-print * * @param mixed $text * * @return bool */ public static function ctype_print($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); } /** * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. * * @see https://php.net/ctype-punct * * @param mixed $text * * @return bool */ public static function ctype_punct($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); } /** * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. * * @see https://php.net/ctype-space * * @param mixed $text * * @return bool */ public static function ctype_space($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); } /** * Returns TRUE if every character in text is an uppercase letter. * * @see https://php.net/ctype-upper * * @param mixed $text * * @return bool */ public static function ctype_upper($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); } /** * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. * * @see https://php.net/ctype-xdigit * * @param mixed $text * * @return bool */ public static function ctype_xdigit($text) { $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); } /** * Converts integers to their char versions according to normal ctype behaviour, if needed. * * If an integer between -128 and 255 inclusive is provided, * it is interpreted as the ASCII value of a single character * (negative values have 256 added in order to allow characters in the Extended ASCII range). * Any other integer is interpreted as a string containing the decimal digits of the integer. * * @param mixed $int * @param string $function * * @return mixed */ private static function convert_int_to_char_for_ctype($int, $function) { if (!\is_int($int)) { return $int; } if ($int < -128 || $int > 255) { return (string) $int; } if (\PHP_VERSION_ID >= 80100) { @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED); } if ($int < 0) { $int += 256; } return \chr($int); } } * * 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')) { if (extension_loaded('xml')) { function iconv_strlen($string, $encoding = null) { return p\Iconv::strlen1($string, $encoding); } } else { function iconv_strlen($string, $encoding = null) { return p\Iconv::strlen2($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); } } } * * 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')) { if (extension_loaded('xml')) { function iconv_strlen(?string $string, ?string $encoding = null): int|false { return p\Iconv::strlen1((string) $string, $encoding); } } else { function iconv_strlen(?string $string, ?string $encoding = null): int|false { return p\Iconv::strlen2((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); } } } * * 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 * * @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) { static $hasXml = null; if (null === $hasXml) { $hasXml = \extension_loaded('xml'); } if ($hasXml) { return self::strlen1($s, $encoding); } return self::strlen2($s, $encoding); } public static function strlen1($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; } return \strlen(utf8_decode($s)); } public static function strlen2($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; } } ' ', 'A' => ',', 'B' => '、', 'C' => '。', 'D' => '.', 'E' => '•', 'F' => ';', 'G' => ':', 'H' => '?', 'I' => '!', 'J' => '︰', 'K' => '…', 'L' => '‥', 'M' => '﹐', 'N' => '、', 'O' => '﹒', 'P' => '·', 'Q' => '﹔', 'R' => '﹕', 'S' => '﹖', 'T' => '﹗', 'U' => '|', 'V' => '–', 'W' => '︱', 'X' => '—', 'Y' => '︳', 'Z' => '�', '[' => '︴', '\\' => '﹏', ']' => '(', '^' => ')', '_' => '︵', '`' => '︶', 'a' => '{', 'b' => '}', 'c' => '︷', 'd' => '︸', 'e' => '〔', 'f' => '〕', 'g' => '︹', 'h' => '︺', 'i' => '【', 'j' => '】', 'k' => '︻', 'l' => '︼', 'm' => '《', 'n' => '》', 'o' => '︽', 'p' => '︾', 'q' => '〈', 'r' => '〉', 's' => '︿', 't' => '﹀', 'u' => '「', 'v' => '」', 'w' => '﹁', 'x' => '﹂', 'y' => '『', 'z' => '』', '{' => '﹃', '|' => '﹄', '}' => '﹙', '~' => '﹚', '' => '﹛', '' => '﹜', '' => '﹝', '' => '﹞', '' => '‘', '' => '’', '' => '“', '' => '”', '' => '〝', '' => '〞', '' => '‵', '' => '′', '' => '#', '' => '&', '' => '*', '' => '※', '' => '§', '' => '〃', '' => '○', '' => '●', '' => '△', '' => '▲', '' => '◎', '' => '☆', '' => '★', '' => '◇', '' => '◆', '' => '□', '' => '■', '' => '▽', '' => '▼', '' => '㊣', '' => '℅', '' => '‾', '' => '�', '' => '_', '' => '�', '' => '﹉', '' => '﹊', '' => '﹍', '' => '﹎', '' => '﹋', '' => '﹌', '' => '﹟', '' => '﹠', '' => '﹡', '' => '+', '' => '-', '' => '×', '' => '÷', '' => '±', '' => '√', '' => '<', '' => '>', '' => '=', '' => '≦', '' => '≧', '' => '≠', '' => '∞', '' => '≒', '' => '≡', '' => '﹢', '' => '﹣', '' => '﹤', '' => '﹥', '' => '﹦', '' => '∼', '' => '∩', '' => '∪', '' => '⊥', '' => '∠', '' => '∟', '' => '⊿', '' => '㏒', '' => '㏑', '' => '∫', '' => '∮', '' => '∵', '' => '∴', '' => '♀', '' => '♂', '' => '♁', '' => '☉', '' => '↑', '' => '↓', '' => '←', '' => '→', '' => '↖', '' => '↗', '' => '↙', '' => '↘', '' => '∥', '' => '∣', '' => '�', '@' => '�', 'A' => '/', 'B' => '\', 'C' => '$', 'D' => '¥', 'E' => '〒', 'F' => '¢', 'G' => '£', 'H' => '%', 'I' => '@', 'J' => '℃', 'K' => '℉', 'L' => '﹩', 'M' => '﹪', 'N' => '﹫', 'O' => '㏕', 'P' => '㎜', 'Q' => '㎝', 'R' => '㎞', 'S' => '㏎', 'T' => '㎡', 'U' => '㎎', 'V' => '㎏', 'W' => '㏄', 'X' => '°', 'Y' => '兙', 'Z' => '兛', '[' => '兞', '\\' => '兝', ']' => '兡', '^' => '兣', '_' => '嗧', '`' => '瓩', 'a' => '糎', 'b' => '▁', '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', '' => 'Ⅰ', '' => 'Ⅱ', '' => 'Ⅲ', '' => 'Ⅳ', '' => 'Ⅴ', '' => 'Ⅵ', '' => 'Ⅶ', '' => 'Ⅷ', '' => 'Ⅸ', '' => 'Ⅹ', '' => '〡', '' => '〢', '' => '〣', '' => '〤', '' => '〥', '' => '〦', '' => '〧', '' => '〨', '' => '〩', '' => '�', '' => '卄', '' => '�', '' => 'A', '' => 'B', '' => 'C', '' => 'D', '' => 'E', '' => 'F', '' => 'G', '' => 'H', '' => 'I', '' => 'J', '' => 'K', '' => 'L', '' => 'M', '' => 'N', '' => 'O', '' => 'P', '' => 'Q', '' => 'R', '' => 'S', '' => 'T', '' => 'U', '' => 'V', '' => 'W', '' => 'X', '' => 'Y', '' => 'Z', '' => 'a', '' => 'b', '' => 'c', '' => 'd', '' => 'e', '' => 'f', '' => 'g', '' => 'h', '' => 'i', '' => 'j', '' => 'k', '' => 'l', '' => 'm', '' => 'n', '' => 'o', '' => 'p', '' => 'q', '' => 'r', '' => 's', '' => 't', '' => 'u', '' => 'v', '@' => 'w', 'A' => 'x', 'B' => 'y', 'C' => 'z', 'D' => 'Α', 'E' => 'Β', 'F' => 'Γ', 'G' => 'Δ', 'H' => 'Ε', 'I' => 'Ζ', 'J' => 'Η', 'K' => 'Θ', 'L' => 'Ι', 'M' => 'Κ', 'N' => 'Λ', 'O' => 'Μ', 'P' => 'Ν', 'Q' => 'Ξ', 'R' => 'Ο', 'S' => 'Π', 'T' => 'Ρ', 'U' => 'Σ', 'V' => 'Τ', 'W' => 'Υ', 'X' => 'Φ', 'Y' => 'Χ', 'Z' => 'Ψ', '[' => 'Ω', '\\' => 'α', ']' => 'β', '^' => 'γ', '_' => 'δ', '`' => 'ε', 'a' => 'ζ', 'b' => 'η', 'c' => 'θ', 'd' => 'ι', 'e' => 'κ', 'f' => 'λ', 'g' => 'μ', 'h' => 'ν', 'i' => 'ξ', 'j' => 'ο', 'k' => 'π', 'l' => 'ρ', 'm' => 'σ', 'n' => 'τ', 'o' => 'υ', 'p' => 'φ', 'q' => 'χ', 'r' => 'ψ', 's' => 'ω', 't' => 'ㄅ', 'u' => 'ㄆ', 'v' => 'ㄇ', 'w' => 'ㄈ', 'x' => 'ㄉ', 'y' => 'ㄊ', 'z' => 'ㄋ', '{' => 'ㄌ', '|' => 'ㄍ', '}' => 'ㄎ', '~' => 'ㄏ', '' => 'ㄐ', '' => 'ㄑ', '' => 'ㄒ', '' => 'ㄓ', '' => 'ㄔ', '' => 'ㄕ', '' => 'ㄖ', '' => 'ㄗ', '' => 'ㄘ', '' => 'ㄙ', '' => 'ㄚ', '' => 'ㄛ', '' => 'ㄜ', '' => 'ㄝ', '' => 'ㄞ', '' => 'ㄟ', '' => 'ㄠ', '' => 'ㄡ', '' => 'ㄢ', '' => 'ㄣ', '' => 'ㄤ', '' => 'ㄥ', '' => 'ㄦ', '' => 'ㄧ', '' => 'ㄨ', '' => 'ㄩ', '' => '˙', '' => 'ˉ', '' => 'ˊ', '' => 'ˇ', '' => 'ˋ', '@' => '一', 'A' => '乙', 'B' => '丁', 'C' => '七', 'D' => '乃', 'E' => '九', 'F' => '了', 'G' => '二', 'H' => '人', 'I' => '儿', 'J' => '入', 'K' => '八', 'L' => '几', 'M' => '刀', 'N' => '刁', 'O' => '力', 'P' => '匕', 'Q' => '十', 'R' => '卜', 'S' => '又', 'T' => '三', 'U' => '下', 'V' => '丈', 'W' => '上', 'X' => '丫', 'Y' => '丸', 'Z' => '凡', '[' => '久', '\\' => '么', ']' => '也', '^' => '乞', '_' => '于', '`' => '亡', 'a' => '兀', 'b' => '刃', 'c' => '勺', 'd' => '千', 'e' => '叉', 'f' => '口', 'g' => '土', 'h' => '士', 'i' => '夕', 'j' => '大', 'k' => '女', 'l' => '子', 'm' => '孑', 'n' => '孓', 'o' => '寸', 'p' => '小', 'q' => '尢', 'r' => '尸', 's' => '山', 't' => '川', 'u' => '工', 'v' => '己', 'w' => '已', 'x' => '巳', 'y' => '巾', 'z' => '干', '{' => '廾', '|' => '弋', '}' => '弓', '~' => '才', '' => '丑', '' => '丐', '' => '不', '' => '中', '' => '丰', '' => '丹', '' => '之', '' => '尹', '' => '予', '' => '云', '' => '井', '' => '互', '' => '五', '' => '亢', '' => '仁', '' => '什', '' => '仃', '' => '仆', '' => '仇', '' => '仍', '' => '今', '' => '介', '' => '仄', '' => '元', '' => '允', '' => '內', '' => '六', '' => '兮', '' => '公', '' => '冗', '' => '凶', '' => '分', '' => '切', '' => '刈', '' => '勻', '' => '勾', '' => '勿', '' => '化', '' => '匹', '' => '午', '' => '升', '' => '卅', '' => '卞', '' => '厄', '' => '友', '' => '及', '' => '反', '' => '壬', '' => '天', '' => '夫', '' => '太', '' => '夭', '' => '孔', '' => '少', '' => '尤', '' => '尺', '' => '屯', '' => '巴', '' => '幻', '' => '廿', '' => '弔', '' => '引', '' => '心', '' => '戈', '' => '戶', '' => '手', '' => '扎', '' => '支', '' => '文', '' => '斗', '' => '斤', '' => '方', '' => '日', '' => '曰', '' => '月', '' => '木', '' => '欠', '' => '止', '' => '歹', '' => '毋', '' => '比', '' => '毛', '' => '氏', '' => '水', '' => '火', '' => '爪', '' => '父', '' => '爻', '' => '片', '' => '牙', '' => '牛', '' => '犬', '' => '王', '' => '丙', '@' => '世', 'A' => '丕', 'B' => '且', 'C' => '丘', 'D' => '主', 'E' => '乍', 'F' => '乏', 'G' => '乎', 'H' => '以', 'I' => '付', 'J' => '仔', 'K' => '仕', 'L' => '他', 'M' => '仗', 'N' => '代', 'O' => '令', 'P' => '仙', 'Q' => '仞', 'R' => '充', 'S' => '兄', 'T' => '冉', 'U' => '冊', 'V' => '冬', 'W' => '凹', 'X' => '出', 'Y' => '凸', 'Z' => '刊', '[' => '加', '\\' => '功', ']' => '包', '^' => '匆', '_' => '北', '`' => '匝', 'a' => '仟', 'b' => '半', 'c' => '卉', 'd' => '卡', 'e' => '占', 'f' => '卯', 'g' => '卮', 'h' => '去', 'i' => '可', 'j' => '古', 'k' => '右', 'l' => '召', 'm' => '叮', 'n' => '叩', 'o' => '叨', 'p' => '叼', 'q' => '司', 'r' => '叵', 's' => '叫', 't' => '另', 'u' => '只', 'v' => '史', 'w' => '叱', 'x' => '台', 'y' => '句', 'z' => '叭', '{' => '叻', '|' => '四', '}' => '囚', '~' => '外', '' => '央', '' => '失', '' => '奴', '' => '奶', '' => '孕', '' => '它', '' => '尼', '' => '巨', '' => '巧', '' => '左', '' => '市', '' => '布', '' => '平', '' => '幼', '' => '弁', '' => '弘', '' => '弗', '' => '必', '' => '戊', '' => '打', '' => '扔', '' => '扒', '' => '扑', '' => '斥', '' => '旦', '' => '朮', '' => '本', '' => '未', '' => '末', '' => '札', '' => '正', '' => '母', '' => '民', '' => '氐', '' => '永', '' => '汁', '' => '汀', '' => '氾', '' => '犯', '' => '玄', '' => '玉', '' => '瓜', '' => '瓦', '' => '甘', '' => '生', '' => '用', '' => '甩', '' => '田', '' => '由', '' => '甲', '' => '申', '' => '疋', '' => '白', '' => '皮', '' => '皿', '' => '目', '' => '矛', '' => '矢', '' => '石', '' => '示', '' => '禾', '' => '穴', '' => '立', '' => '丞', '' => '丟', '' => '乒', '' => '乓', '' => '乩', '' => '亙', '' => '交', '' => '亦', '' => '亥', '' => '仿', '' => '伉', '' => '伙', '' => '伊', '' => '伕', '' => '伍', '' => '伐', '' => '休', '' => '伏', '' => '仲', '' => '件', '' => '任', '' => '仰', '' => '仳', '' => '份', '' => '企', '' => '伋', '' => '光', '' => '兇', '' => '兆', '' => '先', '' => '全', '@' => '共', 'A' => '再', 'B' => '冰', 'C' => '列', 'D' => '刑', 'E' => '划', 'F' => '刎', 'G' => '刖', 'H' => '劣', 'I' => '匈', 'J' => '匡', 'K' => '匠', 'L' => '印', 'M' => '危', 'N' => '吉', 'O' => '吏', 'P' => '同', 'Q' => '吊', 'R' => '吐', 'S' => '吁', 'T' => '吋', 'U' => '各', 'V' => '向', 'W' => '名', 'X' => '合', 'Y' => '吃', 'Z' => '后', '[' => '吆', '\\' => '吒', ']' => '因', '^' => '回', '_' => '囝', '`' => '圳', 'a' => '地', 'b' => '在', 'c' => '圭', 'd' => '圬', 'e' => '圯', 'f' => '圩', 'g' => '夙', 'h' => '多', 'i' => '夷', 'j' => '夸', 'k' => '妄', 'l' => '奸', 'm' => '妃', 'n' => '好', 'o' => '她', 'p' => '如', 'q' => '妁', 'r' => '字', 's' => '存', 't' => '宇', 'u' => '守', 'v' => '宅', 'w' => '安', 'x' => '寺', 'y' => '尖', 'z' => '屹', '{' => '州', '|' => '帆', '}' => '并', '~' => '年', '' => '式', '' => '弛', '' => '忙', '' => '忖', '' => '戎', '' => '戌', '' => '戍', '' => '成', '' => '扣', '' => '扛', '' => '托', '' => '收', '' => '早', '' => '旨', '' => '旬', '' => '旭', '' => '曲', '' => '曳', '' => '有', '' => '朽', '' => '朴', '' => '朱', '' => '朵', '' => '次', '' => '此', '' => '死', '' => '氖', '' => '汝', '' => '汗', '' => '汙', '' => '江', '' => '池', '' => '汐', '' => '汕', '' => '污', '' => '汛', '' => '汍', '' => '汎', '' => '灰', '' => '牟', '' => '牝', '' => '百', '' => '竹', '' => '米', '' => '糸', '' => '缶', '' => '羊', '' => '羽', '' => '老', '' => '考', '' => '而', '' => '耒', '' => '耳', '' => '聿', '' => '肉', '' => '肋', '' => '肌', '' => '臣', '' => '自', '' => '至', '' => '臼', '' => '舌', '' => '舛', '' => '舟', '' => '艮', '' => '色', '' => '艾', '' => '虫', '' => '血', '' => '行', '' => '衣', '' => '西', '' => '阡', '' => '串', '' => '亨', '' => '位', '' => '住', '' => '佇', '' => '佗', '' => '佞', '' => '伴', '' => '佛', '' => '何', '' => '估', '' => '佐', '' => '佑', '' => '伽', '' => '伺', '' => '伸', '' => '佃', '' => '佔', '' => '似', '' => '但', '' => '佣', '@' => '作', 'A' => '你', 'B' => '伯', 'C' => '低', 'D' => '伶', 'E' => '余', 'F' => '佝', 'G' => '佈', 'H' => '佚', 'I' => '兌', 'J' => '克', 'K' => '免', 'L' => '兵', 'M' => '冶', 'N' => '冷', 'O' => '別', 'P' => '判', 'Q' => '利', 'R' => '刪', 'S' => '刨', 'T' => '劫', 'U' => '助', 'V' => '努', 'W' => '劬', 'X' => '匣', 'Y' => '即', 'Z' => '卵', '[' => '吝', '\\' => '吭', ']' => '吞', '^' => '吾', '_' => '否', '`' => '呎', 'a' => '吧', 'b' => '呆', 'c' => '呃', 'd' => '吳', 'e' => '呈', 'f' => '呂', 'g' => '君', 'h' => '吩', 'i' => '告', 'j' => '吹', 'k' => '吻', 'l' => '吸', 'm' => '吮', 'n' => '吵', 'o' => '吶', 'p' => '吠', 'q' => '吼', 'r' => '呀', 's' => '吱', 't' => '含', 'u' => '吟', 'v' => '听', 'w' => '囪', 'x' => '困', 'y' => '囤', 'z' => '囫', '{' => '坊', '|' => '坑', '}' => '址', '~' => '坍', '' => '均', '' => '坎', '' => '圾', '' => '坐', '' => '坏', '' => '圻', '' => '壯', '' => '夾', '' => '妝', '' => '妒', '' => '妨', '' => '妞', '' => '妣', '' => '妙', '' => '妖', '' => '妍', '' => '妤', '' => '妓', '' => '妊', '' => '妥', '' => '孝', '' => '孜', '' => '孚', '' => '孛', '' => '完', '' => '宋', '' => '宏', '' => '尬', '' => '局', '' => '屁', '' => '尿', '' => '尾', '' => '岐', '' => '岑', '' => '岔', '' => '岌', '' => '巫', '' => '希', '' => '序', '' => '庇', '' => '床', '' => '廷', '' => '弄', '' => '弟', '' => '彤', '' => '形', '' => '彷', '' => '役', '' => '忘', '' => '忌', '' => '志', '' => '忍', '' => '忱', '' => '快', '' => '忸', '' => '忪', '' => '戒', '' => '我', '' => '抄', '' => '抗', '' => '抖', '' => '技', '' => '扶', '' => '抉', '' => '扭', '' => '把', '' => '扼', '' => '找', '' => '批', '' => '扳', '' => '抒', '' => '扯', '' => '折', '' => '扮', '' => '投', '' => '抓', '' => '抑', '' => '抆', '' => '改', '' => '攻', '' => '攸', '' => '旱', '' => '更', '' => '束', '' => '李', '' => '杏', '' => '材', '' => '村', '' => '杜', '' => '杖', '' => '杞', '' => '杉', '' => '杆', '' => '杠', '@' => '杓', 'A' => '杗', 'B' => '步', 'C' => '每', 'D' => '求', 'E' => '汞', 'F' => '沙', 'G' => '沁', 'H' => '沈', 'I' => '沉', 'J' => '沅', 'K' => '沛', 'L' => '汪', 'M' => '決', 'N' => '沐', 'O' => '汰', 'P' => '沌', 'Q' => '汨', 'R' => '沖', 'S' => '沒', 'T' => '汽', 'U' => '沃', 'V' => '汲', 'W' => '汾', 'X' => '汴', 'Y' => '沆', 'Z' => '汶', '[' => '沍', '\\' => '沔', ']' => '沘', '^' => '沂', '_' => '灶', '`' => '灼', 'a' => '災', 'b' => '灸', 'c' => '牢', 'd' => '牡', 'e' => '牠', 'f' => '狄', 'g' => '狂', 'h' => '玖', 'i' => '甬', 'j' => '甫', 'k' => '男', 'l' => '甸', 'm' => '皂', 'n' => '盯', 'o' => '矣', 'p' => '私', 'q' => '秀', 'r' => '禿', 's' => '究', 't' => '系', 'u' => '罕', 'v' => '肖', 'w' => '肓', 'x' => '肝', 'y' => '肘', 'z' => '肛', '{' => '肚', '|' => '育', '}' => '良', '~' => '芒', '' => '芋', '' => '芍', '' => '見', '' => '角', '' => '言', '' => '谷', '' => '豆', '' => '豕', '' => '貝', '' => '赤', '' => '走', '' => '足', '' => '身', '' => '車', '' => '辛', '' => '辰', '' => '迂', '' => '迆', '' => '迅', '' => '迄', '' => '巡', '' => '邑', '' => '邢', '' => '邪', '' => '邦', '' => '那', '' => '酉', '' => '釆', '' => '里', '' => '防', '' => '阮', '' => '阱', '' => '阪', '' => '阬', '' => '並', '' => '乖', '' => '乳', '' => '事', '' => '些', '' => '亞', '' => '享', '' => '京', '' => '佯', '' => '依', '' => '侍', '' => '佳', '' => '使', '' => '佬', '' => '供', '' => '例', '' => '來', '' => '侃', '' => '佰', '' => '併', '' => '侈', '' => '佩', '' => '佻', '' => '侖', '' => '佾', '' => '侏', '' => '侑', '' => '佺', '' => '兔', '' => '兒', '' => '兕', '' => '兩', '' => '具', '' => '其', '' => '典', '' => '冽', '' => '函', '' => '刻', '' => '券', '' => '刷', '' => '刺', '' => '到', '' => '刮', '' => '制', '' => '剁', '' => '劾', '' => '劻', '' => '卒', '' => '協', '' => '卓', '' => '卑', '' => '卦', '' => '卷', '' => '卸', '' => '卹', '' => '取', '' => '叔', '' => '受', '' => '味', '' => '呵', '@' => '咖', 'A' => '呸', 'B' => '咕', 'C' => '咀', 'D' => '呻', 'E' => '呷', 'F' => '咄', 'G' => '咒', 'H' => '咆', 'I' => '呼', 'J' => '咐', 'K' => '呱', 'L' => '呶', 'M' => '和', 'N' => '咚', 'O' => '呢', 'P' => '周', 'Q' => '咋', 'R' => '命', 'S' => '咎', 'T' => '固', 'U' => '垃', 'V' => '坷', 'W' => '坪', 'X' => '坩', 'Y' => '坡', 'Z' => '坦', '[' => '坤', '\\' => '坼', ']' => '夜', '^' => '奉', '_' => '奇', '`' => '奈', 'a' => '奄', 'b' => '奔', 'c' => '妾', 'd' => '妻', 'e' => '委', 'f' => '妹', 'g' => '妮', 'h' => '姑', 'i' => '姆', 'j' => '姐', 'k' => '姍', 'l' => '始', 'm' => '姓', 'n' => '姊', 'o' => '妯', 'p' => '妳', 'q' => '姒', 'r' => '姅', 's' => '孟', 't' => '孤', 'u' => '季', 'v' => '宗', 'w' => '定', 'x' => '官', 'y' => '宜', 'z' => '宙', '{' => '宛', '|' => '尚', '}' => '屈', '~' => '居', '' => '屆', '' => '岷', '' => '岡', '' => '岸', '' => '岩', '' => '岫', '' => '岱', '' => '岳', '' => '帘', '' => '帚', '' => '帖', '' => '帕', '' => '帛', '' => '帑', '' => '幸', '' => '庚', '' => '店', '' => '府', '' => '底', '' => '庖', '' => '延', '' => '弦', '' => '弧', '' => '弩', '' => '往', '' => '征', '' => '彿', '' => '彼', '' => '忝', '' => '忠', '' => '忽', '' => '念', '' => '忿', '' => '怏', '' => '怔', '' => '怯', '' => '怵', '' => '怖', '' => '怪', '' => '怕', '' => '怡', '' => '性', '' => '怩', '' => '怫', '' => '怛', '' => '或', '' => '戕', '' => '房', '' => '戾', '' => '所', '' => '承', '' => '拉', '' => '拌', '' => '拄', '' => '抿', '' => '拂', '' => '抹', '' => '拒', '' => '招', '' => '披', '' => '拓', '' => '拔', '' => '拋', '' => '拈', '' => '抨', '' => '抽', '' => '押', '' => '拐', '' => '拙', '' => '拇', '' => '拍', '' => '抵', '' => '拚', '' => '抱', '' => '拘', '' => '拖', '' => '拗', '' => '拆', '' => '抬', '' => '拎', '' => '放', '' => '斧', '' => '於', '' => '旺', '' => '昔', '' => '易', '' => '昌', '' => '昆', '' => '昂', '' => '明', '' => '昀', '' => '昏', '' => '昕', '' => '昊', '@' => '昇', 'A' => '服', 'B' => '朋', 'C' => '杭', 'D' => '枋', 'E' => '枕', 'F' => '東', 'G' => '果', 'H' => '杳', 'I' => '杷', 'J' => '枇', 'K' => '枝', 'L' => '林', 'M' => '杯', 'N' => '杰', 'O' => '板', 'P' => '枉', 'Q' => '松', 'R' => '析', 'S' => '杵', 'T' => '枚', 'U' => '枓', 'V' => '杼', 'W' => '杪', 'X' => '杲', 'Y' => '欣', 'Z' => '武', '[' => '歧', '\\' => '歿', ']' => '氓', '^' => '氛', '_' => '泣', '`' => '注', 'a' => '泳', 'b' => '沱', 'c' => '泌', 'd' => '泥', 'e' => '河', 'f' => '沽', 'g' => '沾', 'h' => '沼', 'i' => '波', 'j' => '沫', 'k' => '法', 'l' => '泓', 'm' => '沸', 'n' => '泄', 'o' => '油', 'p' => '況', 'q' => '沮', 'r' => '泗', 's' => '泅', 't' => '泱', 'u' => '沿', 'v' => '治', 'w' => '泡', 'x' => '泛', 'y' => '泊', 'z' => '沬', '{' => '泯', '|' => '泜', '}' => '泖', '~' => '泠', '' => '炕', '' => '炎', '' => '炒', '' => '炊', '' => '炙', '' => '爬', '' => '爭', '' => '爸', '' => '版', '' => '牧', '' => '物', '' => '狀', '' => '狎', '' => '狙', '' => '狗', '' => '狐', '' => '玩', '' => '玨', '' => '玟', '' => '玫', '' => '玥', '' => '甽', '' => '疝', '' => '疙', '' => '疚', '' => '的', '' => '盂', '' => '盲', '' => '直', '' => '知', '' => '矽', '' => '社', '' => '祀', '' => '祁', '' => '秉', '' => '秈', '' => '空', '' => '穹', '' => '竺', '' => '糾', '' => '罔', '' => '羌', '' => '羋', '' => '者', '' => '肺', '' => '肥', '' => '肢', '' => '肱', '' => '股', '' => '肫', '' => '肩', '' => '肴', '' => '肪', '' => '肯', '' => '臥', '' => '臾', '' => '舍', '' => '芳', '' => '芝', '' => '芙', '' => '芭', '' => '芽', '' => '芟', '' => '芹', '' => '花', '' => '芬', '' => '芥', '' => '芯', '' => '芸', '' => '芣', '' => '芰', '' => '芾', '' => '芷', '' => '虎', '' => '虱', '' => '初', '' => '表', '' => '軋', '' => '迎', '' => '返', '' => '近', '' => '邵', '' => '邸', '' => '邱', '' => '邶', '' => '采', '' => '金', '' => '長', '' => '門', '' => '阜', '' => '陀', '' => '阿', '' => '阻', '' => '附', '@' => '陂', 'A' => '隹', 'B' => '雨', 'C' => '青', 'D' => '非', 'E' => '亟', 'F' => '亭', 'G' => '亮', 'H' => '信', 'I' => '侵', 'J' => '侯', 'K' => '便', 'L' => '俠', 'M' => '俑', 'N' => '俏', 'O' => '保', 'P' => '促', 'Q' => '侶', 'R' => '俘', 'S' => '俟', 'T' => '俊', 'U' => '俗', 'V' => '侮', 'W' => '俐', 'X' => '俄', 'Y' => '係', 'Z' => '俚', '[' => '俎', '\\' => '俞', ']' => '侷', '^' => '兗', '_' => '冒', '`' => '冑', 'a' => '冠', 'b' => '剎', 'c' => '剃', 'd' => '削', 'e' => '前', 'f' => '剌', 'g' => '剋', 'h' => '則', 'i' => '勇', 'j' => '勉', 'k' => '勃', 'l' => '勁', 'm' => '匍', 'n' => '南', 'o' => '卻', 'p' => '厚', 'q' => '叛', 'r' => '咬', 's' => '哀', 't' => '咨', 'u' => '哎', 'v' => '哉', 'w' => '咸', 'x' => '咦', 'y' => '咳', 'z' => '哇', '{' => '哂', '|' => '咽', '}' => '咪', '~' => '品', '' => '哄', '' => '哈', '' => '咯', '' => '咫', '' => '咱', '' => '咻', '' => '咩', '' => '咧', '' => '咿', '' => '囿', '' => '垂', '' => '型', '' => '垠', '' => '垣', '' => '垢', '' => '城', '' => '垮', '' => '垓', '' => '奕', '' => '契', '' => '奏', '' => '奎', '' => '奐', '' => '姜', '' => '姘', '' => '姿', '' => '姣', '' => '姨', '' => '娃', '' => '姥', '' => '姪', '' => '姚', '' => '姦', '' => '威', '' => '姻', '' => '孩', '' => '宣', '' => '宦', '' => '室', '' => '客', '' => '宥', '' => '封', '' => '屎', '' => '屏', '' => '屍', '' => '屋', '' => '峙', '' => '峒', '' => '巷', '' => '帝', '' => '帥', '' => '帟', '' => '幽', '' => '庠', '' => '度', '' => '建', '' => '弈', '' => '弭', '' => '彥', '' => '很', '' => '待', '' => '徊', '' => '律', '' => '徇', '' => '後', '' => '徉', '' => '怒', '' => '思', '' => '怠', '' => '急', '' => '怎', '' => '怨', '' => '恍', '' => '恰', '' => '恨', '' => '恢', '' => '恆', '' => '恃', '' => '恬', '' => '恫', '' => '恪', '' => '恤', '' => '扁', '' => '拜', '' => '挖', '' => '按', '' => '拼', '' => '拭', '' => '持', '' => '拮', '' => '拽', '' => '指', '' => '拱', '' => '拷', '@' => '拯', 'A' => '括', 'B' => '拾', 'C' => '拴', 'D' => '挑', 'E' => '挂', 'F' => '政', 'G' => '故', 'H' => '斫', 'I' => '施', 'J' => '既', 'K' => '春', 'L' => '昭', 'M' => '映', 'N' => '昧', 'O' => '是', 'P' => '星', 'Q' => '昨', 'R' => '昱', 'S' => '昤', 'T' => '曷', 'U' => '柿', 'V' => '染', 'W' => '柱', 'X' => '柔', 'Y' => '某', 'Z' => '柬', '[' => '架', '\\' => '枯', ']' => '柵', '^' => '柩', '_' => '柯', '`' => '柄', 'a' => '柑', 'b' => '枴', 'c' => '柚', 'd' => '查', 'e' => '枸', 'f' => '柏', 'g' => '柞', 'h' => '柳', 'i' => '枰', 'j' => '柙', 'k' => '柢', 'l' => '柝', 'm' => '柒', 'n' => '歪', 'o' => '殃', 'p' => '殆', 'q' => '段', 'r' => '毒', 's' => '毗', 't' => '氟', 'u' => '泉', 'v' => '洋', 'w' => '洲', 'x' => '洪', 'y' => '流', 'z' => '津', '{' => '洌', '|' => '洱', '}' => '洞', '~' => '洗', '' => '活', '' => '洽', '' => '派', '' => '洶', '' => '洛', '' => '泵', '' => '洹', '' => '洧', '' => '洸', '' => '洩', '' => '洮', '' => '洵', '' => '洎', '' => '洫', '' => '炫', '' => '為', '' => '炳', '' => '炬', '' => '炯', '' => '炭', '' => '炸', '' => '炮', '' => '炤', '' => '爰', '' => '牲', '' => '牯', '' => '牴', '' => '狩', '' => '狠', '' => '狡', '' => '玷', '' => '珊', '' => '玻', '' => '玲', '' => '珍', '' => '珀', '' => '玳', '' => '甚', '' => '甭', '' => '畏', '' => '界', '' => '畎', '' => '畋', '' => '疫', '' => '疤', '' => '疥', '' => '疢', '' => '疣', '' => '癸', '' => '皆', '' => '皇', '' => '皈', '' => '盈', '' => '盆', '' => '盃', '' => '盅', '' => '省', '' => '盹', '' => '相', '' => '眉', '' => '看', '' => '盾', '' => '盼', '' => '眇', '' => '矜', '' => '砂', '' => '研', '' => '砌', '' => '砍', '' => '祆', '' => '祉', '' => '祈', '' => '祇', '' => '禹', '' => '禺', '' => '科', '' => '秒', '' => '秋', '' => '穿', '' => '突', '' => '竿', '' => '竽', '' => '籽', '' => '紂', '' => '紅', '' => '紀', '' => '紉', '' => '紇', '' => '約', '' => '紆', '' => '缸', '' => '美', '' => '羿', '' => '耄', '@' => '耐', 'A' => '耍', 'B' => '耑', 'C' => '耶', 'D' => '胖', 'E' => '胥', 'F' => '胚', 'G' => '胃', 'H' => '胄', 'I' => '背', 'J' => '胡', 'K' => '胛', 'L' => '胎', 'M' => '胞', 'N' => '胤', 'O' => '胝', 'P' => '致', 'Q' => '舢', 'R' => '苧', 'S' => '范', 'T' => '茅', 'U' => '苣', 'V' => '苛', 'W' => '苦', 'X' => '茄', 'Y' => '若', 'Z' => '茂', '[' => '茉', '\\' => '苒', ']' => '苗', '^' => '英', '_' => '茁', '`' => '苜', 'a' => '苔', 'b' => '苑', 'c' => '苞', 'd' => '苓', 'e' => '苟', 'f' => '苯', 'g' => '茆', 'h' => '虐', 'i' => '虹', 'j' => '虻', 'k' => '虺', 'l' => '衍', 'm' => '衫', 'n' => '要', 'o' => '觔', 'p' => '計', 'q' => '訂', 'r' => '訃', 's' => '貞', 't' => '負', 'u' => '赴', 'v' => '赳', 'w' => '趴', 'x' => '軍', 'y' => '軌', 'z' => '述', '{' => '迦', '|' => '迢', '}' => '迪', '~' => '迥', '' => '迭', '' => '迫', '' => '迤', '' => '迨', '' => '郊', '' => '郎', '' => '郁', '' => '郃', '' => '酋', '' => '酊', '' => '重', '' => '閂', '' => '限', '' => '陋', '' => '陌', '' => '降', '' => '面', '' => '革', '' => '韋', '' => '韭', '' => '音', '' => '頁', '' => '風', '' => '飛', '' => '食', '' => '首', '' => '香', '' => '乘', '' => '亳', '' => '倌', '' => '倍', '' => '倣', '' => '俯', '' => '倦', '' => '倥', '' => '俸', '' => '倩', '' => '倖', '' => '倆', '' => '值', '' => '借', '' => '倚', '' => '倒', '' => '們', '' => '俺', '' => '倀', '' => '倔', '' => '倨', '' => '俱', '' => '倡', '' => '個', '' => '候', '' => '倘', '' => '俳', '' => '修', '' => '倭', '' => '倪', '' => '俾', '' => '倫', '' => '倉', '' => '兼', '' => '冤', '' => '冥', '' => '冢', '' => '凍', '' => '凌', '' => '准', '' => '凋', '' => '剖', '' => '剜', '' => '剔', '' => '剛', '' => '剝', '' => '匪', '' => '卿', '' => '原', '' => '厝', '' => '叟', '' => '哨', '' => '唐', '' => '唁', '' => '唷', '' => '哼', '' => '哥', '' => '哲', '' => '唆', '' => '哺', '' => '唔', '' => '哩', '' => '哭', '' => '員', '' => '唉', '' => '哮', '' => '哪', '@' => '哦', 'A' => '唧', 'B' => '唇', 'C' => '哽', 'D' => '唏', 'E' => '圃', 'F' => '圄', 'G' => '埂', 'H' => '埔', 'I' => '埋', 'J' => '埃', 'K' => '堉', 'L' => '夏', 'M' => '套', 'N' => '奘', 'O' => '奚', 'P' => '娑', 'Q' => '娘', 'R' => '娜', 'S' => '娟', 'T' => '娛', 'U' => '娓', 'V' => '姬', 'W' => '娠', 'X' => '娣', 'Y' => '娩', 'Z' => '娥', '[' => '娌', '\\' => '娉', ']' => '孫', '^' => '屘', '_' => '宰', '`' => '害', 'a' => '家', 'b' => '宴', 'c' => '宮', 'd' => '宵', 'e' => '容', 'f' => '宸', 'g' => '射', 'h' => '屑', 'i' => '展', 'j' => '屐', 'k' => '峭', 'l' => '峽', 'm' => '峻', 'n' => '峪', 'o' => '峨', 'p' => '峰', 'q' => '島', 'r' => '崁', 's' => '峴', 't' => '差', 'u' => '席', 'v' => '師', 'w' => '庫', 'x' => '庭', 'y' => '座', 'z' => '弱', '{' => '徒', '|' => '徑', '}' => '徐', '~' => '恙', '' => '恣', '' => '恥', '' => '恐', '' => '恕', '' => '恭', '' => '恩', '' => '息', '' => '悄', '' => '悟', '' => '悚', '' => '悍', '' => '悔', '' => '悌', '' => '悅', '' => '悖', '' => '扇', '' => '拳', '' => '挈', '' => '拿', '' => '捎', '' => '挾', '' => '振', '' => '捕', '' => '捂', '' => '捆', '' => '捏', '' => '捉', '' => '挺', '' => '捐', '' => '挽', '' => '挪', '' => '挫', '' => '挨', '' => '捍', '' => '捌', '' => '效', '' => '敉', '' => '料', '' => '旁', '' => '旅', '' => '時', '' => '晉', '' => '晏', '' => '晃', '' => '晒', '' => '晌', '' => '晅', '' => '晁', '' => '書', '' => '朔', '' => '朕', '' => '朗', '' => '校', '' => '核', '' => '案', '' => '框', '' => '桓', '' => '根', '' => '桂', '' => '桔', '' => '栩', '' => '梳', '' => '栗', '' => '桌', '' => '桑', '' => '栽', '' => '柴', '' => '桐', '' => '桀', '' => '格', '' => '桃', '' => '株', '' => '桅', '' => '栓', '' => '栘', '' => '桁', '' => '殊', '' => '殉', '' => '殷', '' => '氣', '' => '氧', '' => '氨', '' => '氦', '' => '氤', '' => '泰', '' => '浪', '' => '涕', '' => '消', '' => '涇', '' => '浦', '' => '浸', '' => '海', '' => '浙', '' => '涓', '@' => '浬', 'A' => '涉', 'B' => '浮', 'C' => '浚', 'D' => '浴', 'E' => '浩', 'F' => '涌', 'G' => '涊', 'H' => '浹', 'I' => '涅', 'J' => '浥', 'K' => '涔', 'L' => '烊', 'M' => '烘', 'N' => '烤', 'O' => '烙', 'P' => '烈', 'Q' => '烏', 'R' => '爹', 'S' => '特', 'T' => '狼', 'U' => '狹', 'V' => '狽', 'W' => '狸', 'X' => '狷', 'Y' => '玆', 'Z' => '班', '[' => '琉', '\\' => '珮', ']' => '珠', '^' => '珪', '_' => '珞', '`' => '畔', 'a' => '畝', 'b' => '畜', 'c' => '畚', 'd' => '留', 'e' => '疾', 'f' => '病', 'g' => '症', 'h' => '疲', 'i' => '疳', 'j' => '疽', 'k' => '疼', 'l' => '疹', 'm' => '痂', 'n' => '疸', 'o' => '皋', 'p' => '皰', 'q' => '益', 'r' => '盍', 's' => '盎', 't' => '眩', 'u' => '真', 'v' => '眠', 'w' => '眨', 'x' => '矩', 'y' => '砰', 'z' => '砧', '{' => '砸', '|' => '砝', '}' => '破', '~' => '砷', '' => '砥', '' => '砭', '' => '砠', '' => '砟', '' => '砲', '' => '祕', '' => '祐', '' => '祠', '' => '祟', '' => '祖', '' => '神', '' => '祝', '' => '祗', '' => '祚', '' => '秤', '' => '秣', '' => '秧', '' => '租', '' => '秦', '' => '秩', '' => '秘', '' => '窄', '' => '窈', '' => '站', '' => '笆', '' => '笑', '' => '粉', '' => '紡', '' => '紗', '' => '紋', '' => '紊', '' => '素', '' => '索', '' => '純', '' => '紐', '' => '紕', '' => '級', '' => '紜', '' => '納', '' => '紙', '' => '紛', '' => '缺', '' => '罟', '' => '羔', '' => '翅', '' => '翁', '' => '耆', '' => '耘', '' => '耕', '' => '耙', '' => '耗', '' => '耽', '' => '耿', '' => '胱', '' => '脂', '' => '胰', '' => '脅', '' => '胭', '' => '胴', '' => '脆', '' => '胸', '' => '胳', '' => '脈', '' => '能', '' => '脊', '' => '胼', '' => '胯', '' => '臭', '' => '臬', '' => '舀', '' => '舐', '' => '航', '' => '舫', '' => '舨', '' => '般', '' => '芻', '' => '茫', '' => '荒', '' => '荔', '' => '荊', '' => '茸', '' => '荐', '' => '草', '' => '茵', '' => '茴', '' => '荏', '' => '茲', '' => '茹', '' => '茶', '' => '茗', '' => '荀', '' => '茱', '' => '茨', '' => '荃', '@' => '虔', 'A' => '蚊', 'B' => '蚪', 'C' => '蚓', 'D' => '蚤', 'E' => '蚩', 'F' => '蚌', 'G' => '蚣', 'H' => '蚜', 'I' => '衰', 'J' => '衷', 'K' => '袁', 'L' => '袂', 'M' => '衽', 'N' => '衹', 'O' => '記', 'P' => '訐', 'Q' => '討', 'R' => '訌', 'S' => '訕', 'T' => '訊', 'U' => '託', 'V' => '訓', 'W' => '訖', 'X' => '訏', 'Y' => '訑', 'Z' => '豈', '[' => '豺', '\\' => '豹', ']' => '財', '^' => '貢', '_' => '起', '`' => '躬', 'a' => '軒', 'b' => '軔', 'c' => '軏', 'd' => '辱', 'e' => '送', 'f' => '逆', 'g' => '迷', 'h' => '退', 'i' => '迺', 'j' => '迴', 'k' => '逃', 'l' => '追', 'm' => '逅', 'n' => '迸', 'o' => '邕', 'p' => '郡', 'q' => '郝', 'r' => '郢', 's' => '酒', 't' => '配', 'u' => '酌', 'v' => '釘', 'w' => '針', 'x' => '釗', 'y' => '釜', 'z' => '釙', '{' => '閃', '|' => '院', '}' => '陣', '~' => '陡', '' => '陛', '' => '陝', '' => '除', '' => '陘', '' => '陞', '' => '隻', '' => '飢', '' => '馬', '' => '骨', '' => '高', '' => '鬥', '' => '鬲', '' => '鬼', '' => '乾', '' => '偺', '' => '偽', '' => '停', '' => '假', '' => '偃', '' => '偌', '' => '做', '' => '偉', '' => '健', '' => '偶', '' => '偎', '' => '偕', '' => '偵', '' => '側', '' => '偷', '' => '偏', '' => '倏', '' => '偯', '' => '偭', '' => '兜', '' => '冕', '' => '凰', '' => '剪', '' => '副', '' => '勒', '' => '務', '' => '勘', '' => '動', '' => '匐', '' => '匏', '' => '匙', '' => '匿', '' => '區', '' => '匾', '' => '參', '' => '曼', '' => '商', '' => '啪', '' => '啦', '' => '啄', '' => '啞', '' => '啡', '' => '啃', '' => '啊', '' => '唱', '' => '啖', '' => '問', '' => '啕', '' => '唯', '' => '啤', '' => '唸', '' => '售', '' => '啜', '' => '唬', '' => '啣', '' => '唳', '' => '啁', '' => '啗', '' => '圈', '' => '國', '' => '圉', '' => '域', '' => '堅', '' => '堊', '' => '堆', '' => '埠', '' => '埤', '' => '基', '' => '堂', '' => '堵', '' => '執', '' => '培', '' => '夠', '' => '奢', '' => '娶', '' => '婁', '' => '婉', '' => '婦', '' => '婪', '' => '婀', '@' => '娼', 'A' => '婢', 'B' => '婚', 'C' => '婆', 'D' => '婊', 'E' => '孰', 'F' => '寇', 'G' => '寅', 'H' => '寄', 'I' => '寂', 'J' => '宿', 'K' => '密', 'L' => '尉', 'M' => '專', 'N' => '將', 'O' => '屠', 'P' => '屜', 'Q' => '屝', 'R' => '崇', 'S' => '崆', 'T' => '崎', 'U' => '崛', 'V' => '崖', 'W' => '崢', 'X' => '崑', 'Y' => '崩', 'Z' => '崔', '[' => '崙', '\\' => '崤', ']' => '崧', '^' => '崗', '_' => '巢', '`' => '常', 'a' => '帶', 'b' => '帳', 'c' => '帷', 'd' => '康', 'e' => '庸', 'f' => '庶', 'g' => '庵', 'h' => '庾', 'i' => '張', 'j' => '強', 'k' => '彗', 'l' => '彬', 'm' => '彩', 'n' => '彫', 'o' => '得', 'p' => '徙', 'q' => '從', 'r' => '徘', 's' => '御', 't' => '徠', 'u' => '徜', 'v' => '恿', 'w' => '患', 'x' => '悉', 'y' => '悠', 'z' => '您', '{' => '惋', '|' => '悴', '}' => '惦', '~' => '悽', '' => '情', '' => '悻', '' => '悵', '' => '惜', '' => '悼', '' => '惘', '' => '惕', '' => '惆', '' => '惟', '' => '悸', '' => '惚', '' => '惇', '' => '戚', '' => '戛', '' => '扈', '' => '掠', '' => '控', '' => '捲', '' => '掖', '' => '探', '' => '接', '' => '捷', '' => '捧', '' => '掘', '' => '措', '' => '捱', '' => '掩', '' => '掉', '' => '掃', '' => '掛', '' => '捫', '' => '推', '' => '掄', '' => '授', '' => '掙', '' => '採', '' => '掬', '' => '排', '' => '掏', '' => '掀', '' => '捻', '' => '捩', '' => '捨', '' => '捺', '' => '敝', '' => '敖', '' => '救', '' => '教', '' => '敗', '' => '啟', '' => '敏', '' => '敘', '' => '敕', '' => '敔', '' => '斜', '' => '斛', '' => '斬', '' => '族', '' => '旋', '' => '旌', '' => '旎', '' => '晝', '' => '晚', '' => '晤', '' => '晨', '' => '晦', '' => '晞', '' => '曹', '' => '勗', '' => '望', '' => '梁', '' => '梯', '' => '梢', '' => '梓', '' => '梵', '' => '桿', '' => '桶', '' => '梱', '' => '梧', '' => '梗', '' => '械', '' => '梃', '' => '棄', '' => '梭', '' => '梆', '' => '梅', '' => '梔', '' => '條', '' => '梨', '' => '梟', '' => '梡', '' => '梂', '' => '欲', '' => '殺', '@' => '毫', 'A' => '毬', 'B' => '氫', 'C' => '涎', 'D' => '涼', 'E' => '淳', 'F' => '淙', 'G' => '液', 'H' => '淡', 'I' => '淌', 'J' => '淤', 'K' => '添', 'L' => '淺', 'M' => '清', 'N' => '淇', 'O' => '淋', 'P' => '涯', 'Q' => '淑', 'R' => '涮', 'S' => '淞', 'T' => '淹', 'U' => '涸', 'V' => '混', 'W' => '淵', 'X' => '淅', 'Y' => '淒', 'Z' => '渚', '[' => '涵', '\\' => '淚', ']' => '淫', '^' => '淘', '_' => '淪', '`' => '深', 'a' => '淮', 'b' => '淨', 'c' => '淆', 'd' => '淄', 'e' => '涪', 'f' => '淬', 'g' => '涿', 'h' => '淦', 'i' => '烹', 'j' => '焉', 'k' => '焊', 'l' => '烽', 'm' => '烯', 'n' => '爽', 'o' => '牽', 'p' => '犁', 'q' => '猜', 'r' => '猛', 's' => '猖', 't' => '猓', 'u' => '猙', 'v' => '率', 'w' => '琅', 'x' => '琊', 'y' => '球', 'z' => '理', '{' => '現', '|' => '琍', '}' => '瓠', '~' => '瓶', '' => '瓷', '' => '甜', '' => '產', '' => '略', '' => '畦', '' => '畢', '' => '異', '' => '疏', '' => '痔', '' => '痕', '' => '疵', '' => '痊', '' => '痍', '' => '皎', '' => '盔', '' => '盒', '' => '盛', '' => '眷', '' => '眾', '' => '眼', '' => '眶', '' => '眸', '' => '眺', '' => '硫', '' => '硃', '' => '硎', '' => '祥', '' => '票', '' => '祭', '' => '移', '' => '窒', '' => '窕', '' => '笠', '' => '笨', '' => '笛', '' => '第', '' => '符', '' => '笙', '' => '笞', '' => '笮', '' => '粒', '' => '粗', '' => '粕', '' => '絆', '' => '絃', '' => '統', '' => '紮', '' => '紹', '' => '紼', '' => '絀', '' => '細', '' => '紳', '' => '組', '' => '累', '' => '終', '' => '紲', '' => '紱', '' => '缽', '' => '羞', '' => '羚', '' => '翌', '' => '翎', '' => '習', '' => '耜', '' => '聊', '' => '聆', '' => '脯', '' => '脖', '' => '脣', '' => '脫', '' => '脩', '' => '脰', '' => '脤', '' => '舂', '' => '舵', '' => '舷', '' => '舶', '' => '船', '' => '莎', '' => '莞', '' => '莘', '' => '荸', '' => '莢', '' => '莖', '' => '莽', '' => '莫', '' => '莒', '' => '莊', '' => '莓', '' => '莉', '' => '莠', '' => '荷', '' => '荻', '' => '荼', '@' => '莆', 'A' => '莧', 'B' => '處', 'C' => '彪', 'D' => '蛇', 'E' => '蛀', 'F' => '蚶', 'G' => '蛄', 'H' => '蚵', 'I' => '蛆', 'J' => '蛋', 'K' => '蚱', 'L' => '蚯', 'M' => '蛉', 'N' => '術', 'O' => '袞', 'P' => '袈', 'Q' => '被', 'R' => '袒', 'S' => '袖', 'T' => '袍', 'U' => '袋', 'V' => '覓', 'W' => '規', 'X' => '訪', 'Y' => '訝', 'Z' => '訣', '[' => '訥', '\\' => '許', ']' => '設', '^' => '訟', '_' => '訛', '`' => '訢', 'a' => '豉', 'b' => '豚', 'c' => '販', 'd' => '責', 'e' => '貫', 'f' => '貨', 'g' => '貪', 'h' => '貧', 'i' => '赧', 'j' => '赦', 'k' => '趾', 'l' => '趺', 'm' => '軛', 'n' => '軟', 'o' => '這', 'p' => '逍', 'q' => '通', 'r' => '逗', 's' => '連', 't' => '速', 'u' => '逝', 'v' => '逐', 'w' => '逕', 'x' => '逞', 'y' => '造', 'z' => '透', '{' => '逢', '|' => '逖', '}' => '逛', '~' => '途', '' => '部', '' => '郭', '' => '都', '' => '酗', '' => '野', '' => '釵', '' => '釦', '' => '釣', '' => '釧', '' => '釭', '' => '釩', '' => '閉', '' => '陪', '' => '陵', '' => '陳', '' => '陸', '' => '陰', '' => '陴', '' => '陶', '' => '陷', '' => '陬', '' => '雀', '' => '雪', '' => '雩', '' => '章', '' => '竟', '' => '頂', '' => '頃', '' => '魚', '' => '鳥', '' => '鹵', '' => '鹿', '' => '麥', '' => '麻', '' => '傢', '' => '傍', '' => '傅', '' => '備', '' => '傑', '' => '傀', '' => '傖', '' => '傘', '' => '傚', '' => '最', '' => '凱', '' => '割', '' => '剴', '' => '創', '' => '剩', '' => '勞', '' => '勝', '' => '勛', '' => '博', '' => '厥', '' => '啻', '' => '喀', '' => '喧', '' => '啼', '' => '喊', '' => '喝', '' => '喘', '' => '喂', '' => '喜', '' => '喪', '' => '喔', '' => '喇', '' => '喋', '' => '喃', '' => '喳', '' => '單', '' => '喟', '' => '唾', '' => '喲', '' => '喚', '' => '喻', '' => '喬', '' => '喱', '' => '啾', '' => '喉', '' => '喫', '' => '喙', '' => '圍', '' => '堯', '' => '堪', '' => '場', '' => '堤', '' => '堰', '' => '報', '' => '堡', '' => '堝', '' => '堠', '' => '壹', '' => '壺', '' => '奠', '@' => '婷', 'A' => '媚', 'B' => '婿', 'C' => '媒', 'D' => '媛', 'E' => '媧', 'F' => '孳', 'G' => '孱', 'H' => '寒', 'I' => '富', 'J' => '寓', 'K' => '寐', 'L' => '尊', 'M' => '尋', 'N' => '就', 'O' => '嵌', 'P' => '嵐', 'Q' => '崴', 'R' => '嵇', 'S' => '巽', 'T' => '幅', 'U' => '帽', 'V' => '幀', 'W' => '幃', 'X' => '幾', 'Y' => '廊', 'Z' => '廁', '[' => '廂', '\\' => '廄', ']' => '弼', '^' => '彭', '_' => '復', '`' => '循', 'a' => '徨', 'b' => '惑', 'c' => '惡', 'd' => '悲', 'e' => '悶', 'f' => '惠', 'g' => '愜', 'h' => '愣', 'i' => '惺', 'j' => '愕', 'k' => '惰', 'l' => '惻', 'm' => '惴', 'n' => '慨', 'o' => '惱', 'p' => '愎', 'q' => '惶', 'r' => '愉', 's' => '愀', 't' => '愒', 'u' => '戟', 'v' => '扉', 'w' => '掣', 'x' => '掌', 'y' => '描', 'z' => '揀', '{' => '揩', '|' => '揉', '}' => '揆', '~' => '揍', '' => '插', '' => '揣', '' => '提', '' => '握', '' => '揖', '' => '揭', '' => '揮', '' => '捶', '' => '援', '' => '揪', '' => '換', '' => '摒', '' => '揚', '' => '揹', '' => '敞', '' => '敦', '' => '敢', '' => '散', '' => '斑', '' => '斐', '' => '斯', '' => '普', '' => '晰', '' => '晴', '' => '晶', '' => '景', '' => '暑', '' => '智', '' => '晾', '' => '晷', '' => '曾', '' => '替', '' => '期', '' => '朝', '' => '棺', '' => '棕', '' => '棠', '' => '棘', '' => '棗', '' => '椅', '' => '棟', '' => '棵', '' => '森', '' => '棧', '' => '棹', '' => '棒', '' => '棲', '' => '棣', '' => '棋', '' => '棍', '' => '植', '' => '椒', '' => '椎', '' => '棉', '' => '棚', '' => '楮', '' => '棻', '' => '款', '' => '欺', '' => '欽', '' => '殘', '' => '殖', '' => '殼', '' => '毯', '' => '氮', '' => '氯', '' => '氬', '' => '港', '' => '游', '' => '湔', '' => '渡', '' => '渲', '' => '湧', '' => '湊', '' => '渠', '' => '渥', '' => '渣', '' => '減', '' => '湛', '' => '湘', '' => '渤', '' => '湖', '' => '湮', '' => '渭', '' => '渦', '' => '湯', '' => '渴', '' => '湍', '' => '渺', '' => '測', '' => '湃', '' => '渝', '' => '渾', '' => '滋', '@' => '溉', 'A' => '渙', 'B' => '湎', 'C' => '湣', 'D' => '湄', 'E' => '湲', 'F' => '湩', 'G' => '湟', 'H' => '焙', 'I' => '焚', 'J' => '焦', 'K' => '焰', 'L' => '無', 'M' => '然', 'N' => '煮', 'O' => '焜', 'P' => '牌', 'Q' => '犄', 'R' => '犀', 'S' => '猶', 'T' => '猥', 'U' => '猴', 'V' => '猩', 'W' => '琺', 'X' => '琪', 'Y' => '琳', 'Z' => '琢', '[' => '琥', '\\' => '琵', ']' => '琶', '^' => '琴', '_' => '琯', '`' => '琛', 'a' => '琦', 'b' => '琨', 'c' => '甥', 'd' => '甦', 'e' => '畫', 'f' => '番', 'g' => '痢', 'h' => '痛', 'i' => '痣', 'j' => '痙', 'k' => '痘', 'l' => '痞', 'm' => '痠', 'n' => '登', 'o' => '發', 'p' => '皖', 'q' => '皓', 'r' => '皴', 's' => '盜', 't' => '睏', 'u' => '短', 'v' => '硝', 'w' => '硬', 'x' => '硯', 'y' => '稍', 'z' => '稈', '{' => '程', '|' => '稅', '}' => '稀', '~' => '窘', '' => '窗', '' => '窖', '' => '童', '' => '竣', '' => '等', '' => '策', '' => '筆', '' => '筐', '' => '筒', '' => '答', '' => '筍', '' => '筋', '' => '筏', '' => '筑', '' => '粟', '' => '粥', '' => '絞', '' => '結', '' => '絨', '' => '絕', '' => '紫', '' => '絮', '' => '絲', '' => '絡', '' => '給', '' => '絢', '' => '絰', '' => '絳', '' => '善', '' => '翔', '' => '翕', '' => '耋', '' => '聒', '' => '肅', '' => '腕', '' => '腔', '' => '腋', '' => '腑', '' => '腎', '' => '脹', '' => '腆', '' => '脾', '' => '腌', '' => '腓', '' => '腴', '' => '舒', '' => '舜', '' => '菩', '' => '萃', '' => '菸', '' => '萍', '' => '菠', '' => '菅', '' => '萋', '' => '菁', '' => '華', '' => '菱', '' => '菴', '' => '著', '' => '萊', '' => '菰', '' => '萌', '' => '菌', '' => '菽', '' => '菲', '' => '菊', '' => '萸', '' => '萎', '' => '萄', '' => '菜', '' => '萇', '' => '菔', '' => '菟', '' => '虛', '' => '蛟', '' => '蛙', '' => '蛭', '' => '蛔', '' => '蛛', '' => '蛤', '' => '蛐', '' => '蛞', '' => '街', '' => '裁', '' => '裂', '' => '袱', '' => '覃', '' => '視', '' => '註', '' => '詠', '' => '評', '' => '詞', '' => '証', '' => '詁', '@' => '詔', 'A' => '詛', 'B' => '詐', 'C' => '詆', 'D' => '訴', 'E' => '診', 'F' => '訶', 'G' => '詖', 'H' => '象', 'I' => '貂', 'J' => '貯', 'K' => '貼', 'L' => '貳', 'M' => '貽', 'N' => '賁', 'O' => '費', 'P' => '賀', 'Q' => '貴', 'R' => '買', 'S' => '貶', 'T' => '貿', 'U' => '貸', 'V' => '越', 'W' => '超', 'X' => '趁', 'Y' => '跎', 'Z' => '距', '[' => '跋', '\\' => '跚', ']' => '跑', '^' => '跌', '_' => '跛', '`' => '跆', 'a' => '軻', 'b' => '軸', 'c' => '軼', 'd' => '辜', 'e' => '逮', 'f' => '逵', 'g' => '週', 'h' => '逸', 'i' => '進', 'j' => '逶', 'k' => '鄂', 'l' => '郵', 'm' => '鄉', 'n' => '郾', 'o' => '酣', 'p' => '酥', 'q' => '量', 'r' => '鈔', 's' => '鈕', 't' => '鈣', 'u' => '鈉', 'v' => '鈞', 'w' => '鈍', 'x' => '鈐', 'y' => '鈇', 'z' => '鈑', '{' => '閔', '|' => '閏', '}' => '開', '~' => '閑', '' => '間', '' => '閒', '' => '閎', '' => '隊', '' => '階', '' => '隋', '' => '陽', '' => '隅', '' => '隆', '' => '隍', '' => '陲', '' => '隄', '' => '雁', '' => '雅', '' => '雄', '' => '集', '' => '雇', '' => '雯', '' => '雲', '' => '韌', '' => '項', '' => '順', '' => '須', '' => '飧', '' => '飪', '' => '飯', '' => '飩', '' => '飲', '' => '飭', '' => '馮', '' => '馭', '' => '黃', '' => '黍', '' => '黑', '' => '亂', '' => '傭', '' => '債', '' => '傲', '' => '傳', '' => '僅', '' => '傾', '' => '催', '' => '傷', '' => '傻', '' => '傯', '' => '僇', '' => '剿', '' => '剷', '' => '剽', '' => '募', '' => '勦', '' => '勤', '' => '勢', '' => '勣', '' => '匯', '' => '嗟', '' => '嗨', '' => '嗓', '' => '嗦', '' => '嗎', '' => '嗜', '' => '嗇', '' => '嗑', '' => '嗣', '' => '嗤', '' => '嗯', '' => '嗚', '' => '嗡', '' => '嗅', '' => '嗆', '' => '嗥', '' => '嗉', '' => '園', '' => '圓', '' => '塞', '' => '塑', '' => '塘', '' => '塗', '' => '塚', '' => '塔', '' => '填', '' => '塌', '' => '塭', '' => '塊', '' => '塢', '' => '塒', '' => '塋', '' => '奧', '' => '嫁', '' => '嫉', '' => '嫌', '' => '媾', '' => '媽', '' => '媼', '@' => '媳', 'A' => '嫂', 'B' => '媲', 'C' => '嵩', 'D' => '嵯', 'E' => '幌', 'F' => '幹', 'G' => '廉', 'H' => '廈', 'I' => '弒', 'J' => '彙', 'K' => '徬', 'L' => '微', 'M' => '愚', 'N' => '意', 'O' => '慈', 'P' => '感', 'Q' => '想', 'R' => '愛', 'S' => '惹', 'T' => '愁', 'U' => '愈', 'V' => '慎', 'W' => '慌', 'X' => '慄', 'Y' => '慍', 'Z' => '愾', '[' => '愴', '\\' => '愧', ']' => '愍', '^' => '愆', '_' => '愷', '`' => '戡', 'a' => '戢', 'b' => '搓', 'c' => '搾', 'd' => '搞', 'e' => '搪', 'f' => '搭', 'g' => '搽', 'h' => '搬', 'i' => '搏', 'j' => '搜', 'k' => '搔', 'l' => '損', 'm' => '搶', 'n' => '搖', 'o' => '搗', 'p' => '搆', 'q' => '敬', 'r' => '斟', 's' => '新', 't' => '暗', 'u' => '暉', 'v' => '暇', 'w' => '暈', 'x' => '暖', 'y' => '暄', 'z' => '暘', '{' => '暍', '|' => '會', '}' => '榔', '~' => '業', '' => '楚', '' => '楷', '' => '楠', '' => '楔', '' => '極', '' => '椰', '' => '概', '' => '楊', '' => '楨', '' => '楫', '' => '楞', '' => '楓', '' => '楹', '' => '榆', '' => '楝', '' => '楣', '' => '楛', '' => '歇', '' => '歲', '' => '毀', '' => '殿', '' => '毓', '' => '毽', '' => '溢', '' => '溯', '' => '滓', '' => '溶', '' => '滂', '' => '源', '' => '溝', '' => '滇', '' => '滅', '' => '溥', '' => '溘', '' => '溼', '' => '溺', '' => '溫', '' => '滑', '' => '準', '' => '溜', '' => '滄', '' => '滔', '' => '溪', '' => '溧', '' => '溴', '' => '煎', '' => '煙', '' => '煩', '' => '煤', '' => '煉', '' => '照', '' => '煜', '' => '煬', '' => '煦', '' => '煌', '' => '煥', '' => '煞', '' => '煆', '' => '煨', '' => '煖', '' => '爺', '' => '牒', '' => '猷', '' => '獅', '' => '猿', '' => '猾', '' => '瑯', '' => '瑚', '' => '瑕', '' => '瑟', '' => '瑞', '' => '瑁', '' => '琿', '' => '瑙', '' => '瑛', '' => '瑜', '' => '當', '' => '畸', '' => '瘀', '' => '痰', '' => '瘁', '' => '痲', '' => '痱', '' => '痺', '' => '痿', '' => '痴', '' => '痳', '' => '盞', '' => '盟', '' => '睛', '' => '睫', '' => '睦', '' => '睞', '' => '督', '@' => '睹', 'A' => '睪', 'B' => '睬', 'C' => '睜', 'D' => '睥', 'E' => '睨', 'F' => '睢', 'G' => '矮', 'H' => '碎', 'I' => '碰', 'J' => '碗', 'K' => '碘', 'L' => '碌', 'M' => '碉', 'N' => '硼', 'O' => '碑', 'P' => '碓', 'Q' => '硿', 'R' => '祺', 'S' => '祿', 'T' => '禁', 'U' => '萬', 'V' => '禽', 'W' => '稜', 'X' => '稚', 'Y' => '稠', 'Z' => '稔', '[' => '稟', '\\' => '稞', ']' => '窟', '^' => '窠', '_' => '筷', '`' => '節', 'a' => '筠', 'b' => '筮', 'c' => '筧', 'd' => '粱', 'e' => '粳', 'f' => '粵', 'g' => '經', 'h' => '絹', 'i' => '綑', 'j' => '綁', 'k' => '綏', 'l' => '絛', 'm' => '置', 'n' => '罩', 'o' => '罪', 'p' => '署', 'q' => '義', 'r' => '羨', 's' => '群', 't' => '聖', 'u' => '聘', 'v' => '肆', 'w' => '肄', 'x' => '腱', 'y' => '腰', 'z' => '腸', '{' => '腥', '|' => '腮', '}' => '腳', '~' => '腫', '' => '腹', '' => '腺', '' => '腦', '' => '舅', '' => '艇', '' => '蒂', '' => '葷', '' => '落', '' => '萱', '' => '葵', '' => '葦', '' => '葫', '' => '葉', '' => '葬', '' => '葛', '' => '萼', '' => '萵', '' => '葡', '' => '董', '' => '葩', '' => '葭', '' => '葆', '' => '虞', '' => '虜', '' => '號', '' => '蛹', '' => '蜓', '' => '蜈', '' => '蜇', '' => '蜀', '' => '蛾', '' => '蛻', '' => '蜂', '' => '蜃', '' => '蜆', '' => '蜊', '' => '衙', '' => '裟', '' => '裔', '' => '裙', '' => '補', '' => '裘', '' => '裝', '' => '裡', '' => '裊', '' => '裕', '' => '裒', '' => '覜', '' => '解', '' => '詫', '' => '該', '' => '詳', '' => '試', '' => '詩', '' => '詰', '' => '誇', '' => '詼', '' => '詣', '' => '誠', '' => '話', '' => '誅', '' => '詭', '' => '詢', '' => '詮', '' => '詬', '' => '詹', '' => '詻', '' => '訾', '' => '詨', '' => '豢', '' => '貊', '' => '貉', '' => '賊', '' => '資', '' => '賈', '' => '賄', '' => '貲', '' => '賃', '' => '賂', '' => '賅', '' => '跡', '' => '跟', '' => '跨', '' => '路', '' => '跳', '' => '跺', '' => '跪', '' => '跤', '' => '跦', '' => '躲', '' => '較', '' => '載', '' => '軾', '' => '輊', '@' => '辟', 'A' => '農', 'B' => '運', 'C' => '遊', 'D' => '道', 'E' => '遂', 'F' => '達', 'G' => '逼', 'H' => '違', 'I' => '遐', 'J' => '遇', 'K' => '遏', 'L' => '過', 'M' => '遍', 'N' => '遑', 'O' => '逾', 'P' => '遁', 'Q' => '鄒', 'R' => '鄗', 'S' => '酬', 'T' => '酪', 'U' => '酩', 'V' => '釉', 'W' => '鈷', 'X' => '鉗', 'Y' => '鈸', 'Z' => '鈽', '[' => '鉀', '\\' => '鈾', ']' => '鉛', '^' => '鉋', '_' => '鉤', '`' => '鉑', 'a' => '鈴', 'b' => '鉉', 'c' => '鉍', 'd' => '鉅', 'e' => '鈹', 'f' => '鈿', 'g' => '鉚', 'h' => '閘', 'i' => '隘', 'j' => '隔', 'k' => '隕', 'l' => '雍', 'm' => '雋', 'n' => '雉', 'o' => '雊', 'p' => '雷', 'q' => '電', 'r' => '雹', 's' => '零', 't' => '靖', 'u' => '靴', 'v' => '靶', 'w' => '預', 'x' => '頑', 'y' => '頓', 'z' => '頊', '{' => '頒', '|' => '頌', '}' => '飼', '~' => '飴', '' => '飽', '' => '飾', '' => '馳', '' => '馱', '' => '馴', '' => '髡', '' => '鳩', '' => '麂', '' => '鼎', '' => '鼓', '' => '鼠', '' => '僧', '' => '僮', '' => '僥', '' => '僖', '' => '僭', '' => '僚', '' => '僕', '' => '像', '' => '僑', '' => '僱', '' => '僎', '' => '僩', '' => '兢', '' => '凳', '' => '劃', '' => '劂', '' => '匱', '' => '厭', '' => '嗾', '' => '嘀', '' => '嘛', '' => '嘗', '' => '嗽', '' => '嘔', '' => '嘆', '' => '嘉', '' => '嘍', '' => '嘎', '' => '嗷', '' => '嘖', '' => '嘟', '' => '嘈', '' => '嘐', '' => '嗶', '' => '團', '' => '圖', '' => '塵', '' => '塾', '' => '境', '' => '墓', '' => '墊', '' => '塹', '' => '墅', '' => '塽', '' => '壽', '' => '夥', '' => '夢', '' => '夤', '' => '奪', '' => '奩', '' => '嫡', '' => '嫦', '' => '嫩', '' => '嫗', '' => '嫖', '' => '嫘', '' => '嫣', '' => '孵', '' => '寞', '' => '寧', '' => '寡', '' => '寥', '' => '實', '' => '寨', '' => '寢', '' => '寤', '' => '察', '' => '對', '' => '屢', '' => '嶄', '' => '嶇', '' => '幛', '' => '幣', '' => '幕', '' => '幗', '' => '幔', '' => '廓', '' => '廖', '' => '弊', '' => '彆', '' => '彰', '' => '徹', '' => '慇', '@' => '愿', 'A' => '態', 'B' => '慷', 'C' => '慢', 'D' => '慣', 'E' => '慟', 'F' => '慚', 'G' => '慘', 'H' => '慵', 'I' => '截', 'J' => '撇', 'K' => '摘', 'L' => '摔', 'M' => '撤', 'N' => '摸', 'O' => '摟', 'P' => '摺', 'Q' => '摑', 'R' => '摧', 'S' => '搴', 'T' => '摭', 'U' => '摻', 'V' => '敲', 'W' => '斡', 'X' => '旗', 'Y' => '旖', 'Z' => '暢', '[' => '暨', '\\' => '暝', ']' => '榜', '^' => '榨', '_' => '榕', '`' => '槁', 'a' => '榮', 'b' => '槓', 'c' => '構', 'd' => '榛', 'e' => '榷', 'f' => '榻', 'g' => '榫', 'h' => '榴', 'i' => '槐', 'j' => '槍', 'k' => '榭', 'l' => '槌', 'm' => '榦', 'n' => '槃', 'o' => '榣', 'p' => '歉', 'q' => '歌', 'r' => '氳', 's' => '漳', 't' => '演', 'u' => '滾', 'v' => '漓', 'w' => '滴', 'x' => '漩', 'y' => '漾', 'z' => '漠', '{' => '漬', '|' => '漏', '}' => '漂', '~' => '漢', '' => '滿', '' => '滯', '' => '漆', '' => '漱', '' => '漸', '' => '漲', '' => '漣', '' => '漕', '' => '漫', '' => '漯', '' => '澈', '' => '漪', '' => '滬', '' => '漁', '' => '滲', '' => '滌', '' => '滷', '' => '熔', '' => '熙', '' => '煽', '' => '熊', '' => '熄', '' => '熒', '' => '爾', '' => '犒', '' => '犖', '' => '獄', '' => '獐', '' => '瑤', '' => '瑣', '' => '瑪', '' => '瑰', '' => '瑭', '' => '甄', '' => '疑', '' => '瘧', '' => '瘍', '' => '瘋', '' => '瘉', '' => '瘓', '' => '盡', '' => '監', '' => '瞄', '' => '睽', '' => '睿', '' => '睡', '' => '磁', '' => '碟', '' => '碧', '' => '碳', '' => '碩', '' => '碣', '' => '禎', '' => '福', '' => '禍', '' => '種', '' => '稱', '' => '窪', '' => '窩', '' => '竭', '' => '端', '' => '管', '' => '箕', '' => '箋', '' => '筵', '' => '算', '' => '箝', '' => '箔', '' => '箏', '' => '箸', '' => '箇', '' => '箄', '' => '粹', '' => '粽', '' => '精', '' => '綻', '' => '綰', '' => '綜', '' => '綽', '' => '綾', '' => '綠', '' => '緊', '' => '綴', '' => '網', '' => '綱', '' => '綺', '' => '綢', '' => '綿', '' => '綵', '' => '綸', '' => '維', '' => '緒', '' => '緇', '' => '綬', '@' => '罰', 'A' => '翠', 'B' => '翡', 'C' => '翟', 'D' => '聞', 'E' => '聚', 'F' => '肇', 'G' => '腐', 'H' => '膀', 'I' => '膏', 'J' => '膈', 'K' => '膊', 'L' => '腿', 'M' => '膂', 'N' => '臧', 'O' => '臺', 'P' => '與', 'Q' => '舔', 'R' => '舞', 'S' => '艋', 'T' => '蓉', 'U' => '蒿', 'V' => '蓆', 'W' => '蓄', 'X' => '蒙', 'Y' => '蒞', 'Z' => '蒲', '[' => '蒜', '\\' => '蓋', ']' => '蒸', '^' => '蓀', '_' => '蓓', '`' => '蒐', 'a' => '蒼', 'b' => '蓑', 'c' => '蓊', 'd' => '蜿', 'e' => '蜜', 'f' => '蜻', 'g' => '蜢', 'h' => '蜥', 'i' => '蜴', 'j' => '蜘', 'k' => '蝕', 'l' => '蜷', 'm' => '蜩', 'n' => '裳', 'o' => '褂', 'p' => '裴', 'q' => '裹', 'r' => '裸', 's' => '製', 't' => '裨', 'u' => '褚', 'v' => '裯', 'w' => '誦', 'x' => '誌', 'y' => '語', 'z' => '誣', '{' => '認', '|' => '誡', '}' => '誓', '~' => '誤', '' => '說', '' => '誥', '' => '誨', '' => '誘', '' => '誑', '' => '誚', '' => '誧', '' => '豪', '' => '貍', '' => '貌', '' => '賓', '' => '賑', '' => '賒', '' => '赫', '' => '趙', '' => '趕', '' => '跼', '' => '輔', '' => '輒', '' => '輕', '' => '輓', '' => '辣', '' => '遠', '' => '遘', '' => '遜', '' => '遣', '' => '遙', '' => '遞', '' => '遢', '' => '遝', '' => '遛', '' => '鄙', '' => '鄘', '' => '鄞', '' => '酵', '' => '酸', '' => '酷', '' => '酴', '' => '鉸', '' => '銀', '' => '銅', '' => '銘', '' => '銖', '' => '鉻', '' => '銓', '' => '銜', '' => '銨', '' => '鉼', '' => '銑', '' => '閡', '' => '閨', '' => '閩', '' => '閣', '' => '閥', '' => '閤', '' => '隙', '' => '障', '' => '際', '' => '雌', '' => '雒', '' => '需', '' => '靼', '' => '鞅', '' => '韶', '' => '頗', '' => '領', '' => '颯', '' => '颱', '' => '餃', '' => '餅', '' => '餌', '' => '餉', '' => '駁', '' => '骯', '' => '骰', '' => '髦', '' => '魁', '' => '魂', '' => '鳴', '' => '鳶', '' => '鳳', '' => '麼', '' => '鼻', '' => '齊', '' => '億', '' => '儀', '' => '僻', '' => '僵', '' => '價', '' => '儂', '' => '儈', '' => '儉', '' => '儅', '' => '凜', '@' => '劇', 'A' => '劈', 'B' => '劉', 'C' => '劍', 'D' => '劊', 'E' => '勰', 'F' => '厲', 'G' => '嘮', 'H' => '嘻', 'I' => '嘹', 'J' => '嘲', 'K' => '嘿', 'L' => '嘴', 'M' => '嘩', 'N' => '噓', 'O' => '噎', 'P' => '噗', 'Q' => '噴', 'R' => '嘶', 'S' => '嘯', 'T' => '嘰', 'U' => '墀', 'V' => '墟', 'W' => '增', 'X' => '墳', 'Y' => '墜', 'Z' => '墮', '[' => '墩', '\\' => '墦', ']' => '奭', '^' => '嬉', '_' => '嫻', '`' => '嬋', 'a' => '嫵', 'b' => '嬌', 'c' => '嬈', 'd' => '寮', 'e' => '寬', 'f' => '審', 'g' => '寫', 'h' => '層', 'i' => '履', 'j' => '嶝', 'k' => '嶔', 'l' => '幢', 'm' => '幟', 'n' => '幡', 'o' => '廢', 'p' => '廚', 'q' => '廟', 'r' => '廝', 's' => '廣', 't' => '廠', 'u' => '彈', 'v' => '影', 'w' => '德', 'x' => '徵', 'y' => '慶', 'z' => '慧', '{' => '慮', '|' => '慝', '}' => '慕', '~' => '憂', '' => '慼', '' => '慰', '' => '慫', '' => '慾', '' => '憧', '' => '憐', '' => '憫', '' => '憎', '' => '憬', '' => '憚', '' => '憤', '' => '憔', '' => '憮', '' => '戮', '' => '摩', '' => '摯', '' => '摹', '' => '撞', '' => '撲', '' => '撈', '' => '撐', '' => '撰', '' => '撥', '' => '撓', '' => '撕', '' => '撩', '' => '撒', '' => '撮', '' => '播', '' => '撫', '' => '撚', '' => '撬', '' => '撙', '' => '撢', '' => '撳', '' => '敵', '' => '敷', '' => '數', '' => '暮', '' => '暫', '' => '暴', '' => '暱', '' => '樣', '' => '樟', '' => '槨', '' => '樁', '' => '樞', '' => '標', '' => '槽', '' => '模', '' => '樓', '' => '樊', '' => '槳', '' => '樂', '' => '樅', '' => '槭', '' => '樑', '' => '歐', '' => '歎', '' => '殤', '' => '毅', '' => '毆', '' => '漿', '' => '潼', '' => '澄', '' => '潑', '' => '潦', '' => '潔', '' => '澆', '' => '潭', '' => '潛', '' => '潸', '' => '潮', '' => '澎', '' => '潺', '' => '潰', '' => '潤', '' => '澗', '' => '潘', '' => '滕', '' => '潯', '' => '潠', '' => '潟', '' => '熟', '' => '熬', '' => '熱', '' => '熨', '' => '牖', '' => '犛', '' => '獎', '' => '獗', '' => '瑩', '' => '璋', '' => '璃', '@' => '瑾', 'A' => '璀', 'B' => '畿', 'C' => '瘠', 'D' => '瘩', 'E' => '瘟', 'F' => '瘤', 'G' => '瘦', 'H' => '瘡', 'I' => '瘢', 'J' => '皚', 'K' => '皺', 'L' => '盤', 'M' => '瞎', 'N' => '瞇', 'O' => '瞌', 'P' => '瞑', 'Q' => '瞋', 'R' => '磋', 'S' => '磅', 'T' => '確', 'U' => '磊', 'V' => '碾', 'W' => '磕', 'X' => '碼', 'Y' => '磐', 'Z' => '稿', '[' => '稼', '\\' => '穀', ']' => '稽', '^' => '稷', '_' => '稻', '`' => '窯', 'a' => '窮', 'b' => '箭', 'c' => '箱', 'd' => '範', 'e' => '箴', 'f' => '篆', 'g' => '篇', 'h' => '篁', 'i' => '箠', 'j' => '篌', 'k' => '糊', 'l' => '締', 'm' => '練', 'n' => '緯', 'o' => '緻', 'p' => '緘', 'q' => '緬', 'r' => '緝', 's' => '編', 't' => '緣', 'u' => '線', 'v' => '緞', 'w' => '緩', 'x' => '綞', 'y' => '緙', 'z' => '緲', '{' => '緹', '|' => '罵', '}' => '罷', '~' => '羯', '' => '翩', '' => '耦', '' => '膛', '' => '膜', '' => '膝', '' => '膠', '' => '膚', '' => '膘', '' => '蔗', '' => '蔽', '' => '蔚', '' => '蓮', '' => '蔬', '' => '蔭', '' => '蔓', '' => '蔑', '' => '蔣', '' => '蔡', '' => '蔔', '' => '蓬', '' => '蔥', '' => '蓿', '' => '蔆', '' => '螂', '' => '蝴', '' => '蝶', '' => '蝠', '' => '蝦', '' => '蝸', '' => '蝨', '' => '蝙', '' => '蝗', '' => '蝌', '' => '蝓', '' => '衛', '' => '衝', '' => '褐', '' => '複', '' => '褒', '' => '褓', '' => '褕', '' => '褊', '' => '誼', '' => '諒', '' => '談', '' => '諄', '' => '誕', '' => '請', '' => '諸', '' => '課', '' => '諉', '' => '諂', '' => '調', '' => '誰', '' => '論', '' => '諍', '' => '誶', '' => '誹', '' => '諛', '' => '豌', '' => '豎', '' => '豬', '' => '賠', '' => '賞', '' => '賦', '' => '賤', '' => '賬', '' => '賭', '' => '賢', '' => '賣', '' => '賜', '' => '質', '' => '賡', '' => '赭', '' => '趟', '' => '趣', '' => '踫', '' => '踐', '' => '踝', '' => '踢', '' => '踏', '' => '踩', '' => '踟', '' => '踡', '' => '踞', '' => '躺', '' => '輝', '' => '輛', '' => '輟', '' => '輩', '' => '輦', '' => '輪', '' => '輜', '' => '輞', '@' => '輥', 'A' => '適', 'B' => '遮', 'C' => '遨', 'D' => '遭', 'E' => '遷', 'F' => '鄰', 'G' => '鄭', 'H' => '鄧', 'I' => '鄱', 'J' => '醇', 'K' => '醉', 'L' => '醋', 'M' => '醃', 'N' => '鋅', 'O' => '銻', 'P' => '銷', 'Q' => '鋪', 'R' => '銬', 'S' => '鋤', 'T' => '鋁', 'U' => '銳', 'V' => '銼', 'W' => '鋒', 'X' => '鋇', 'Y' => '鋰', 'Z' => '銲', '[' => '閭', '\\' => '閱', ']' => '霄', '^' => '霆', '_' => '震', '`' => '霉', 'a' => '靠', 'b' => '鞍', 'c' => '鞋', 'd' => '鞏', 'e' => '頡', 'f' => '頫', 'g' => '頜', 'h' => '颳', 'i' => '養', 'j' => '餓', 'k' => '餒', 'l' => '餘', 'm' => '駝', 'n' => '駐', 'o' => '駟', 'p' => '駛', 'q' => '駑', 'r' => '駕', 's' => '駒', 't' => '駙', 'u' => '骷', 'v' => '髮', 'w' => '髯', 'x' => '鬧', 'y' => '魅', 'z' => '魄', '{' => '魷', '|' => '魯', '}' => '鴆', '~' => '鴉', '' => '鴃', '' => '麩', '' => '麾', '' => '黎', '' => '墨', '' => '齒', '' => '儒', '' => '儘', '' => '儔', '' => '儐', '' => '儕', '' => '冀', '' => '冪', '' => '凝', '' => '劑', '' => '劓', '' => '勳', '' => '噙', '' => '噫', '' => '噹', '' => '噩', '' => '噤', '' => '噸', '' => '噪', '' => '器', '' => '噥', '' => '噱', '' => '噯', '' => '噬', '' => '噢', '' => '噶', '' => '壁', '' => '墾', '' => '壇', '' => '壅', '' => '奮', '' => '嬝', '' => '嬴', '' => '學', '' => '寰', '' => '導', '' => '彊', '' => '憲', '' => '憑', '' => '憩', '' => '憊', '' => '懍', '' => '憶', '' => '憾', '' => '懊', '' => '懈', '' => '戰', '' => '擅', '' => '擁', '' => '擋', '' => '撻', '' => '撼', '' => '據', '' => '擄', '' => '擇', '' => '擂', '' => '操', '' => '撿', '' => '擒', '' => '擔', '' => '撾', '' => '整', '' => '曆', '' => '曉', '' => '暹', '' => '曄', '' => '曇', '' => '暸', '' => '樽', '' => '樸', '' => '樺', '' => '橙', '' => '橫', '' => '橘', '' => '樹', '' => '橄', '' => '橢', '' => '橡', '' => '橋', '' => '橇', '' => '樵', '' => '機', '' => '橈', '' => '歙', '' => '歷', '' => '氅', '' => '濂', '' => '澱', '' => '澡', '@' => '濃', 'A' => '澤', 'B' => '濁', 'C' => '澧', 'D' => '澳', 'E' => '激', 'F' => '澹', 'G' => '澶', 'H' => '澦', 'I' => '澠', 'J' => '澴', 'K' => '熾', 'L' => '燉', 'M' => '燐', 'N' => '燒', 'O' => '燈', 'P' => '燕', 'Q' => '熹', 'R' => '燎', 'S' => '燙', 'T' => '燜', 'U' => '燃', 'V' => '燄', 'W' => '獨', 'X' => '璜', 'Y' => '璣', 'Z' => '璘', '[' => '璟', '\\' => '璞', ']' => '瓢', '^' => '甌', '_' => '甍', '`' => '瘴', 'a' => '瘸', 'b' => '瘺', 'c' => '盧', 'd' => '盥', 'e' => '瞠', 'f' => '瞞', 'g' => '瞟', 'h' => '瞥', 'i' => '磨', 'j' => '磚', 'k' => '磬', 'l' => '磧', 'm' => '禦', 'n' => '積', 'o' => '穎', 'p' => '穆', 'q' => '穌', 'r' => '穋', 's' => '窺', 't' => '篙', 'u' => '簑', 'v' => '築', 'w' => '篤', 'x' => '篛', 'y' => '篡', 'z' => '篩', '{' => '篦', '|' => '糕', '}' => '糖', '~' => '縊', '' => '縑', '' => '縈', '' => '縛', '' => '縣', '' => '縞', '' => '縝', '' => '縉', '' => '縐', '' => '罹', '' => '羲', '' => '翰', '' => '翱', '' => '翮', '' => '耨', '' => '膳', '' => '膩', '' => '膨', '' => '臻', '' => '興', '' => '艘', '' => '艙', '' => '蕊', '' => '蕙', '' => '蕈', '' => '蕨', '' => '蕩', '' => '蕃', '' => '蕉', '' => '蕭', '' => '蕪', '' => '蕞', '' => '螃', '' => '螟', '' => '螞', '' => '螢', '' => '融', '' => '衡', '' => '褪', '' => '褲', '' => '褥', '' => '褫', '' => '褡', '' => '親', '' => '覦', '' => '諦', '' => '諺', '' => '諫', '' => '諱', '' => '謀', '' => '諜', '' => '諧', '' => '諮', '' => '諾', '' => '謁', '' => '謂', '' => '諷', '' => '諭', '' => '諳', '' => '諶', '' => '諼', '' => '豫', '' => '豭', '' => '貓', '' => '賴', '' => '蹄', '' => '踱', '' => '踴', '' => '蹂', '' => '踹', '' => '踵', '' => '輻', '' => '輯', '' => '輸', '' => '輳', '' => '辨', '' => '辦', '' => '遵', '' => '遴', '' => '選', '' => '遲', '' => '遼', '' => '遺', '' => '鄴', '' => '醒', '' => '錠', '' => '錶', '' => '鋸', '' => '錳', '' => '錯', '' => '錢', '' => '鋼', '' => '錫', '' => '錄', '' => '錚', '@' => '錐', 'A' => '錦', 'B' => '錡', 'C' => '錕', 'D' => '錮', 'E' => '錙', 'F' => '閻', 'G' => '隧', 'H' => '隨', 'I' => '險', 'J' => '雕', 'K' => '霎', 'L' => '霑', 'M' => '霖', 'N' => '霍', 'O' => '霓', 'P' => '霏', 'Q' => '靛', 'R' => '靜', 'S' => '靦', 'T' => '鞘', 'U' => '頰', 'V' => '頸', 'W' => '頻', 'X' => '頷', 'Y' => '頭', 'Z' => '頹', '[' => '頤', '\\' => '餐', ']' => '館', '^' => '餞', '_' => '餛', '`' => '餡', 'a' => '餚', 'b' => '駭', 'c' => '駢', 'd' => '駱', 'e' => '骸', 'f' => '骼', 'g' => '髻', 'h' => '髭', 'i' => '鬨', 'j' => '鮑', 'k' => '鴕', 'l' => '鴣', 'm' => '鴦', 'n' => '鴨', 'o' => '鴒', 'p' => '鴛', 'q' => '默', 'r' => '黔', 's' => '龍', 't' => '龜', 'u' => '優', 'v' => '償', 'w' => '儡', 'x' => '儲', 'y' => '勵', 'z' => '嚎', '{' => '嚀', '|' => '嚐', '}' => '嚅', '~' => '嚇', '' => '嚏', '' => '壕', '' => '壓', '' => '壑', '' => '壎', '' => '嬰', '' => '嬪', '' => '嬤', '' => '孺', '' => '尷', '' => '屨', '' => '嶼', '' => '嶺', '' => '嶽', '' => '嶸', '' => '幫', '' => '彌', '' => '徽', '' => '應', '' => '懂', '' => '懇', '' => '懦', '' => '懋', '' => '戲', '' => '戴', '' => '擎', '' => '擊', '' => '擘', '' => '擠', '' => '擰', '' => '擦', '' => '擬', '' => '擱', '' => '擢', '' => '擭', '' => '斂', '' => '斃', '' => '曙', '' => '曖', '' => '檀', '' => '檔', '' => '檄', '' => '檢', '' => '檜', '' => '櫛', '' => '檣', '' => '橾', '' => '檗', '' => '檐', '' => '檠', '' => '歜', '' => '殮', '' => '毚', '' => '氈', '' => '濘', '' => '濱', '' => '濟', '' => '濠', '' => '濛', '' => '濤', '' => '濫', '' => '濯', '' => '澀', '' => '濬', '' => '濡', '' => '濩', '' => '濕', '' => '濮', '' => '濰', '' => '燧', '' => '營', '' => '燮', '' => '燦', '' => '燥', '' => '燭', '' => '燬', '' => '燴', '' => '燠', '' => '爵', '' => '牆', '' => '獰', '' => '獲', '' => '璩', '' => '環', '' => '璦', '' => '璨', '' => '癆', '' => '療', '' => '癌', '' => '盪', '' => '瞳', '' => '瞪', '' => '瞰', '' => '瞬', '@' => '瞧', 'A' => '瞭', 'B' => '矯', 'C' => '磷', 'D' => '磺', 'E' => '磴', 'F' => '磯', 'G' => '礁', 'H' => '禧', 'I' => '禪', 'J' => '穗', 'K' => '窿', 'L' => '簇', 'M' => '簍', 'N' => '篾', 'O' => '篷', 'P' => '簌', 'Q' => '篠', 'R' => '糠', 'S' => '糜', 'T' => '糞', 'U' => '糢', 'V' => '糟', 'W' => '糙', 'X' => '糝', 'Y' => '縮', 'Z' => '績', '[' => '繆', '\\' => '縷', ']' => '縲', '^' => '繃', '_' => '縫', '`' => '總', 'a' => '縱', 'b' => '繅', 'c' => '繁', 'd' => '縴', 'e' => '縹', 'f' => '繈', 'g' => '縵', 'h' => '縿', 'i' => '縯', 'j' => '罄', 'k' => '翳', 'l' => '翼', 'm' => '聱', 'n' => '聲', 'o' => '聰', 'p' => '聯', 'q' => '聳', 'r' => '臆', 's' => '臃', 't' => '膺', 'u' => '臂', 'v' => '臀', 'w' => '膿', 'x' => '膽', 'y' => '臉', 'z' => '膾', '{' => '臨', '|' => '舉', '}' => '艱', '~' => '薪', '' => '薄', '' => '蕾', '' => '薜', '' => '薑', '' => '薔', '' => '薯', '' => '薛', '' => '薇', '' => '薨', '' => '薊', '' => '虧', '' => '蟀', '' => '蟑', '' => '螳', '' => '蟒', '' => '蟆', '' => '螫', '' => '螻', '' => '螺', '' => '蟈', '' => '蟋', '' => '褻', '' => '褶', '' => '襄', '' => '褸', '' => '褽', '' => '覬', '' => '謎', '' => '謗', '' => '謙', '' => '講', '' => '謊', '' => '謠', '' => '謝', '' => '謄', '' => '謐', '' => '豁', '' => '谿', '' => '豳', '' => '賺', '' => '賽', '' => '購', '' => '賸', '' => '賻', '' => '趨', '' => '蹉', '' => '蹋', '' => '蹈', '' => '蹊', '' => '轄', '' => '輾', '' => '轂', '' => '轅', '' => '輿', '' => '避', '' => '遽', '' => '還', '' => '邁', '' => '邂', '' => '邀', '' => '鄹', '' => '醣', '' => '醞', '' => '醜', '' => '鍍', '' => '鎂', '' => '錨', '' => '鍵', '' => '鍊', '' => '鍥', '' => '鍋', '' => '錘', '' => '鍾', '' => '鍬', '' => '鍛', '' => '鍰', '' => '鍚', '' => '鍔', '' => '闊', '' => '闋', '' => '闌', '' => '闈', '' => '闆', '' => '隱', '' => '隸', '' => '雖', '' => '霜', '' => '霞', '' => '鞠', '' => '韓', '' => '顆', '' => '颶', '' => '餵', '' => '騁', '@' => '駿', 'A' => '鮮', 'B' => '鮫', 'C' => '鮪', 'D' => '鮭', 'E' => '鴻', 'F' => '鴿', 'G' => '麋', 'H' => '黏', 'I' => '點', 'J' => '黜', 'K' => '黝', 'L' => '黛', 'M' => '鼾', 'N' => '齋', 'O' => '叢', 'P' => '嚕', 'Q' => '嚮', 'R' => '壙', 'S' => '壘', 'T' => '嬸', 'U' => '彝', 'V' => '懣', 'W' => '戳', 'X' => '擴', 'Y' => '擲', 'Z' => '擾', '[' => '攆', '\\' => '擺', ']' => '擻', '^' => '擷', '_' => '斷', '`' => '曜', 'a' => '朦', 'b' => '檳', 'c' => '檬', 'd' => '櫃', 'e' => '檻', 'f' => '檸', 'g' => '櫂', 'h' => '檮', 'i' => '檯', 'j' => '歟', 'k' => '歸', 'l' => '殯', 'm' => '瀉', 'n' => '瀋', 'o' => '濾', 'p' => '瀆', 'q' => '濺', 'r' => '瀑', 's' => '瀏', 't' => '燻', 'u' => '燼', 'v' => '燾', 'w' => '燸', 'x' => '獷', 'y' => '獵', 'z' => '璧', '{' => '璿', '|' => '甕', '}' => '癖', '~' => '癘', '¡' => '癒', '¢' => '瞽', '£' => '瞿', '¤' => '瞻', '¥' => '瞼', '¦' => '礎', '§' => '禮', '¨' => '穡', '©' => '穢', 'ª' => '穠', '«' => '竄', '¬' => '竅', '­' => '簫', '®' => '簧', '¯' => '簪', '°' => '簞', '±' => '簣', '²' => '簡', '³' => '糧', '´' => '織', 'µ' => '繕', '¶' => '繞', '·' => '繚', '¸' => '繡', '¹' => '繒', 'º' => '繙', '»' => '罈', '¼' => '翹', '½' => '翻', '¾' => '職', '¿' => '聶', '' => '臍', '' => '臏', '' => '舊', '' => '藏', '' => '薩', '' => '藍', '' => '藐', '' => '藉', '' => '薰', '' => '薺', '' => '薹', '' => '薦', '' => '蟯', '' => '蟬', '' => '蟲', '' => '蟠', '' => '覆', '' => '覲', '' => '觴', '' => '謨', '' => '謹', '' => '謬', '' => '謫', '' => '豐', '' => '贅', '' => '蹙', '' => '蹣', '' => '蹦', '' => '蹤', '' => '蹟', '' => '蹕', '' => '軀', '' => '轉', '' => '轍', '' => '邇', '' => '邃', '' => '邈', '' => '醫', '' => '醬', '' => '釐', '' => '鎔', '' => '鎊', '' => '鎖', '' => '鎢', '' => '鎳', '' => '鎮', '' => '鎬', '' => '鎰', '' => '鎘', '' => '鎚', '' => '鎗', '' => '闔', '' => '闖', '' => '闐', '' => '闕', '' => '離', '' => '雜', '' => '雙', '' => '雛', '' => '雞', '' => '霤', '' => '鞣', '' => '鞦', '@' => '鞭', 'A' => '韹', 'B' => '額', 'C' => '顏', 'D' => '題', 'E' => '顎', 'F' => '顓', 'G' => '颺', 'H' => '餾', 'I' => '餿', 'J' => '餽', 'K' => '餮', 'L' => '馥', 'M' => '騎', 'N' => '髁', 'O' => '鬃', 'P' => '鬆', 'Q' => '魏', 'R' => '魎', 'S' => '魍', 'T' => '鯊', 'U' => '鯉', 'V' => '鯽', 'W' => '鯈', 'X' => '鯀', 'Y' => '鵑', 'Z' => '鵝', '[' => '鵠', '\\' => '黠', ']' => '鼕', '^' => '鼬', '_' => '儳', '`' => '嚥', 'a' => '壞', 'b' => '壟', 'c' => '壢', 'd' => '寵', 'e' => '龐', 'f' => '廬', 'g' => '懲', 'h' => '懷', 'i' => '懶', 'j' => '懵', 'k' => '攀', 'l' => '攏', 'm' => '曠', 'n' => '曝', 'o' => '櫥', 'p' => '櫝', 'q' => '櫚', 'r' => '櫓', 's' => '瀛', 't' => '瀟', 'u' => '瀨', 'v' => '瀚', 'w' => '瀝', 'x' => '瀕', 'y' => '瀘', 'z' => '爆', '{' => '爍', '|' => '牘', '}' => '犢', '~' => '獸', 'á' => '獺', 'â' => '璽', 'ã' => '瓊', 'ä' => '瓣', 'å' => '疇', 'æ' => '疆', 'ç' => '癟', 'è' => '癡', 'é' => '矇', 'ê' => '礙', 'ë' => '禱', 'ì' => '穫', 'í' => '穩', 'î' => '簾', 'ï' => '簿', 'ð' => '簸', 'ñ' => '簽', 'ò' => '簷', 'ó' => '籀', 'ô' => '繫', 'õ' => '繭', 'ö' => '繹', '÷' => '繩', 'ø' => '繪', 'ù' => '羅', 'ú' => '繳', 'û' => '羶', 'ü' => '羹', 'ý' => '羸', 'þ' => '臘', 'ÿ' => '藩', '' => '藝', '' => '藪', '' => '藕', '' => '藤', '' => '藥', '' => '藷', '' => '蟻', '' => '蠅', '' => '蠍', '' => '蟹', '' => '蟾', '' => '襠', '' => '襟', '' => '襖', '' => '襞', '' => '譁', '' => '譜', '' => '識', '' => '證', '' => '譚', '' => '譎', '' => '譏', '' => '譆', '' => '譙', '' => '贈', '' => '贊', '' => '蹼', '' => '蹲', '' => '躇', '' => '蹶', '' => '蹬', '' => '蹺', '' => '蹴', '' => '轔', '' => '轎', '' => '辭', '' => '邊', '' => '邋', '' => '醱', '' => '醮', '' => '鏡', '' => '鏑', '' => '鏟', '' => '鏃', '' => '鏈', '' => '鏜', '' => '鏝', '' => '鏖', '' => '鏢', '' => '鏍', '' => '鏘', '' => '鏤', '' => '鏗', '' => '鏨', '' => '關', '' => '隴', '' => '難', '' => '霪', '' => '霧', '' => '靡', '' => '韜', '' => '韻', '' => '類', '@' => '願', 'A' => '顛', 'B' => '颼', 'C' => '饅', 'D' => '饉', 'E' => '騖', 'F' => '騙', 'G' => '鬍', 'H' => '鯨', 'I' => '鯧', 'J' => '鯖', 'K' => '鯛', 'L' => '鶉', 'M' => '鵡', 'N' => '鵲', 'O' => '鵪', 'P' => '鵬', 'Q' => '麒', 'R' => '麗', 'S' => '麓', 'T' => '麴', 'U' => '勸', 'V' => '嚨', 'W' => '嚷', 'X' => '嚶', 'Y' => '嚴', 'Z' => '嚼', '[' => '壤', '\\' => '孀', ']' => '孃', '^' => '孽', '_' => '寶', '`' => '巉', 'a' => '懸', 'b' => '懺', 'c' => '攘', 'd' => '攔', 'e' => '攙', 'f' => '曦', 'g' => '朧', 'h' => '櫬', 'i' => '瀾', 'j' => '瀰', 'k' => '瀲', 'l' => '爐', 'm' => '獻', 'n' => '瓏', 'o' => '癢', 'p' => '癥', 'q' => '礦', 'r' => '礪', 's' => '礬', 't' => '礫', 'u' => '竇', 'v' => '競', 'w' => '籌', 'x' => '籃', 'y' => '籍', 'z' => '糯', '{' => '糰', '|' => '辮', '}' => '繽', '~' => '繼', 'ġ' => '纂', 'Ģ' => '罌', 'ģ' => '耀', 'Ĥ' => '臚', 'ĥ' => '艦', 'Ħ' => '藻', 'ħ' => '藹', 'Ĩ' => '蘑', 'ĩ' => '藺', 'Ī' => '蘆', 'ī' => '蘋', 'Ĭ' => '蘇', 'ĭ' => '蘊', 'Į' => '蠔', 'į' => '蠕', 'İ' => '襤', 'ı' => '覺', 'IJ' => '觸', 'ij' => '議', 'Ĵ' => '譬', 'ĵ' => '警', 'Ķ' => '譯', 'ķ' => '譟', 'ĸ' => '譫', 'Ĺ' => '贏', 'ĺ' => '贍', 'Ļ' => '躉', 'ļ' => '躁', 'Ľ' => '躅', 'ľ' => '躂', 'Ŀ' => '醴', '' => '釋', '' => '鐘', '' => '鐃', '' => '鏽', '' => '闡', '' => '霰', '' => '飄', '' => '饒', '' => '饑', '' => '馨', '' => '騫', '' => '騰', '' => '騷', '' => '騵', '' => '鰓', '' => '鰍', '' => '鹹', '' => '麵', '' => '黨', '' => '鼯', '' => '齟', '' => '齣', '' => '齡', '' => '儷', '' => '儸', '' => '囁', '' => '囀', '' => '囂', '' => '夔', '' => '屬', '' => '巍', '' => '懼', '' => '懾', '' => '攝', '' => '攜', '' => '斕', '' => '曩', '' => '櫻', '' => '欄', '' => '櫺', '' => '殲', '' => '灌', '' => '爛', '' => '犧', '' => '瓖', '' => '瓔', '' => '癩', '' => '矓', '' => '籐', '' => '纏', '' => '續', '' => '羼', '' => '蘗', '' => '蘭', '' => '蘚', '' => '蠣', '' => '蠢', '' => '蠡', '' => '蠟', '' => '襪', '' => '襬', '' => '覽', '' => '譴', '@' => '護', 'A' => '譽', 'B' => '贓', 'C' => '躊', 'D' => '躍', 'E' => '躋', 'F' => '轟', 'G' => '辯', 'H' => '醺', 'I' => '鐮', 'J' => '鐳', 'K' => '鐵', 'L' => '鐺', 'M' => '鐸', 'N' => '鐲', 'O' => '鐫', 'P' => '闢', 'Q' => '霸', 'R' => '霹', 'S' => '露', 'T' => '響', 'U' => '顧', 'V' => '顥', 'W' => '饗', 'X' => '驅', 'Y' => '驃', 'Z' => '驀', '[' => '騾', '\\' => '髏', ']' => '魔', '^' => '魑', '_' => '鰭', '`' => '鰥', 'a' => '鶯', 'b' => '鶴', 'c' => '鷂', 'd' => '鶸', 'e' => '麝', 'f' => '黯', 'g' => '鼙', 'h' => '齜', 'i' => '齦', 'j' => '齧', 'k' => '儼', 'l' => '儻', 'm' => '囈', 'n' => '囊', 'o' => '囉', 'p' => '孿', 'q' => '巔', 'r' => '巒', 's' => '彎', 't' => '懿', 'u' => '攤', 'v' => '權', 'w' => '歡', 'x' => '灑', 'y' => '灘', 'z' => '玀', '{' => '瓤', '|' => '疊', '}' => '癮', '~' => '癬', 'š' => '禳', 'Ţ' => '籠', 'ţ' => '籟', 'Ť' => '聾', 'ť' => '聽', 'Ŧ' => '臟', 'ŧ' => '襲', 'Ũ' => '襯', 'ũ' => '觼', 'Ū' => '讀', 'ū' => '贖', 'Ŭ' => '贗', 'ŭ' => '躑', 'Ů' => '躓', 'ů' => '轡', 'Ű' => '酈', 'ű' => '鑄', 'Ų' => '鑑', 'ų' => '鑒', 'Ŵ' => '霽', 'ŵ' => '霾', 'Ŷ' => '韃', 'ŷ' => '韁', 'Ÿ' => '顫', 'Ź' => '饕', 'ź' => '驕', 'Ż' => '驍', 'ż' => '髒', 'Ž' => '鬚', 'ž' => '鱉', 'ſ' => '鰱', '' => '鰾', '' => '鰻', '' => '鷓', '' => '鷗', '' => '鼴', '' => '齬', '' => '齪', '' => '龔', '' => '囌', '' => '巖', '' => '戀', '' => '攣', '' => '攫', '' => '攪', '' => '曬', '' => '欐', '' => '瓚', '' => '竊', '' => '籤', '' => '籣', '' => '籥', '' => '纓', '' => '纖', '' => '纔', '' => '臢', '' => '蘸', '' => '蘿', '' => '蠱', '' => '變', '' => '邐', '' => '邏', '' => '鑣', '' => '鑠', '' => '鑤', '' => '靨', '' => '顯', '' => '饜', '' => '驚', '' => '驛', '' => '驗', '' => '髓', '' => '體', '' => '髑', '' => '鱔', '' => '鱗', '' => '鱖', '' => '鷥', '' => '麟', '' => '黴', '' => '囑', '' => '壩', '' => '攬', '' => '灞', '' => '癱', '' => '癲', '' => '矗', '' => '罐', '' => '羈', '' => '蠶', '' => '蠹', '' => '衢', '' => '讓', '' => '讒', '@' => '讖', 'A' => '艷', 'B' => '贛', 'C' => '釀', 'D' => '鑪', 'E' => '靂', 'F' => '靈', 'G' => '靄', 'H' => '韆', 'I' => '顰', 'J' => '驟', 'K' => '鬢', 'L' => '魘', 'M' => '鱟', 'N' => '鷹', 'O' => '鷺', 'P' => '鹼', 'Q' => '鹽', 'R' => '鼇', 'S' => '齷', 'T' => '齲', 'U' => '廳', 'V' => '欖', 'W' => '灣', 'X' => '籬', 'Y' => '籮', 'Z' => '蠻', '[' => '觀', '\\' => '躡', ']' => '釁', '^' => '鑲', '_' => '鑰', '`' => '顱', 'a' => '饞', 'b' => '髖', 'c' => '鬣', 'd' => '黌', 'e' => '灤', 'f' => '矚', 'g' => '讚', 'h' => '鑷', 'i' => '韉', 'j' => '驢', 'k' => '驥', 'l' => '纜', 'm' => '讜', 'n' => '躪', 'o' => '釅', 'p' => '鑽', 'q' => '鑾', 'r' => '鑼', 's' => '鱷', 't' => '鱸', 'u' => '黷', 'v' => '豔', 'w' => '鑿', 'x' => '鸚', 'y' => '爨', 'z' => '驪', '{' => '鬱', '|' => '鸛', '}' => '鸞', '~' => '籲', 'ơ' => 'ヾ', 'Ƣ' => 'ゝ', 'ƣ' => 'ゞ', 'Ƥ' => '々', 'ƥ' => 'ぁ', 'Ʀ' => 'あ', 'Ƨ' => 'ぃ', 'ƨ' => 'い', 'Ʃ' => 'ぅ', 'ƪ' => 'う', 'ƫ' => 'ぇ', 'Ƭ' => 'え', 'ƭ' => 'ぉ', 'Ʈ' => 'お', 'Ư' => 'か', 'ư' => 'が', 'Ʊ' => 'き', 'Ʋ' => 'ぎ', 'Ƴ' => 'く', 'ƴ' => 'ぐ', 'Ƶ' => 'け', 'ƶ' => 'げ', 'Ʒ' => 'こ', 'Ƹ' => 'ご', 'ƹ' => 'さ', 'ƺ' => 'ざ', 'ƻ' => 'し', 'Ƽ' => 'じ', 'ƽ' => 'す', 'ƾ' => 'ず', 'ƿ' => 'せ', '' => 'ぜ', '' => 'そ', '' => 'ぞ', '' => 'た', '' => 'だ', '' => 'ち', '' => 'ぢ', '' => 'っ', '' => 'つ', '' => 'づ', '' => 'て', '' => 'で', '' => 'と', '' => 'ど', '' => 'な', '' => 'に', '' => 'ぬ', '' => 'ね', '' => 'の', '' => 'は', '' => 'ば', '' => 'ぱ', '' => 'ひ', '' => 'び', '' => 'ぴ', '' => 'ふ', '' => 'ぶ', '' => 'ぷ', '' => 'へ', '' => 'べ', '' => 'ぺ', '' => 'ほ', '' => 'ぼ', '' => 'ぽ', '' => 'ま', '' => 'み', '' => 'む', '' => 'め', '' => 'も', '' => 'ゃ', '' => 'や', '' => 'ゅ', '' => 'ゆ', '' => 'ょ', '' => 'よ', '' => 'ら', '' => 'り', '' => 'る', '' => 'れ', '' => 'ろ', '' => 'ゎ', '' => 'わ', '' => 'ゐ', '' => 'ゑ', '' => 'を', '' => 'ん', '' => 'ァ', '' => 'ア', '' => 'ィ', '' => 'イ', '' => 'ゥ', '' => 'ウ', '' => 'ェ', '@' => 'エ', 'A' => 'ォ', 'B' => 'オ', 'C' => 'カ', 'D' => 'ガ', 'E' => 'キ', 'F' => 'ギ', 'G' => 'ク', 'H' => 'グ', 'I' => 'ケ', 'J' => 'ゲ', 'K' => 'コ', 'L' => 'ゴ', 'M' => 'サ', 'N' => 'ザ', 'O' => 'シ', 'P' => 'ジ', 'Q' => 'ス', 'R' => 'ズ', 'S' => 'セ', 'T' => 'ゼ', 'U' => 'ソ', 'V' => 'ゾ', 'W' => 'タ', 'X' => 'ダ', 'Y' => 'チ', 'Z' => 'ヂ', '[' => 'ッ', '\\' => 'ツ', ']' => 'ヅ', '^' => 'テ', '_' => 'デ', '`' => 'ト', 'a' => 'ド', 'b' => 'ナ', 'c' => 'ニ', 'd' => 'ヌ', 'e' => 'ネ', 'f' => 'ノ', 'g' => 'ハ', 'h' => 'バ', 'i' => 'パ', 'j' => 'ヒ', 'k' => 'ビ', 'l' => 'ピ', 'm' => 'フ', 'n' => 'ブ', 'o' => 'プ', 'p' => 'ヘ', 'q' => 'ベ', 'r' => 'ペ', 's' => 'ホ', 't' => 'ボ', 'u' => 'ポ', 'v' => 'マ', 'w' => 'ミ', 'x' => 'ム', 'y' => 'メ', 'z' => 'モ', '{' => 'ャ', '|' => 'ヤ', '}' => 'ュ', '~' => 'ユ', 'ǡ' => 'ョ', 'Ǣ' => 'ヨ', 'ǣ' => 'ラ', 'Ǥ' => 'リ', 'ǥ' => 'ル', 'Ǧ' => 'レ', 'ǧ' => 'ロ', 'Ǩ' => 'ヮ', 'ǩ' => 'ワ', 'Ǫ' => 'ヰ', 'ǫ' => 'ヱ', 'Ǭ' => 'ヲ', 'ǭ' => 'ン', 'Ǯ' => 'ヴ', 'ǯ' => 'ヵ', 'ǰ' => 'ヶ', 'DZ' => 'Д', 'Dz' => 'Е', 'dz' => 'Ё', 'Ǵ' => 'Ж', 'ǵ' => 'З', 'Ƕ' => 'И', 'Ƿ' => 'Й', 'Ǹ' => 'К', 'ǹ' => 'Л', 'Ǻ' => 'М', 'ǻ' => 'У', 'Ǽ' => 'Ф', 'ǽ' => 'Х', 'Ǿ' => 'Ц', 'ǿ' => 'Ч', '' => 'Ш', '' => 'Щ', '' => 'Ъ', '' => 'Ы', '' => 'Ь', '' => 'Э', '' => 'Ю', '' => 'Я', '' => 'а', '' => 'б', '' => 'в', '' => 'г', '' => 'д', '' => 'е', '' => 'ё', '' => 'ж', '' => 'з', '' => 'и', '' => 'й', '' => 'к', '' => 'л', '' => 'м', '' => 'н', '' => 'о', '' => 'п', '' => 'р', '' => 'с', '' => 'т', '' => 'у', '' => 'ф', '' => 'х', '' => 'ц', '' => 'ч', '' => 'ш', '' => 'щ', '' => 'ъ', '' => 'ы', '' => 'ь', '' => 'э', '' => 'ю', '' => 'я', '' => '①', '' => '②', '' => '③', '' => '④', '' => '⑤', '' => '⑥', '' => '⑦', '' => '⑧', '' => '⑨', '' => '⑩', '' => '⑴', '' => '⑵', '' => '⑶', '' => '⑷', '' => '⑸', '' => '⑹', '' => '⑺', '' => '⑻', '' => '⑼', '' => '⑽', '@' => '乂', 'A' => '乜', 'B' => '凵', 'C' => '匚', 'D' => '厂', 'E' => '万', 'F' => '丌', 'G' => '乇', 'H' => '亍', 'I' => '囗', 'J' => '兀', 'K' => '屮', 'L' => '彳', 'M' => '丏', 'N' => '冇', 'O' => '与', 'P' => '丮', 'Q' => '亓', 'R' => '仂', 'S' => '仉', 'T' => '仈', 'U' => '冘', 'V' => '勼', 'W' => '卬', 'X' => '厹', 'Y' => '圠', 'Z' => '夃', '[' => '夬', '\\' => '尐', ']' => '巿', '^' => '旡', '_' => '殳', '`' => '毌', 'a' => '气', 'b' => '爿', 'c' => '丱', 'd' => '丼', 'e' => '仨', 'f' => '仜', 'g' => '仩', 'h' => '仡', 'i' => '仝', 'j' => '仚', 'k' => '刌', 'l' => '匜', 'm' => '卌', 'n' => '圢', 'o' => '圣', 'p' => '夗', 'q' => '夯', 'r' => '宁', 's' => '宄', 't' => '尒', 'u' => '尻', 'v' => '屴', 'w' => '屳', 'x' => '帄', 'y' => '庀', 'z' => '庂', '{' => '忉', '|' => '戉', '}' => '扐', '~' => '氕', 'ɡ' => '氶', 'ɢ' => '汃', 'ɣ' => '氿', 'ɤ' => '氻', 'ɥ' => '犮', 'ɦ' => '犰', 'ɧ' => '玊', 'ɨ' => '禸', 'ɩ' => '肊', 'ɪ' => '阞', 'ɫ' => '伎', 'ɬ' => '优', 'ɭ' => '伬', 'ɮ' => '仵', 'ɯ' => '伔', 'ɰ' => '仱', 'ɱ' => '伀', 'ɲ' => '价', 'ɳ' => '伈', 'ɴ' => '伝', 'ɵ' => '伂', 'ɶ' => '伅', 'ɷ' => '伢', 'ɸ' => '伓', 'ɹ' => '伄', 'ɺ' => '仴', 'ɻ' => '伒', 'ɼ' => '冱', 'ɽ' => '刓', 'ɾ' => '刉', 'ɿ' => '刐', '' => '劦', '' => '匢', '' => '匟', '' => '卍', '' => '厊', '' => '吇', '' => '囡', '' => '囟', '' => '圮', '' => '圪', '' => '圴', '' => '夼', '' => '妀', '' => '奼', '' => '妅', '' => '奻', '' => '奾', '' => '奷', '' => '奿', '' => '孖', '' => '尕', '' => '尥', '' => '屼', '' => '屺', '' => '屻', '' => '屾', '' => '巟', '' => '幵', '' => '庄', '' => '异', '' => '弚', '' => '彴', '' => '忕', '' => '忔', '' => '忏', '' => '扜', '' => '扞', '' => '扤', '' => '扡', '' => '扦', '' => '扢', '' => '扙', '' => '扠', '' => '扚', '' => '扥', '' => '旯', '' => '旮', '' => '朾', '' => '朹', '' => '朸', '' => '朻', '' => '机', '' => '朿', '' => '朼', '' => '朳', '' => '氘', '' => '汆', '' => '汒', '' => '汜', '' => '汏', '' => '汊', '' => '汔', '' => '汋', '@' => '汌', 'A' => '灱', 'B' => '牞', 'C' => '犴', 'D' => '犵', 'E' => '玎', 'F' => '甪', 'G' => '癿', 'H' => '穵', 'I' => '网', 'J' => '艸', 'K' => '艼', 'L' => '芀', 'M' => '艽', 'N' => '艿', 'O' => '虍', 'P' => '襾', 'Q' => '邙', 'R' => '邗', 'S' => '邘', 'T' => '邛', 'U' => '邔', 'V' => '阢', 'W' => '阤', 'X' => '阠', 'Y' => '阣', 'Z' => '佖', '[' => '伻', '\\' => '佢', ']' => '佉', '^' => '体', '_' => '佤', '`' => '伾', 'a' => '佧', 'b' => '佒', 'c' => '佟', 'd' => '佁', 'e' => '佘', 'f' => '伭', 'g' => '伳', 'h' => '伿', 'i' => '佡', 'j' => '冏', 'k' => '冹', 'l' => '刜', 'm' => '刞', 'n' => '刡', 'o' => '劭', 'p' => '劮', 'q' => '匉', 'r' => '卣', 's' => '卲', 't' => '厎', 'u' => '厏', 'v' => '吰', 'w' => '吷', 'x' => '吪', 'y' => '呔', 'z' => '呅', '{' => '吙', '|' => '吜', '}' => '吥', '~' => '吘', 'ʡ' => '吽', 'ʢ' => '呏', 'ʣ' => '呁', 'ʤ' => '吨', 'ʥ' => '吤', 'ʦ' => '呇', 'ʧ' => '囮', 'ʨ' => '囧', 'ʩ' => '囥', 'ʪ' => '坁', 'ʫ' => '坅', 'ʬ' => '坌', 'ʭ' => '坉', 'ʮ' => '坋', 'ʯ' => '坒', 'ʰ' => '夆', 'ʱ' => '奀', 'ʲ' => '妦', 'ʳ' => '妘', 'ʴ' => '妠', 'ʵ' => '妗', 'ʶ' => '妎', 'ʷ' => '妢', 'ʸ' => '妐', 'ʹ' => '妏', 'ʺ' => '妧', 'ʻ' => '妡', 'ʼ' => '宎', 'ʽ' => '宒', 'ʾ' => '尨', 'ʿ' => '尪', '' => '岍', '' => '岏', '' => '岈', '' => '岋', '' => '岉', '' => '岒', '' => '岊', '' => '岆', '' => '岓', '' => '岕', '' => '巠', '' => '帊', '' => '帎', '' => '庋', '' => '庉', '' => '庌', '' => '庈', '' => '庍', '' => '弅', '' => '弝', '' => '彸', '' => '彶', '' => '忒', '' => '忑', '' => '忐', '' => '忭', '' => '忨', '' => '忮', '' => '忳', '' => '忡', '' => '忤', '' => '忣', '' => '忺', '' => '忯', '' => '忷', '' => '忻', '' => '怀', '' => '忴', '' => '戺', '' => '抃', '' => '抌', '' => '抎', '' => '抏', '' => '抔', '' => '抇', '' => '扱', '' => '扻', '' => '扺', '' => '扰', '' => '抁', '' => '抈', '' => '扷', '' => '扽', '' => '扲', '' => '扴', '' => '攷', '' => '旰', '' => '旴', '' => '旳', '' => '旲', '' => '旵', '' => '杅', '' => '杇', '@' => '杙', 'A' => '杕', 'B' => '杌', 'C' => '杈', 'D' => '杝', 'E' => '杍', 'F' => '杚', 'G' => '杋', 'H' => '毐', 'I' => '氙', 'J' => '氚', 'K' => '汸', 'L' => '汧', 'M' => '汫', 'N' => '沄', 'O' => '沋', 'P' => '沏', 'Q' => '汱', 'R' => '汯', 'S' => '汩', 'T' => '沚', 'U' => '汭', 'V' => '沇', 'W' => '沕', 'X' => '沜', 'Y' => '汦', 'Z' => '汳', '[' => '汥', '\\' => '汻', ']' => '沎', '^' => '灴', '_' => '灺', '`' => '牣', 'a' => '犿', 'b' => '犽', 'c' => '狃', 'd' => '狆', 'e' => '狁', 'f' => '犺', 'g' => '狅', 'h' => '玕', 'i' => '玗', 'j' => '玓', 'k' => '玔', 'l' => '玒', 'm' => '町', 'n' => '甹', 'o' => '疔', 'p' => '疕', 'q' => '皁', 'r' => '礽', 's' => '耴', 't' => '肕', 'u' => '肙', 'v' => '肐', 'w' => '肒', 'x' => '肜', 'y' => '芐', 'z' => '芏', '{' => '芅', '|' => '芎', '}' => '芑', '~' => '芓', 'ˡ' => '芊', 'ˢ' => '芃', 'ˣ' => '芄', 'ˤ' => '豸', '˥' => '迉', '˦' => '辿', '˧' => '邟', '˨' => '邡', '˩' => '邥', '˪' => '邞', '˫' => '邧', 'ˬ' => '邠', '˭' => '阰', 'ˮ' => '阨', '˯' => '阯', '˰' => '阭', '˱' => '丳', '˲' => '侘', '˳' => '佼', '˴' => '侅', '˵' => '佽', '˶' => '侀', '˷' => '侇', '˸' => '佶', '˹' => '佴', '˺' => '侉', '˻' => '侄', '˼' => '佷', '˽' => '佌', '˾' => '侗', '˿' => '佪', '' => '侚', '' => '佹', '' => '侁', '' => '佸', '' => '侐', '' => '侜', '' => '侔', '' => '侞', '' => '侒', '' => '侂', '' => '侕', '' => '佫', '' => '佮', '' => '冞', '' => '冼', '' => '冾', '' => '刵', '' => '刲', '' => '刳', '' => '剆', '' => '刱', '' => '劼', '' => '匊', '' => '匋', '' => '匼', '' => '厒', '' => '厔', '' => '咇', '' => '呿', '' => '咁', '' => '咑', '' => '咂', '' => '咈', '' => '呫', '' => '呺', '' => '呾', '' => '呥', '' => '呬', '' => '呴', '' => '呦', '' => '咍', '' => '呯', '' => '呡', '' => '呠', '' => '咘', '' => '呣', '' => '呧', '' => '呤', '' => '囷', '' => '囹', '' => '坯', '' => '坲', '' => '坭', '' => '坫', '' => '坱', '' => '坰', '' => '坶', '' => '垀', '' => '坵', '' => '坻', '' => '坳', '' => '坴', '' => '坢', '@' => '坨', 'A' => '坽', 'B' => '夌', 'C' => '奅', 'D' => '妵', 'E' => '妺', 'F' => '姏', 'G' => '姎', 'H' => '妲', 'I' => '姌', 'J' => '姁', 'K' => '妶', 'L' => '妼', 'M' => '姃', 'N' => '姖', 'O' => '妱', 'P' => '妽', 'Q' => '姀', 'R' => '姈', 'S' => '妴', 'T' => '姇', 'U' => '孢', 'V' => '孥', 'W' => '宓', 'X' => '宕', 'Y' => '屄', 'Z' => '屇', '[' => '岮', '\\' => '岤', ']' => '岠', '^' => '岵', '_' => '岯', '`' => '岨', 'a' => '岬', 'b' => '岟', 'c' => '岣', 'd' => '岭', 'e' => '岢', 'f' => '岪', 'g' => '岧', 'h' => '岝', 'i' => '岥', 'j' => '岶', 'k' => '岰', 'l' => '岦', 'm' => '帗', 'n' => '帔', 'o' => '帙', 'p' => '弨', 'q' => '弢', 'r' => '弣', 's' => '弤', 't' => '彔', 'u' => '徂', 'v' => '彾', 'w' => '彽', 'x' => '忞', 'y' => '忥', 'z' => '怭', '{' => '怦', '|' => '怙', '}' => '怲', '~' => '怋', '̡' => '怴', '̢' => '怊', '̣' => '怗', '̤' => '怳', '̥' => '怚', '̦' => '怞', '̧' => '怬', '̨' => '怢', '̩' => '怍', '̪' => '怐', '̫' => '怮', '̬' => '怓', '̭' => '怑', '̮' => '怌', '̯' => '怉', '̰' => '怜', '̱' => '戔', '̲' => '戽', '̳' => '抭', '̴' => '抴', '̵' => '拑', '̶' => '抾', '̷' => '抪', '̸' => '抶', '̹' => '拊', '̺' => '抮', '̻' => '抳', '̼' => '抯', '̽' => '抻', '̾' => '抩', '̿' => '抰', '' => '抸', '' => '攽', '' => '斨', '' => '斻', '' => '昉', '' => '旼', '' => '昄', '' => '昒', '' => '昈', '' => '旻', '' => '昃', '' => '昋', '' => '昍', '' => '昅', '' => '旽', '' => '昑', '' => '昐', '' => '曶', '' => '朊', '' => '枅', '' => '杬', '' => '枎', '' => '枒', '' => '杶', '' => '杻', '' => '枘', '' => '枆', '' => '构', '' => '杴', '' => '枍', '' => '枌', '' => '杺', '' => '枟', '' => '枑', '' => '枙', '' => '枃', '' => '杽', '' => '极', '' => '杸', '' => '杹', '' => '枔', '' => '欥', '' => '殀', '' => '歾', '' => '毞', '' => '氝', '' => '沓', '' => '泬', '' => '泫', '' => '泮', '' => '泙', '' => '沶', '' => '泔', '' => '沭', '' => '泧', '' => '沷', '' => '泐', '' => '泂', '' => '沺', '' => '泃', '' => '泆', '' => '泭', '' => '泲', '@' => '泒', 'A' => '泝', 'B' => '沴', 'C' => '沊', 'D' => '沝', 'E' => '沀', 'F' => '泞', 'G' => '泀', 'H' => '洰', 'I' => '泍', 'J' => '泇', 'K' => '沰', 'L' => '泹', 'M' => '泏', 'N' => '泩', 'O' => '泑', 'P' => '炔', 'Q' => '炘', 'R' => '炅', 'S' => '炓', 'T' => '炆', 'U' => '炄', 'V' => '炑', 'W' => '炖', 'X' => '炂', 'Y' => '炚', 'Z' => '炃', '[' => '牪', '\\' => '狖', ']' => '狋', '^' => '狘', '_' => '狉', '`' => '狜', 'a' => '狒', 'b' => '狔', 'c' => '狚', 'd' => '狌', 'e' => '狑', 'f' => '玤', 'g' => '玡', 'h' => '玭', 'i' => '玦', 'j' => '玢', 'k' => '玠', 'l' => '玬', 'm' => '玝', 'n' => '瓝', 'o' => '瓨', 'p' => '甿', 'q' => '畀', 'r' => '甾', 's' => '疌', 't' => '疘', 'u' => '皯', 'v' => '盳', 'w' => '盱', 'x' => '盰', 'y' => '盵', 'z' => '矸', '{' => '矼', '|' => '矹', '}' => '矻', '~' => '矺', '͡' => '矷', '͢' => '祂', 'ͣ' => '礿', 'ͤ' => '秅', 'ͥ' => '穸', 'ͦ' => '穻', 'ͧ' => '竻', 'ͨ' => '籵', 'ͩ' => '糽', 'ͪ' => '耵', 'ͫ' => '肏', 'ͬ' => '肮', 'ͭ' => '肣', 'ͮ' => '肸', 'ͯ' => '肵', 'Ͱ' => '肭', 'ͱ' => '舠', 'Ͳ' => '芠', 'ͳ' => '苀', 'ʹ' => '芫', '͵' => '芚', 'Ͷ' => '芘', 'ͷ' => '芛', '͸' => '芵', '͹' => '芧', 'ͺ' => '芮', 'ͻ' => '芼', 'ͼ' => '芞', 'ͽ' => '芺', ';' => '芴', 'Ϳ' => '芨', '' => '芡', '' => '芩', '' => '苂', '' => '芤', '' => '苃', '' => '芶', '' => '芢', '' => '虰', '' => '虯', '' => '虭', '' => '虮', '' => '豖', '' => '迒', '' => '迋', '' => '迓', '' => '迍', '' => '迖', '' => '迕', '' => '迗', '' => '邲', '' => '邴', '' => '邯', '' => '邳', '' => '邰', '' => '阹', '' => '阽', '' => '阼', '' => '阺', '' => '陃', '' => '俍', '' => '俅', '' => '俓', '' => '侲', '' => '俉', '' => '俋', '' => '俁', '' => '俔', '' => '俜', '' => '俙', '' => '侻', '' => '侳', '' => '俛', '' => '俇', '' => '俖', '' => '侺', '' => '俀', '' => '侹', '' => '俬', '' => '剄', '' => '剉', '' => '勀', '' => '勂', '' => '匽', '' => '卼', '' => '厗', '' => '厖', '' => '厙', '' => '厘', '' => '咺', '' => '咡', '' => '咭', '' => '咥', '' => '哏', '@' => '哃', 'A' => '茍', 'B' => '咷', 'C' => '咮', 'D' => '哖', 'E' => '咶', 'F' => '哅', 'G' => '哆', 'H' => '咠', 'I' => '呰', 'J' => '咼', 'K' => '咢', 'L' => '咾', 'M' => '呲', 'N' => '哞', 'O' => '咰', 'P' => '垵', 'Q' => '垞', 'R' => '垟', 'S' => '垤', 'T' => '垌', 'U' => '垗', 'V' => '垝', 'W' => '垛', 'X' => '垔', 'Y' => '垘', 'Z' => '垏', '[' => '垙', '\\' => '垥', ']' => '垚', '^' => '垕', '_' => '壴', '`' => '复', 'a' => '奓', 'b' => '姡', 'c' => '姞', 'd' => '姮', 'e' => '娀', 'f' => '姱', 'g' => '姝', 'h' => '姺', 'i' => '姽', 'j' => '姼', 'k' => '姶', 'l' => '姤', 'm' => '姲', 'n' => '姷', 'o' => '姛', 'p' => '姩', 'q' => '姳', 'r' => '姵', 's' => '姠', 't' => '姾', 'u' => '姴', 'v' => '姭', 'w' => '宨', 'x' => '屌', 'y' => '峐', 'z' => '峘', '{' => '峌', '|' => '峗', '}' => '峋', '~' => '峛', 'Ρ' => '峞', '΢' => '峚', 'Σ' => '峉', 'Τ' => '峇', 'Υ' => '峊', 'Φ' => '峖', 'Χ' => '峓', 'Ψ' => '峔', 'Ω' => '峏', 'Ϊ' => '峈', 'Ϋ' => '峆', 'ά' => '峎', 'έ' => '峟', 'ή' => '峸', 'ί' => '巹', 'ΰ' => '帡', 'α' => '帢', 'β' => '帣', 'γ' => '帠', 'δ' => '帤', 'ε' => '庰', 'ζ' => '庤', 'η' => '庢', 'θ' => '庛', 'ι' => '庣', 'κ' => '庥', 'λ' => '弇', 'μ' => '弮', 'ν' => '彖', 'ξ' => '徆', 'ο' => '怷', '' => '怹', '' => '恔', '' => '恲', '' => '恞', '' => '恅', '' => '恓', '' => '恇', '' => '恉', '' => '恛', '' => '恌', '' => '恀', '' => '恂', '' => '恟', '' => '怤', '' => '恄', '' => '恘', '' => '恦', '' => '恮', '' => '扂', '' => '扃', '' => '拏', '' => '挍', '' => '挋', '' => '拵', '' => '挎', '' => '挃', '' => '拫', '' => '拹', '' => '挏', '' => '挌', '' => '拸', '' => '拶', '' => '挀', '' => '挓', '' => '挔', '' => '拺', '' => '挕', '' => '拻', '' => '拰', '' => '敁', '' => '敃', '' => '斪', '' => '斿', '' => '昶', '' => '昡', '' => '昲', '' => '昵', '' => '昜', '' => '昦', '' => '昢', '' => '昳', '' => '昫', '' => '昺', '' => '昝', '' => '昴', '' => '昹', '' => '昮', '' => '朏', '' => '朐', '' => '柁', '' => '柲', '' => '柈', '' => '枺', '@' => '柜', 'A' => '枻', 'B' => '柸', 'C' => '柘', 'D' => '柀', 'E' => '枷', 'F' => '柅', 'G' => '柫', 'H' => '柤', 'I' => '柟', 'J' => '枵', 'K' => '柍', 'L' => '枳', 'M' => '柷', 'N' => '柶', 'O' => '柮', 'P' => '柣', 'Q' => '柂', 'R' => '枹', 'S' => '柎', 'T' => '柧', 'U' => '柰', 'V' => '枲', 'W' => '柼', 'X' => '柆', 'Y' => '柭', 'Z' => '柌', '[' => '枮', '\\' => '柦', ']' => '柛', '^' => '柺', '_' => '柉', '`' => '柊', 'a' => '柃', 'b' => '柪', 'c' => '柋', 'd' => '欨', 'e' => '殂', 'f' => '殄', 'g' => '殶', 'h' => '毖', 'i' => '毘', 'j' => '毠', 'k' => '氠', 'l' => '氡', 'm' => '洨', 'n' => '洴', 'o' => '洭', 'p' => '洟', 'q' => '洼', 'r' => '洿', 's' => '洒', 't' => '洊', 'u' => '泚', 'v' => '洳', 'w' => '洄', 'x' => '洙', 'y' => '洺', 'z' => '洚', '{' => '洑', '|' => '洀', '}' => '洝', '~' => '浂', 'ϡ' => '洁', 'Ϣ' => '洘', 'ϣ' => '洷', 'Ϥ' => '洃', 'ϥ' => '洏', 'Ϧ' => '浀', 'ϧ' => '洇', 'Ϩ' => '洠', 'ϩ' => '洬', 'Ϫ' => '洈', 'ϫ' => '洢', 'Ϭ' => '洉', 'ϭ' => '洐', 'Ϯ' => '炷', 'ϯ' => '炟', 'ϰ' => '炾', 'ϱ' => '炱', 'ϲ' => '炰', 'ϳ' => '炡', 'ϴ' => '炴', 'ϵ' => '炵', '϶' => '炩', 'Ϸ' => '牁', 'ϸ' => '牉', 'Ϲ' => '牊', 'Ϻ' => '牬', 'ϻ' => '牰', 'ϼ' => '牳', 'Ͻ' => '牮', 'Ͼ' => '狊', 'Ͽ' => '狤', '' => '狨', '' => '狫', '' => '狟', '' => '狪', '' => '狦', '' => '狣', '' => '玅', '' => '珌', '' => '珂', '' => '珈', '' => '珅', '' => '玹', '' => '玶', '' => '玵', '' => '玴', '' => '珫', '' => '玿', '' => '珇', '' => '玾', '' => '珃', '' => '珆', '' => '玸', '' => '珋', '' => '瓬', '' => '瓮', '' => '甮', '' => '畇', '' => '畈', '' => '疧', '' => '疪', '' => '癹', '' => '盄', '' => '眈', '' => '眃', '' => '眄', '' => '眅', '' => '眊', '' => '盷', '' => '盻', '' => '盺', '' => '矧', '' => '矨', '' => '砆', '' => '砑', '' => '砒', '' => '砅', '' => '砐', '' => '砏', '' => '砎', '' => '砉', '' => '砃', '' => '砓', '' => '祊', '' => '祌', '' => '祋', '' => '祅', '' => '祄', '' => '秕', '' => '种', '' => '秏', '' => '秖', '' => '秎', '' => '窀', '@' => '穾', 'A' => '竑', 'B' => '笀', 'C' => '笁', 'D' => '籺', 'E' => '籸', 'F' => '籹', 'G' => '籿', 'H' => '粀', 'I' => '粁', 'J' => '紃', 'K' => '紈', 'L' => '紁', 'M' => '罘', 'N' => '羑', 'O' => '羍', 'P' => '羾', 'Q' => '耇', 'R' => '耎', 'S' => '耏', 'T' => '耔', 'U' => '耷', 'V' => '胘', 'W' => '胇', 'X' => '胠', 'Y' => '胑', 'Z' => '胈', '[' => '胂', '\\' => '胐', ']' => '胅', '^' => '胣', '_' => '胙', '`' => '胜', 'a' => '胊', 'b' => '胕', 'c' => '胉', 'd' => '胏', 'e' => '胗', 'f' => '胦', 'g' => '胍', 'h' => '臿', 'i' => '舡', 'j' => '芔', 'k' => '苙', 'l' => '苾', 'm' => '苹', 'n' => '茇', 'o' => '苨', 'p' => '茀', 'q' => '苕', 'r' => '茺', 's' => '苫', 't' => '苖', 'u' => '苴', 'v' => '苬', 'w' => '苡', 'x' => '苲', 'y' => '苵', 'z' => '茌', '{' => '苻', '|' => '苶', '}' => '苰', '~' => '苪', 'С' => '苤', 'Т' => '苠', 'У' => '苺', 'Ф' => '苳', 'Х' => '苭', 'Ц' => '虷', 'Ч' => '虴', 'Ш' => '虼', 'Щ' => '虳', 'Ъ' => '衁', 'Ы' => '衎', 'Ь' => '衧', 'Э' => '衪', 'Ю' => '衩', 'Я' => '觓', 'а' => '訄', 'б' => '訇', 'в' => '赲', 'г' => '迣', 'д' => '迡', 'е' => '迮', 'ж' => '迠', 'з' => '郱', 'и' => '邽', 'й' => '邿', 'к' => '郕', 'л' => '郅', 'м' => '邾', 'н' => '郇', 'о' => '郋', 'п' => '郈', '' => '釔', '' => '釓', '' => '陔', '' => '陏', '' => '陑', '' => '陓', '' => '陊', '' => '陎', '' => '倞', '' => '倅', '' => '倇', '' => '倓', '' => '倢', '' => '倰', '' => '倛', '' => '俵', '' => '俴', '' => '倳', '' => '倷', '' => '倬', '' => '俶', '' => '俷', '' => '倗', '' => '倜', '' => '倠', '' => '倧', '' => '倵', '' => '倯', '' => '倱', '' => '倎', '' => '党', '' => '冔', '' => '冓', '' => '凊', '' => '凄', '' => '凅', '' => '凈', '' => '凎', '' => '剡', '' => '剚', '' => '剒', '' => '剞', '' => '剟', '' => '剕', '' => '剢', '' => '勍', '' => '匎', '' => '厞', '' => '唦', '' => '哢', '' => '唗', '' => '唒', '' => '哧', '' => '哳', '' => '哤', '' => '唚', '' => '哿', '' => '唄', '' => '唈', '' => '哫', '' => '唑', '' => '唅', '' => '哱', '@' => '唊', 'A' => '哻', 'B' => '哷', 'C' => '哸', 'D' => '哠', 'E' => '唎', 'F' => '唃', 'G' => '唋', 'H' => '圁', 'I' => '圂', 'J' => '埌', 'K' => '堲', 'L' => '埕', 'M' => '埒', 'N' => '垺', 'O' => '埆', 'P' => '垽', 'Q' => '垼', 'R' => '垸', 'S' => '垶', 'T' => '垿', 'U' => '埇', 'V' => '埐', 'W' => '垹', 'X' => '埁', 'Y' => '夎', 'Z' => '奊', '[' => '娙', '\\' => '娖', ']' => '娭', '^' => '娮', '_' => '娕', '`' => '娏', 'a' => '娗', 'b' => '娊', 'c' => '娞', 'd' => '娳', 'e' => '孬', 'f' => '宧', 'g' => '宭', 'h' => '宬', 'i' => '尃', 'j' => '屖', 'k' => '屔', 'l' => '峬', 'm' => '峿', 'n' => '峮', 'o' => '峱', 'p' => '峷', 'q' => '崀', 'r' => '峹', 's' => '帩', 't' => '帨', 'u' => '庨', 'v' => '庮', 'w' => '庪', 'x' => '庬', 'y' => '弳', 'z' => '弰', '{' => '彧', '|' => '恝', '}' => '恚', '~' => '恧', 'ѡ' => '恁', 'Ѣ' => '悢', 'ѣ' => '悈', 'Ѥ' => '悀', 'ѥ' => '悒', 'Ѧ' => '悁', 'ѧ' => '悝', 'Ѩ' => '悃', 'ѩ' => '悕', 'Ѫ' => '悛', 'ѫ' => '悗', 'Ѭ' => '悇', 'ѭ' => '悜', 'Ѯ' => '悎', 'ѯ' => '戙', 'Ѱ' => '扆', 'ѱ' => '拲', 'Ѳ' => '挐', 'ѳ' => '捖', 'Ѵ' => '挬', 'ѵ' => '捄', 'Ѷ' => '捅', 'ѷ' => '挶', 'Ѹ' => '捃', 'ѹ' => '揤', 'Ѻ' => '挹', 'ѻ' => '捋', 'Ѽ' => '捊', 'ѽ' => '挼', 'Ѿ' => '挩', 'ѿ' => '捁', '' => '挴', '' => '捘', '' => '捔', '' => '捙', '' => '挭', '' => '捇', '' => '挳', '' => '捚', '' => '捑', '' => '挸', '' => '捗', '' => '捀', '' => '捈', '' => '敊', '' => '敆', '' => '旆', '' => '旃', '' => '旄', '' => '旂', '' => '晊', '' => '晟', '' => '晇', '' => '晑', '' => '朒', '' => '朓', '' => '栟', '' => '栚', '' => '桉', '' => '栲', '' => '栳', '' => '栻', '' => '桋', '' => '桏', '' => '栖', '' => '栱', '' => '栜', '' => '栵', '' => '栫', '' => '栭', '' => '栯', '' => '桎', '' => '桄', '' => '栴', '' => '栝', '' => '栒', '' => '栔', '' => '栦', '' => '栨', '' => '栮', '' => '桍', '' => '栺', '' => '栥', '' => '栠', '' => '欬', '' => '欯', '' => '欭', '' => '欱', '' => '欴', '' => '歭', '' => '肂', '' => '殈', '' => '毦', '' => '毤', '@' => '毨', 'A' => '毣', 'B' => '毢', 'C' => '毧', 'D' => '氥', 'E' => '浺', 'F' => '浣', 'G' => '浤', 'H' => '浶', 'I' => '洍', 'J' => '浡', 'K' => '涒', 'L' => '浘', 'M' => '浢', 'N' => '浭', 'O' => '浯', 'P' => '涑', 'Q' => '涍', 'R' => '淯', 'S' => '浿', 'T' => '涆', 'U' => '浞', 'V' => '浧', 'W' => '浠', 'X' => '涗', 'Y' => '浰', 'Z' => '浼', '[' => '浟', '\\' => '涂', ']' => '涘', '^' => '洯', '_' => '浨', '`' => '涋', 'a' => '浾', 'b' => '涀', 'c' => '涄', 'd' => '洖', 'e' => '涃', 'f' => '浻', 'g' => '浽', 'h' => '浵', 'i' => '涐', 'j' => '烜', 'k' => '烓', 'l' => '烑', 'm' => '烝', 'n' => '烋', 'o' => '缹', 'p' => '烢', 'q' => '烗', 'r' => '烒', 's' => '烞', 't' => '烠', 'u' => '烔', 'v' => '烍', 'w' => '烅', 'x' => '烆', 'y' => '烇', 'z' => '烚', '{' => '烎', '|' => '烡', '}' => '牂', '~' => '牸', 'ҡ' => '牷', 'Ң' => '牶', 'ң' => '猀', 'Ҥ' => '狺', 'ҥ' => '狴', 'Ҧ' => '狾', 'ҧ' => '狶', 'Ҩ' => '狳', 'ҩ' => '狻', 'Ҫ' => '猁', 'ҫ' => '珓', 'Ҭ' => '珙', 'ҭ' => '珥', 'Ү' => '珖', 'ү' => '玼', 'Ұ' => '珧', 'ұ' => '珣', 'Ҳ' => '珩', 'ҳ' => '珜', 'Ҵ' => '珒', 'ҵ' => '珛', 'Ҷ' => '珔', 'ҷ' => '珝', 'Ҹ' => '珚', 'ҹ' => '珗', 'Һ' => '珘', 'һ' => '珨', 'Ҽ' => '瓞', 'ҽ' => '瓟', 'Ҿ' => '瓴', 'ҿ' => '瓵', '' => '甡', '' => '畛', '' => '畟', '' => '疰', '' => '痁', '' => '疻', '' => '痄', '' => '痀', '' => '疿', '' => '疶', '' => '疺', '' => '皊', '' => '盉', '' => '眝', '' => '眛', '' => '眐', '' => '眓', '' => '眒', '' => '眣', '' => '眑', '' => '眕', '' => '眙', '' => '眚', '' => '眢', '' => '眧', '' => '砣', '' => '砬', '' => '砢', '' => '砵', '' => '砯', '' => '砨', '' => '砮', '' => '砫', '' => '砡', '' => '砩', '' => '砳', '' => '砪', '' => '砱', '' => '祔', '' => '祛', '' => '祏', '' => '祜', '' => '祓', '' => '祒', '' => '祑', '' => '秫', '' => '秬', '' => '秠', '' => '秮', '' => '秭', '' => '秪', '' => '秜', '' => '秞', '' => '秝', '' => '窆', '' => '窉', '' => '窅', '' => '窋', '' => '窌', '' => '窊', '' => '窇', '' => '竘', '' => '笐', '@' => '笄', 'A' => '笓', 'B' => '笅', 'C' => '笏', 'D' => '笈', 'E' => '笊', 'F' => '笎', 'G' => '笉', 'H' => '笒', 'I' => '粄', 'J' => '粑', 'K' => '粊', 'L' => '粌', 'M' => '粈', 'N' => '粍', 'O' => '粅', 'P' => '紞', 'Q' => '紝', 'R' => '紑', 'S' => '紎', 'T' => '紘', 'U' => '紖', 'V' => '紓', 'W' => '紟', 'X' => '紒', 'Y' => '紏', 'Z' => '紌', '[' => '罜', '\\' => '罡', ']' => '罞', '^' => '罠', '_' => '罝', '`' => '罛', 'a' => '羖', 'b' => '羒', 'c' => '翃', 'd' => '翂', 'e' => '翀', 'f' => '耖', 'g' => '耾', 'h' => '耹', 'i' => '胺', 'j' => '胲', 'k' => '胹', 'l' => '胵', 'm' => '脁', 'n' => '胻', 'o' => '脀', 'p' => '舁', 'q' => '舯', 'r' => '舥', 's' => '茳', 't' => '茭', 'u' => '荄', 'v' => '茙', 'w' => '荑', 'x' => '茥', 'y' => '荖', 'z' => '茿', '{' => '荁', '|' => '茦', '}' => '茜', '~' => '茢', 'ӡ' => '荂', 'Ӣ' => '荎', 'ӣ' => '茛', 'Ӥ' => '茪', 'ӥ' => '茈', 'Ӧ' => '茼', 'ӧ' => '荍', 'Ө' => '茖', 'ө' => '茤', 'Ӫ' => '茠', 'ӫ' => '茷', 'Ӭ' => '茯', 'ӭ' => '茩', 'Ӯ' => '荇', 'ӯ' => '荅', 'Ӱ' => '荌', 'ӱ' => '荓', 'Ӳ' => '茞', 'ӳ' => '茬', 'Ӵ' => '荋', 'ӵ' => '茧', 'Ӷ' => '荈', 'ӷ' => '虓', 'Ӹ' => '虒', 'ӹ' => '蚢', 'Ӻ' => '蚨', 'ӻ' => '蚖', 'Ӽ' => '蚍', 'ӽ' => '蚑', 'Ӿ' => '蚞', 'ӿ' => '蚇', '' => '蚗', '' => '蚆', '' => '蚋', '' => '蚚', '' => '蚅', '' => '蚥', '' => '蚙', '' => '蚡', '' => '蚧', '' => '蚕', '' => '蚘', '' => '蚎', '' => '蚝', '' => '蚐', '' => '蚔', '' => '衃', '' => '衄', '' => '衭', '' => '衵', '' => '衶', '' => '衲', '' => '袀', '' => '衱', '' => '衿', '' => '衯', '' => '袃', '' => '衾', '' => '衴', '' => '衼', '' => '訒', '' => '豇', '' => '豗', '' => '豻', '' => '貤', '' => '貣', '' => '赶', '' => '赸', '' => '趵', '' => '趷', '' => '趶', '' => '軑', '' => '軓', '' => '迾', '' => '迵', '' => '适', '' => '迿', '' => '迻', '' => '逄', '' => '迼', '' => '迶', '' => '郖', '' => '郠', '' => '郙', '' => '郚', '' => '郣', '' => '郟', '' => '郥', '' => '郘', '' => '郛', '' => '郗', '' => '郜', '' => '郤', '' => '酐', '@' => '酎', 'A' => '酏', 'B' => '釕', 'C' => '釢', 'D' => '釚', 'E' => '陜', 'F' => '陟', 'G' => '隼', 'H' => '飣', 'I' => '髟', 'J' => '鬯', 'K' => '乿', 'L' => '偰', 'M' => '偪', 'N' => '偡', 'O' => '偞', 'P' => '偠', 'Q' => '偓', 'R' => '偋', 'S' => '偝', 'T' => '偲', 'U' => '偈', 'V' => '偍', 'W' => '偁', 'X' => '偛', 'Y' => '偊', 'Z' => '偢', '[' => '倕', '\\' => '偅', ']' => '偟', '^' => '偩', '_' => '偫', '`' => '偣', 'a' => '偤', 'b' => '偆', 'c' => '偀', 'd' => '偮', 'e' => '偳', 'f' => '偗', 'g' => '偑', 'h' => '凐', 'i' => '剫', 'j' => '剭', 'k' => '剬', 'l' => '剮', 'm' => '勖', 'n' => '勓', 'o' => '匭', 'p' => '厜', 'q' => '啵', 'r' => '啶', 's' => '唼', 't' => '啍', 'u' => '啐', 'v' => '唴', 'w' => '唪', 'x' => '啑', 'y' => '啢', 'z' => '唶', '{' => '唵', '|' => '唰', '}' => '啒', '~' => '啅', 'ԡ' => '唌', 'Ԣ' => '唲', 'ԣ' => '啥', 'Ԥ' => '啎', 'ԥ' => '唹', 'Ԧ' => '啈', 'ԧ' => '唭', 'Ԩ' => '唻', 'ԩ' => '啀', 'Ԫ' => '啋', 'ԫ' => '圊', 'Ԭ' => '圇', 'ԭ' => '埻', 'Ԯ' => '堔', 'ԯ' => '埢', '԰' => '埶', 'Ա' => '埜', 'Բ' => '埴', 'Գ' => '堀', 'Դ' => '埭', 'Ե' => '埽', 'Զ' => '堈', 'Է' => '埸', 'Ը' => '堋', 'Թ' => '埳', 'Ժ' => '埏', 'Ի' => '堇', 'Լ' => '埮', 'Խ' => '埣', 'Ծ' => '埲', 'Կ' => '埥', '' => '埬', '' => '埡', '' => '堎', '' => '埼', '' => '堐', '' => '埧', '' => '堁', '' => '堌', '' => '埱', '' => '埩', '' => '埰', '' => '堍', '' => '堄', '' => '奜', '' => '婠', '' => '婘', '' => '婕', '' => '婧', '' => '婞', '' => '娸', '' => '娵', '' => '婭', '' => '婐', '' => '婟', '' => '婥', '' => '婬', '' => '婓', '' => '婤', '' => '婗', '' => '婃', '' => '婝', '' => '婒', '' => '婄', '' => '婛', '' => '婈', '' => '媎', '' => '娾', '' => '婍', '' => '娹', '' => '婌', '' => '婰', '' => '婩', '' => '婇', '' => '婑', '' => '婖', '' => '婂', '' => '婜', '' => '孲', '' => '孮', '' => '寁', '' => '寀', '' => '屙', '' => '崞', '' => '崋', '' => '崝', '' => '崚', '' => '崠', '' => '崌', '' => '崨', '' => '崍', '' => '崦', '' => '崥', '' => '崏', '@' => '崰', 'A' => '崒', 'B' => '崣', 'C' => '崟', 'D' => '崮', 'E' => '帾', 'F' => '帴', 'G' => '庱', 'H' => '庴', 'I' => '庹', 'J' => '庲', 'K' => '庳', 'L' => '弶', 'M' => '弸', 'N' => '徛', 'O' => '徖', 'P' => '徟', 'Q' => '悊', 'R' => '悐', 'S' => '悆', 'T' => '悾', 'U' => '悰', 'V' => '悺', 'W' => '惓', 'X' => '惔', 'Y' => '惏', 'Z' => '惤', '[' => '惙', '\\' => '惝', ']' => '惈', '^' => '悱', '_' => '惛', '`' => '悷', 'a' => '惊', 'b' => '悿', 'c' => '惃', 'd' => '惍', 'e' => '惀', 'f' => '挲', 'g' => '捥', 'h' => '掊', 'i' => '掂', 'j' => '捽', 'k' => '掽', 'l' => '掞', 'm' => '掭', 'n' => '掝', 'o' => '掗', 'p' => '掫', 'q' => '掎', 'r' => '捯', 's' => '掇', 't' => '掐', 'u' => '据', 'v' => '掯', 'w' => '捵', 'x' => '掜', 'y' => '捭', 'z' => '掮', '{' => '捼', '|' => '掤', '}' => '挻', '~' => '掟', 'ա' => '捸', 'բ' => '掅', 'գ' => '掁', 'դ' => '掑', 'ե' => '掍', 'զ' => '捰', 'է' => '敓', 'ը' => '旍', 'թ' => '晥', 'ժ' => '晡', 'ի' => '晛', 'լ' => '晙', 'խ' => '晜', 'ծ' => '晢', 'կ' => '朘', 'հ' => '桹', 'ձ' => '梇', 'ղ' => '梐', 'ճ' => '梜', 'մ' => '桭', 'յ' => '桮', 'ն' => '梮', 'շ' => '梫', 'ո' => '楖', 'չ' => '桯', 'պ' => '梣', 'ջ' => '梬', 'ռ' => '梩', 'ս' => '桵', 'վ' => '桴', 'տ' => '梲', '' => '梏', '' => '桷', '' => '梒', '' => '桼', '' => '桫', '' => '桲', '' => '梪', '' => '梀', '' => '桱', '' => '桾', '' => '梛', '' => '梖', '' => '梋', '' => '梠', '' => '梉', '' => '梤', '' => '桸', '' => '桻', '' => '梑', '' => '梌', '' => '梊', '' => '桽', '' => '欶', '' => '欳', '' => '欷', '' => '欸', '' => '殑', '' => '殏', '' => '殍', '' => '殎', '' => '殌', '' => '氪', '' => '淀', '' => '涫', '' => '涴', '' => '涳', '' => '湴', '' => '涬', '' => '淩', '' => '淢', '' => '涷', '' => '淶', '' => '淔', '' => '渀', '' => '淈', '' => '淠', '' => '淟', '' => '淖', '' => '涾', '' => '淥', '' => '淜', '' => '淝', '' => '淛', '' => '淴', '' => '淊', '' => '涽', '' => '淭', '' => '淰', '' => '涺', '' => '淕', '' => '淂', '' => '淏', '' => '淉', '@' => '淐', 'A' => '淲', 'B' => '淓', 'C' => '淽', 'D' => '淗', 'E' => '淍', 'F' => '淣', 'G' => '涻', 'H' => '烺', 'I' => '焍', 'J' => '烷', 'K' => '焗', 'L' => '烴', 'M' => '焌', 'N' => '烰', 'O' => '焄', 'P' => '烳', 'Q' => '焐', 'R' => '烼', 'S' => '烿', 'T' => '焆', 'U' => '焓', 'V' => '焀', 'W' => '烸', 'X' => '烶', 'Y' => '焋', 'Z' => '焂', '[' => '焎', '\\' => '牾', ']' => '牻', '^' => '牼', '_' => '牿', '`' => '猝', 'a' => '猗', 'b' => '猇', 'c' => '猑', 'd' => '猘', 'e' => '猊', 'f' => '猈', 'g' => '狿', 'h' => '猏', 'i' => '猞', 'j' => '玈', 'k' => '珶', 'l' => '珸', 'm' => '珵', 'n' => '琄', 'o' => '琁', 'p' => '珽', 'q' => '琇', 'r' => '琀', 's' => '珺', 't' => '珼', 'u' => '珿', 'v' => '琌', 'w' => '琋', 'x' => '珴', 'y' => '琈', 'z' => '畤', '{' => '畣', '|' => '痎', '}' => '痒', '~' => '痏', '֡' => '痋', '֢' => '痌', '֣' => '痑', '֤' => '痐', '֥' => '皏', '֦' => '皉', '֧' => '盓', '֨' => '眹', '֩' => '眯', '֪' => '眭', '֫' => '眱', '֬' => '眲', '֭' => '眴', '֮' => '眳', '֯' => '眽', 'ְ' => '眥', 'ֱ' => '眻', 'ֲ' => '眵', 'ֳ' => '硈', 'ִ' => '硒', 'ֵ' => '硉', 'ֶ' => '硍', 'ַ' => '硊', 'ָ' => '硌', 'ֹ' => '砦', 'ֺ' => '硅', 'ֻ' => '硐', 'ּ' => '祤', 'ֽ' => '祧', '־' => '祩', 'ֿ' => '祪', '' => '祣', '' => '祫', '' => '祡', '' => '离', '' => '秺', '' => '秸', '' => '秶', '' => '秷', '' => '窏', '' => '窔', '' => '窐', '' => '笵', '' => '筇', '' => '笴', '' => '笥', '' => '笰', '' => '笢', '' => '笤', '' => '笳', '' => '笘', '' => '笪', '' => '笝', '' => '笱', '' => '笫', '' => '笭', '' => '笯', '' => '笲', '' => '笸', '' => '笚', '' => '笣', '' => '粔', '' => '粘', '' => '粖', '' => '粣', '' => '紵', '' => '紽', '' => '紸', '' => '紶', '' => '紺', '' => '絅', '' => '紬', '' => '紩', '' => '絁', '' => '絇', '' => '紾', '' => '紿', '' => '絊', '' => '紻', '' => '紨', '' => '罣', '' => '羕', '' => '羜', '' => '羝', '' => '羛', '' => '翊', '' => '翋', '' => '翍', '' => '翐', '' => '翑', '' => '翇', '' => '翏', '' => '翉', '' => '耟', '@' => '耞', 'A' => '耛', 'B' => '聇', 'C' => '聃', 'D' => '聈', 'E' => '脘', 'F' => '脥', 'G' => '脙', 'H' => '脛', 'I' => '脭', 'J' => '脟', 'K' => '脬', 'L' => '脞', 'M' => '脡', 'N' => '脕', 'O' => '脧', 'P' => '脝', 'Q' => '脢', 'R' => '舑', 'S' => '舸', 'T' => '舳', 'U' => '舺', 'V' => '舴', 'W' => '舲', 'X' => '艴', 'Y' => '莐', 'Z' => '莣', '[' => '莨', '\\' => '莍', ']' => '荺', '^' => '荳', '_' => '莤', '`' => '荴', 'a' => '莏', 'b' => '莁', 'c' => '莕', 'd' => '莙', 'e' => '荵', 'f' => '莔', 'g' => '莩', 'h' => '荽', 'i' => '莃', 'j' => '莌', 'k' => '莝', 'l' => '莛', 'm' => '莪', 'n' => '莋', 'o' => '荾', 'p' => '莥', 'q' => '莯', 'r' => '莈', 's' => '莗', 't' => '莰', 'u' => '荿', 'v' => '莦', 'w' => '莇', 'x' => '莮', 'y' => '荶', 'z' => '莚', '{' => '虙', '|' => '虖', '}' => '蚿', '~' => '蚷', 'ס' => '蛂', 'ע' => '蛁', 'ף' => '蛅', 'פ' => '蚺', 'ץ' => '蚰', 'צ' => '蛈', 'ק' => '蚹', 'ר' => '蚳', 'ש' => '蚸', 'ת' => '蛌', '׫' => '蚴', '׬' => '蚻', '׭' => '蚼', '׮' => '蛃', 'ׯ' => '蚽', 'װ' => '蚾', 'ױ' => '衒', 'ײ' => '袉', '׳' => '袕', '״' => '袨', '׵' => '袢', '׶' => '袪', '׷' => '袚', '׸' => '袑', '׹' => '袡', '׺' => '袟', '׻' => '袘', '׼' => '袧', '׽' => '袙', '׾' => '袛', '׿' => '袗', '' => '袤', '' => '袬', '' => '袌', '' => '袓', '' => '袎', '' => '覂', '' => '觖', '' => '觙', '' => '觕', '' => '訰', '' => '訧', '' => '訬', '' => '訞', '' => '谹', '' => '谻', '' => '豜', '' => '豝', '' => '豽', '' => '貥', '' => '赽', '' => '赻', '' => '赹', '' => '趼', '' => '跂', '' => '趹', '' => '趿', '' => '跁', '' => '軘', '' => '軞', '' => '軝', '' => '軜', '' => '軗', '' => '軠', '' => '軡', '' => '逤', '' => '逋', '' => '逑', '' => '逜', '' => '逌', '' => '逡', '' => '郯', '' => '郪', '' => '郰', '' => '郴', '' => '郲', '' => '郳', '' => '郔', '' => '郫', '' => '郬', '' => '郩', '' => '酖', '' => '酘', '' => '酚', '' => '酓', '' => '酕', '' => '釬', '' => '釴', '' => '釱', '' => '釳', '' => '釸', '' => '釤', '' => '釹', '' => '釪', '@' => '釫', 'A' => '釷', 'B' => '釨', 'C' => '釮', 'D' => '镺', 'E' => '閆', 'F' => '閈', 'G' => '陼', 'H' => '陭', 'I' => '陫', 'J' => '陱', 'K' => '陯', 'L' => '隿', 'M' => '靪', 'N' => '頄', 'O' => '飥', 'P' => '馗', 'Q' => '傛', 'R' => '傕', 'S' => '傔', 'T' => '傞', 'U' => '傋', 'V' => '傣', 'W' => '傃', 'X' => '傌', 'Y' => '傎', 'Z' => '傝', '[' => '偨', '\\' => '傜', ']' => '傒', '^' => '傂', '_' => '傇', '`' => '兟', 'a' => '凔', 'b' => '匒', 'c' => '匑', 'd' => '厤', 'e' => '厧', 'f' => '喑', 'g' => '喨', 'h' => '喥', 'i' => '喭', 'j' => '啷', 'k' => '噅', 'l' => '喢', 'm' => '喓', 'n' => '喈', 'o' => '喏', 'p' => '喵', 'q' => '喁', 'r' => '喣', 's' => '喒', 't' => '喤', 'u' => '啽', 'v' => '喌', 'w' => '喦', 'x' => '啿', 'y' => '喕', 'z' => '喡', '{' => '喎', '|' => '圌', '}' => '堩', '~' => '堷', 'ء' => '堙', 'آ' => '堞', 'أ' => '堧', 'ؤ' => '堣', 'إ' => '堨', 'ئ' => '埵', 'ا' => '塈', 'ب' => '堥', 'ة' => '堜', 'ت' => '堛', 'ث' => '堳', 'ج' => '堿', 'ح' => '堶', 'خ' => '堮', 'د' => '堹', 'ذ' => '堸', 'ر' => '堭', 'ز' => '堬', 'س' => '堻', 'ش' => '奡', 'ص' => '媯', 'ض' => '媔', 'ط' => '媟', 'ظ' => '婺', 'ع' => '媢', 'غ' => '媞', 'ػ' => '婸', 'ؼ' => '媦', 'ؽ' => '婼', 'ؾ' => '媥', 'ؿ' => '媬', '' => '媕', '' => '媮', '' => '娷', '' => '媄', '' => '媊', '' => '媗', '' => '媃', '' => '媋', '' => '媩', '' => '婻', '' => '婽', '' => '媌', '' => '媜', '' => '媏', '' => '媓', '' => '媝', '' => '寪', '' => '寍', '' => '寋', '' => '寔', '' => '寑', '' => '寊', '' => '寎', '' => '尌', '' => '尰', '' => '崷', '' => '嵃', '' => '嵫', '' => '嵁', '' => '嵋', '' => '崿', '' => '崵', '' => '嵑', '' => '嵎', '' => '嵕', '' => '崳', '' => '崺', '' => '嵒', '' => '崽', '' => '崱', '' => '嵙', '' => '嵂', '' => '崹', '' => '嵉', '' => '崸', '' => '崼', '' => '崲', '' => '崶', '' => '嵀', '' => '嵅', '' => '幄', '' => '幁', '' => '彘', '' => '徦', '' => '徥', '' => '徫', '' => '惉', '' => '悹', '' => '惌', '' => '惢', '' => '惎', '' => '惄', '' => '愔', '@' => '惲', 'A' => '愊', 'B' => '愖', 'C' => '愅', 'D' => '惵', 'E' => '愓', 'F' => '惸', 'G' => '惼', 'H' => '惾', 'I' => '惁', 'J' => '愃', 'K' => '愘', 'L' => '愝', 'M' => '愐', 'N' => '惿', 'O' => '愄', 'P' => '愋', 'Q' => '扊', 'R' => '掔', 'S' => '掱', 'T' => '掰', 'U' => '揎', 'V' => '揥', 'W' => '揨', 'X' => '揯', 'Y' => '揃', 'Z' => '撝', '[' => '揳', '\\' => '揊', ']' => '揠', '^' => '揶', '_' => '揕', '`' => '揲', 'a' => '揵', 'b' => '摡', 'c' => '揟', 'd' => '掾', 'e' => '揝', 'f' => '揜', 'g' => '揄', 'h' => '揘', 'i' => '揓', 'j' => '揂', 'k' => '揇', 'l' => '揌', 'm' => '揋', 'n' => '揈', 'o' => '揰', 'p' => '揗', 'q' => '揙', 'r' => '攲', 's' => '敧', 't' => '敪', 'u' => '敤', 'v' => '敜', 'w' => '敨', 'x' => '敥', 'y' => '斌', 'z' => '斝', '{' => '斞', '|' => '斮', '}' => '旐', '~' => '旒', '١' => '晼', '٢' => '晬', '٣' => '晻', '٤' => '暀', '٥' => '晱', '٦' => '晹', '٧' => '晪', '٨' => '晲', '٩' => '朁', '٪' => '椌', '٫' => '棓', '٬' => '椄', '٭' => '棜', 'ٮ' => '椪', 'ٯ' => '棬', 'ٰ' => '棪', 'ٱ' => '棱', 'ٲ' => '椏', 'ٳ' => '棖', 'ٴ' => '棷', 'ٵ' => '棫', 'ٶ' => '棤', 'ٷ' => '棶', 'ٸ' => '椓', 'ٹ' => '椐', 'ٺ' => '棳', 'ٻ' => '棡', 'ټ' => '椇', 'ٽ' => '棌', 'پ' => '椈', 'ٿ' => '楰', '' => '梴', '' => '椑', '' => '棯', '' => '棆', '' => '椔', '' => '棸', '' => '棐', '' => '棽', '' => '棼', '' => '棨', '' => '椋', '' => '椊', '' => '椗', '' => '棎', '' => '棈', '' => '棝', '' => '棞', '' => '棦', '' => '棴', '' => '棑', '' => '椆', '' => '棔', '' => '棩', '' => '椕', '' => '椥', '' => '棇', '' => '欹', '' => '欻', '' => '欿', '' => '欼', '' => '殔', '' => '殗', '' => '殙', '' => '殕', '' => '殽', '' => '毰', '' => '毲', '' => '毳', '' => '氰', '' => '淼', '' => '湆', '' => '湇', '' => '渟', '' => '湉', '' => '溈', '' => '渼', '' => '渽', '' => '湅', '' => '湢', '' => '渫', '' => '渿', '' => '湁', '' => '湝', '' => '湳', '' => '渜', '' => '渳', '' => '湋', '' => '湀', '' => '湑', '' => '渻', '' => '渃', '' => '渮', '' => '湞', '@' => '湨', 'A' => '湜', 'B' => '湡', 'C' => '渱', 'D' => '渨', 'E' => '湠', 'F' => '湱', 'G' => '湫', 'H' => '渹', 'I' => '渢', 'J' => '渰', 'K' => '湓', 'L' => '湥', 'M' => '渧', 'N' => '湸', 'O' => '湤', 'P' => '湷', 'Q' => '湕', 'R' => '湹', 'S' => '湒', 'T' => '湦', 'U' => '渵', 'V' => '渶', 'W' => '湚', 'X' => '焠', 'Y' => '焞', 'Z' => '焯', '[' => '烻', '\\' => '焮', ']' => '焱', '^' => '焣', '_' => '焥', '`' => '焢', 'a' => '焲', 'b' => '焟', 'c' => '焨', 'd' => '焺', 'e' => '焛', 'f' => '牋', 'g' => '牚', 'h' => '犈', 'i' => '犉', 'j' => '犆', 'k' => '犅', 'l' => '犋', 'm' => '猒', 'n' => '猋', 'o' => '猰', 'p' => '猢', 'q' => '猱', 'r' => '猳', 's' => '猧', 't' => '猲', 'u' => '猭', 'v' => '猦', 'w' => '猣', 'x' => '猵', 'y' => '猌', 'z' => '琮', '{' => '琬', '|' => '琰', '}' => '琫', '~' => '琖', 'ڡ' => '琚', 'ڢ' => '琡', 'ڣ' => '琭', 'ڤ' => '琱', 'ڥ' => '琤', 'ڦ' => '琣', 'ڧ' => '琝', 'ڨ' => '琩', 'ک' => '琠', 'ڪ' => '琲', 'ګ' => '瓻', 'ڬ' => '甯', 'ڭ' => '畯', 'ڮ' => '畬', 'گ' => '痧', 'ڰ' => '痚', 'ڱ' => '痡', 'ڲ' => '痦', 'ڳ' => '痝', 'ڴ' => '痟', 'ڵ' => '痤', 'ڶ' => '痗', 'ڷ' => '皕', 'ڸ' => '皒', 'ڹ' => '盚', 'ں' => '睆', 'ڻ' => '睇', 'ڼ' => '睄', 'ڽ' => '睍', 'ھ' => '睅', 'ڿ' => '睊', '' => '睎', '' => '睋', '' => '睌', '' => '矞', '' => '矬', '' => '硠', '' => '硤', '' => '硥', '' => '硜', '' => '硭', '' => '硱', '' => '硪', '' => '确', '' => '硰', '' => '硩', '' => '硨', '' => '硞', '' => '硢', '' => '祴', '' => '祳', '' => '祲', '' => '祰', '' => '稂', '' => '稊', '' => '稃', '' => '稌', '' => '稄', '' => '窙', '' => '竦', '' => '竤', '' => '筊', '' => '笻', '' => '筄', '' => '筈', '' => '筌', '' => '筎', '' => '筀', '' => '筘', '' => '筅', '' => '粢', '' => '粞', '' => '粨', '' => '粡', '' => '絘', '' => '絯', '' => '絣', '' => '絓', '' => '絖', '' => '絧', '' => '絪', '' => '絏', '' => '絭', '' => '絜', '' => '絫', '' => '絒', '' => '絔', '' => '絩', '' => '絑', '' => '絟', '' => '絎', '' => '缾', '' => '缿', '' => '罥', '@' => '罦', 'A' => '羢', 'B' => '羠', 'C' => '羡', 'D' => '翗', 'E' => '聑', 'F' => '聏', 'G' => '聐', 'H' => '胾', 'I' => '胔', 'J' => '腃', 'K' => '腊', 'L' => '腒', 'M' => '腏', 'N' => '腇', 'O' => '脽', 'P' => '腍', 'Q' => '脺', 'R' => '臦', 'S' => '臮', 'T' => '臷', 'U' => '臸', 'V' => '臹', 'W' => '舄', 'X' => '舼', 'Y' => '舽', 'Z' => '舿', '[' => '艵', '\\' => '茻', ']' => '菏', '^' => '菹', '_' => '萣', '`' => '菀', 'a' => '菨', 'b' => '萒', 'c' => '菧', 'd' => '菤', 'e' => '菼', 'f' => '菶', 'g' => '萐', 'h' => '菆', 'i' => '菈', 'j' => '菫', 'k' => '菣', 'l' => '莿', 'm' => '萁', 'n' => '菝', 'o' => '菥', 'p' => '菘', 'q' => '菿', 'r' => '菡', 's' => '菋', 't' => '菎', 'u' => '菖', 'v' => '菵', 'w' => '菉', 'x' => '萉', 'y' => '萏', 'z' => '菞', '{' => '萑', '|' => '萆', '}' => '菂', '~' => '菳', 'ۡ' => '菕', 'ۢ' => '菺', 'ۣ' => '菇', 'ۤ' => '菑', 'ۥ' => '菪', 'ۦ' => '萓', 'ۧ' => '菃', 'ۨ' => '菬', '۩' => '菮', '۪' => '菄', '۫' => '菻', '۬' => '菗', 'ۭ' => '菢', 'ۮ' => '萛', 'ۯ' => '菛', '۰' => '菾', '۱' => '蛘', '۲' => '蛢', '۳' => '蛦', '۴' => '蛓', '۵' => '蛣', '۶' => '蛚', '۷' => '蛪', '۸' => '蛝', '۹' => '蛫', 'ۺ' => '蛜', 'ۻ' => '蛬', 'ۼ' => '蛩', '۽' => '蛗', '۾' => '蛨', 'ۿ' => '蛑', '' => '衈', '' => '衖', '' => '衕', '' => '袺', '' => '裗', '' => '袹', '' => '袸', '' => '裀', '' => '袾', '' => '袶', '' => '袼', '' => '袷', '' => '袽', '' => '袲', '' => '褁', '' => '裉', '' => '覕', '' => '覘', '' => '覗', '' => '觝', '' => '觚', '' => '觛', '' => '詎', '' => '詍', '' => '訹', '' => '詙', '' => '詀', '' => '詗', '' => '詘', '' => '詄', '' => '詅', '' => '詒', '' => '詈', '' => '詑', '' => '詊', '' => '詌', '' => '詏', '' => '豟', '' => '貁', '' => '貀', '' => '貺', '' => '貾', '' => '貰', '' => '貹', '' => '貵', '' => '趄', '' => '趀', '' => '趉', '' => '跘', '' => '跓', '' => '跍', '' => '跇', '' => '跖', '' => '跜', '' => '跏', '' => '跕', '' => '跙', '' => '跈', '' => '跗', '' => '跅', '' => '軯', '' => '軷', '' => '軺', '@' => '軹', 'A' => '軦', 'B' => '軮', 'C' => '軥', 'D' => '軵', 'E' => '軧', 'F' => '軨', 'G' => '軶', 'H' => '軫', 'I' => '軱', 'J' => '軬', 'K' => '軴', 'L' => '軩', 'M' => '逭', 'N' => '逴', 'O' => '逯', 'P' => '鄆', 'Q' => '鄬', 'R' => '鄄', 'S' => '郿', 'T' => '郼', 'U' => '鄈', 'V' => '郹', 'W' => '郻', 'X' => '鄁', 'Y' => '鄀', 'Z' => '鄇', '[' => '鄅', '\\' => '鄃', ']' => '酡', '^' => '酤', '_' => '酟', '`' => '酢', 'a' => '酠', 'b' => '鈁', 'c' => '鈊', 'd' => '鈥', 'e' => '鈃', 'f' => '鈚', 'g' => '鈦', 'h' => '鈏', 'i' => '鈌', 'j' => '鈀', 'k' => '鈒', 'l' => '釿', 'm' => '釽', 'n' => '鈆', 'o' => '鈄', 'p' => '鈧', 'q' => '鈂', 'r' => '鈜', 's' => '鈤', 't' => '鈙', 'u' => '鈗', 'v' => '鈅', 'w' => '鈖', 'x' => '镻', 'y' => '閍', 'z' => '閌', '{' => '閐', '|' => '隇', '}' => '陾', '~' => '隈', 'ܡ' => '隉', 'ܢ' => '隃', 'ܣ' => '隀', 'ܤ' => '雂', 'ܥ' => '雈', 'ܦ' => '雃', 'ܧ' => '雱', 'ܨ' => '雰', 'ܩ' => '靬', 'ܪ' => '靰', 'ܫ' => '靮', 'ܬ' => '頇', 'ܭ' => '颩', 'ܮ' => '飫', 'ܯ' => '鳦', 'ܰ' => '黹', 'ܱ' => '亃', 'ܲ' => '亄', 'ܳ' => '亶', 'ܴ' => '傽', 'ܵ' => '傿', 'ܶ' => '僆', 'ܷ' => '傮', 'ܸ' => '僄', 'ܹ' => '僊', 'ܺ' => '傴', 'ܻ' => '僈', 'ܼ' => '僂', 'ܽ' => '傰', 'ܾ' => '僁', 'ܿ' => '傺', '' => '傱', '' => '僋', '' => '僉', '' => '傶', '' => '傸', '' => '凗', '' => '剺', '' => '剸', '' => '剻', '' => '剼', '' => '嗃', '' => '嗛', '' => '嗌', '' => '嗐', '' => '嗋', '' => '嗊', '' => '嗝', '' => '嗀', '' => '嗔', '' => '嗄', '' => '嗩', '' => '喿', '' => '嗒', '' => '喍', '' => '嗏', '' => '嗕', '' => '嗢', '' => '嗖', '' => '嗈', '' => '嗲', '' => '嗍', '' => '嗙', '' => '嗂', '' => '圔', '' => '塓', '' => '塨', '' => '塤', '' => '塏', '' => '塍', '' => '塉', '' => '塯', '' => '塕', '' => '塎', '' => '塝', '' => '塙', '' => '塥', '' => '塛', '' => '堽', '' => '塣', '' => '塱', '' => '壼', '' => '嫇', '' => '嫄', '' => '嫋', '' => '媺', '' => '媸', '' => '媱', '' => '媵', '' => '媰', '' => '媿', '' => '嫈', '' => '媻', '' => '嫆', '@' => '媷', 'A' => '嫀', 'B' => '嫊', 'C' => '媴', 'D' => '媶', 'E' => '嫍', 'F' => '媹', 'G' => '媐', 'H' => '寖', 'I' => '寘', 'J' => '寙', 'K' => '尟', 'L' => '尳', 'M' => '嵱', 'N' => '嵣', 'O' => '嵊', 'P' => '嵥', 'Q' => '嵲', 'R' => '嵬', 'S' => '嵞', 'T' => '嵨', 'U' => '嵧', 'V' => '嵢', 'W' => '巰', 'X' => '幏', 'Y' => '幎', 'Z' => '幊', '[' => '幍', '\\' => '幋', ']' => '廅', '^' => '廌', '_' => '廆', '`' => '廋', 'a' => '廇', 'b' => '彀', 'c' => '徯', 'd' => '徭', 'e' => '惷', 'f' => '慉', 'g' => '慊', 'h' => '愫', 'i' => '慅', 'j' => '愶', 'k' => '愲', 'l' => '愮', 'm' => '慆', 'n' => '愯', 'o' => '慏', 'p' => '愩', 'q' => '慀', 'r' => '戠', 's' => '酨', 't' => '戣', 'u' => '戥', 'v' => '戤', 'w' => '揅', 'x' => '揱', 'y' => '揫', 'z' => '搐', '{' => '搒', '|' => '搉', '}' => '搠', '~' => '搤', 'ݡ' => '搳', 'ݢ' => '摃', 'ݣ' => '搟', 'ݤ' => '搕', 'ݥ' => '搘', 'ݦ' => '搹', 'ݧ' => '搷', 'ݨ' => '搢', 'ݩ' => '搣', 'ݪ' => '搌', 'ݫ' => '搦', 'ݬ' => '搰', 'ݭ' => '搨', 'ݮ' => '摁', 'ݯ' => '搵', 'ݰ' => '搯', 'ݱ' => '搊', 'ݲ' => '搚', 'ݳ' => '摀', 'ݴ' => '搥', 'ݵ' => '搧', 'ݶ' => '搋', 'ݷ' => '揧', 'ݸ' => '搛', 'ݹ' => '搮', 'ݺ' => '搡', 'ݻ' => '搎', 'ݼ' => '敯', 'ݽ' => '斒', 'ݾ' => '旓', 'ݿ' => '暆', '' => '暌', '' => '暕', '' => '暐', '' => '暋', '' => '暊', '' => '暙', '' => '暔', '' => '晸', '' => '朠', '' => '楦', '' => '楟', '' => '椸', '' => '楎', '' => '楢', '' => '楱', '' => '椿', '' => '楅', '' => '楪', '' => '椹', '' => '楂', '' => '楗', '' => '楙', '' => '楺', '' => '楈', '' => '楉', '' => '椵', '' => '楬', '' => '椳', '' => '椽', '' => '楥', '' => '棰', '' => '楸', '' => '椴', '' => '楩', '' => '楀', '' => '楯', '' => '楄', '' => '楶', '' => '楘', '' => '楁', '' => '楴', '' => '楌', '' => '椻', '' => '楋', '' => '椷', '' => '楜', '' => '楏', '' => '楑', '' => '椲', '' => '楒', '' => '椯', '' => '楻', '' => '椼', '' => '歆', '' => '歅', '' => '歃', '' => '歂', '' => '歈', '' => '歁', '' => '殛', '' => '嗀', '' => '毻', '' => '毼', '@' => '毹', 'A' => '毷', 'B' => '毸', 'C' => '溛', 'D' => '滖', 'E' => '滈', 'F' => '溏', 'G' => '滀', 'H' => '溟', 'I' => '溓', 'J' => '溔', 'K' => '溠', 'L' => '溱', 'M' => '溹', 'N' => '滆', 'O' => '滒', 'P' => '溽', 'Q' => '滁', 'R' => '溞', 'S' => '滉', 'T' => '溷', 'U' => '溰', 'V' => '滍', 'W' => '溦', 'X' => '滏', 'Y' => '溲', 'Z' => '溾', '[' => '滃', '\\' => '滜', ']' => '滘', '^' => '溙', '_' => '溒', '`' => '溎', 'a' => '溍', 'b' => '溤', 'c' => '溡', 'd' => '溿', 'e' => '溳', 'f' => '滐', 'g' => '滊', 'h' => '溗', 'i' => '溮', 'j' => '溣', 'k' => '煇', 'l' => '煔', 'm' => '煒', 'n' => '煣', 'o' => '煠', 'p' => '煁', 'q' => '煝', 'r' => '煢', 's' => '煲', 't' => '煸', 'u' => '煪', 'v' => '煡', 'w' => '煂', 'x' => '煘', 'y' => '煃', 'z' => '煋', '{' => '煰', '|' => '煟', '}' => '煐', '~' => '煓', 'ޡ' => '煄', 'ޢ' => '煍', 'ޣ' => '煚', 'ޤ' => '牏', 'ޥ' => '犍', 'ަ' => '犌', 'ާ' => '犑', 'ި' => '犐', 'ީ' => '犎', 'ު' => '猼', 'ޫ' => '獂', 'ެ' => '猻', 'ޭ' => '猺', 'ޮ' => '獀', 'ޯ' => '獊', 'ް' => '獉', 'ޱ' => '瑄', '޲' => '瑊', '޳' => '瑋', '޴' => '瑒', '޵' => '瑑', '޶' => '瑗', '޷' => '瑀', '޸' => '瑏', '޹' => '瑐', '޺' => '瑎', '޻' => '瑂', '޼' => '瑆', '޽' => '瑍', '޾' => '瑔', '޿' => '瓡', '' => '瓿', '' => '瓾', '' => '瓽', '' => '甝', '' => '畹', '' => '畷', '' => '榃', '' => '痯', '' => '瘏', '' => '瘃', '' => '痷', '' => '痾', '' => '痼', '' => '痹', '' => '痸', '' => '瘐', '' => '痻', '' => '痶', '' => '痭', '' => '痵', '' => '痽', '' => '皙', '' => '皵', '' => '盝', '' => '睕', '' => '睟', '' => '睠', '' => '睒', '' => '睖', '' => '睚', '' => '睩', '' => '睧', '' => '睔', '' => '睙', '' => '睭', '' => '矠', '' => '碇', '' => '碚', '' => '碔', '' => '碏', '' => '碄', '' => '碕', '' => '碅', '' => '碆', '' => '碡', '' => '碃', '' => '硹', '' => '碙', '' => '碀', '' => '碖', '' => '硻', '' => '祼', '' => '禂', '' => '祽', '' => '祹', '' => '稑', '' => '稘', '' => '稙', '' => '稒', '' => '稗', '' => '稕', '' => '稢', '' => '稓', '@' => '稛', 'A' => '稐', 'B' => '窣', 'C' => '窢', 'D' => '窞', 'E' => '竫', 'F' => '筦', 'G' => '筤', 'H' => '筭', 'I' => '筴', 'J' => '筩', 'K' => '筲', 'L' => '筥', 'M' => '筳', 'N' => '筱', 'O' => '筰', 'P' => '筡', 'Q' => '筸', 'R' => '筶', 'S' => '筣', 'T' => '粲', 'U' => '粴', 'V' => '粯', 'W' => '綈', 'X' => '綆', 'Y' => '綀', 'Z' => '綍', '[' => '絿', '\\' => '綅', ']' => '絺', '^' => '綎', '_' => '絻', '`' => '綃', 'a' => '絼', 'b' => '綌', 'c' => '綔', 'd' => '綄', 'e' => '絽', 'f' => '綒', 'g' => '罭', 'h' => '罫', 'i' => '罧', 'j' => '罨', 'k' => '罬', 'l' => '羦', 'm' => '羥', 'n' => '羧', 'o' => '翛', 'p' => '翜', 'q' => '耡', 'r' => '腤', 's' => '腠', 't' => '腷', 'u' => '腜', 'v' => '腩', 'w' => '腛', 'x' => '腢', 'y' => '腲', 'z' => '朡', '{' => '腞', '|' => '腶', '}' => '腧', '~' => '腯', 'ߡ' => '腄', 'ߢ' => '腡', 'ߣ' => '舝', 'ߤ' => '艉', 'ߥ' => '艄', 'ߦ' => '艀', 'ߧ' => '艂', 'ߨ' => '艅', 'ߩ' => '蓱', 'ߪ' => '萿', '߫' => '葖', '߬' => '葶', '߭' => '葹', '߮' => '蒏', '߯' => '蒍', '߰' => '葥', '߱' => '葑', '߲' => '葀', '߳' => '蒆', 'ߴ' => '葧', 'ߵ' => '萰', '߶' => '葍', '߷' => '葽', '߸' => '葚', '߹' => '葙', 'ߺ' => '葴', '߻' => '葳', '߼' => '葝', '߽' => '蔇', '߾' => '葞', '߿' => '萷', '' => '萺', '' => '萴', '' => '葺', '' => '葃', '' => '葸', '' => '萲', '' => '葅', '' => '萩', '' => '菙', '' => '葋', '' => '萯', '' => '葂', '' => '萭', '' => '葟', '' => '葰', '' => '萹', '' => '葎', '' => '葌', '' => '葒', '' => '葯', '' => '蓅', '' => '蒎', '' => '萻', '' => '葇', '' => '萶', '' => '萳', '' => '葨', '' => '葾', '' => '葄', '' => '萫', '' => '葠', '' => '葔', '' => '葮', '' => '葐', '' => '蜋', '' => '蜄', '' => '蛷', '' => '蜌', '' => '蛺', '' => '蛖', '' => '蛵', '' => '蝍', '' => '蛸', '' => '蜎', '' => '蜉', '' => '蜁', '' => '蛶', '' => '蜍', '' => '蜅', '' => '裖', '' => '裋', '' => '裍', '' => '裎', '' => '裞', '' => '裛', '' => '裚', '' => '裌', '' => '裐', '' => '覅', '' => '覛', '' => '觟', '' => '觥', '' => '觤', '@' => '觡', 'A' => '觠', 'B' => '觢', 'C' => '觜', 'D' => '触', 'E' => '詶', 'F' => '誆', 'G' => '詿', 'H' => '詡', 'I' => '訿', 'J' => '詷', 'K' => '誂', 'L' => '誄', 'M' => '詵', 'N' => '誃', 'O' => '誁', 'P' => '詴', 'Q' => '詺', 'R' => '谼', 'S' => '豋', 'T' => '豊', 'U' => '豥', 'V' => '豤', 'W' => '豦', 'X' => '貆', 'Y' => '貄', 'Z' => '貅', '[' => '賌', '\\' => '赨', ']' => '赩', '^' => '趑', '_' => '趌', '`' => '趎', 'a' => '趏', 'b' => '趍', 'c' => '趓', 'd' => '趔', 'e' => '趐', 'f' => '趒', 'g' => '跰', 'h' => '跠', 'i' => '跬', 'j' => '跱', 'k' => '跮', 'l' => '跐', 'm' => '跩', 'n' => '跣', 'o' => '跢', 'p' => '跧', 'q' => '跲', 'r' => '跫', 's' => '跴', 't' => '輆', 'u' => '軿', 'v' => '輁', 'w' => '輀', 'x' => '輅', 'y' => '輇', 'z' => '輈', '{' => '輂', '|' => '輋', '}' => '遒', '~' => '逿', '' => '遄', '' => '遉', '' => '逽', '' => '鄐', '' => '鄍', '' => '鄏', '' => '鄑', '' => '鄖', '' => '鄔', '' => '鄋', '' => '鄎', '' => '酮', '' => '酯', '' => '鉈', '' => '鉒', '' => '鈰', '' => '鈺', '' => '鉦', '' => '鈳', '' => '鉥', '' => '鉞', '' => '銃', '' => '鈮', '' => '鉊', '' => '鉆', '' => '鉭', '' => '鉬', '' => '鉏', '' => '鉠', '' => '鉧', '' => '鉯', '' => '鈶', '' => '鉡', '' => '鉰', '' => '鈱', '' => '鉔', '' => '鉣', '' => '鉐', '' => '鉲', '' => '鉎', '' => '鉓', '' => '鉌', '' => '鉖', '' => '鈲', '' => '閟', '' => '閜', '' => '閞', '' => '閛', '' => '隒', '' => '隓', '' => '隑', '' => '隗', '' => '雎', '' => '雺', '' => '雽', '' => '雸', '' => '雵', '' => '靳', '' => '靷', '' => '靸', '' => '靲', '' => '頏', '' => '頍', '' => '頎', '' => '颬', '' => '飶', '' => '飹', '' => '馯', '' => '馲', '' => '馰', '' => '馵', '' => '骭', '' => '骫', '' => '魛', '' => '鳪', '' => '鳭', '' => '鳧', '' => '麀', '' => '黽', '' => '僦', '' => '僔', '' => '僗', '' => '僨', '' => '僳', '' => '僛', '' => '僪', '' => '僝', '' => '僤', '' => '僓', '' => '僬', '' => '僰', '' => '僯', '' => '僣', '' => '僠', '@' => '凘', 'A' => '劀', 'B' => '劁', 'C' => '勩', 'D' => '勫', 'E' => '匰', 'F' => '厬', 'G' => '嘧', 'H' => '嘕', 'I' => '嘌', 'J' => '嘒', 'K' => '嗼', 'L' => '嘏', 'M' => '嘜', 'N' => '嘁', 'O' => '嘓', 'P' => '嘂', 'Q' => '嗺', 'R' => '嘝', 'S' => '嘄', 'T' => '嗿', 'U' => '嗹', 'V' => '墉', 'W' => '塼', 'X' => '墐', 'Y' => '墘', 'Z' => '墆', '[' => '墁', '\\' => '塿', ']' => '塴', '^' => '墋', '_' => '塺', '`' => '墇', 'a' => '墑', 'b' => '墎', 'c' => '塶', 'd' => '墂', 'e' => '墈', 'f' => '塻', 'g' => '墔', 'h' => '墏', 'i' => '壾', 'j' => '奫', 'k' => '嫜', 'l' => '嫮', 'm' => '嫥', 'n' => '嫕', 'o' => '嫪', 'p' => '嫚', 'q' => '嫭', 'r' => '嫫', 's' => '嫳', 't' => '嫢', 'u' => '嫠', 'v' => '嫛', 'w' => '嫬', 'x' => '嫞', 'y' => '嫝', 'z' => '嫙', '{' => '嫨', '|' => '嫟', '}' => '孷', '~' => '寠', '' => '寣', '' => '屣', '' => '嶂', '' => '嶀', '' => '嵽', '' => '嶆', '' => '嵺', '' => '嶁', '' => '嵷', '' => '嶊', '' => '嶉', '' => '嶈', '' => '嵾', '' => '嵼', '' => '嶍', '' => '嵹', '' => '嵿', '' => '幘', '' => '幙', '' => '幓', '' => '廘', '' => '廑', '' => '廗', '' => '廎', '' => '廜', '' => '廕', '' => '廙', '' => '廒', '' => '廔', '' => '彄', '' => '彃', '' => '彯', '' => '徶', '' => '愬', '' => '愨', '' => '慁', '' => '慞', '' => '慱', '' => '慳', '' => '慒', '' => '慓', '' => '慲', '' => '慬', '' => '憀', '' => '慴', '' => '慔', '' => '慺', '' => '慛', '' => '慥', '' => '愻', '' => '慪', '' => '慡', '' => '慖', '' => '戩', '' => '戧', '' => '戫', '' => '搫', '' => '摍', '' => '摛', '' => '摝', '' => '摴', '' => '摶', '' => '摲', '' => '摳', '' => '摽', '' => '摵', '' => '摦', '' => '撦', '' => '摎', '' => '撂', '' => '摞', '' => '摜', '' => '摋', '' => '摓', '' => '摠', '' => '摐', '' => '摿', '' => '搿', '' => '摬', '' => '摫', '' => '摙', '' => '摥', '' => '摷', '' => '敳', '' => '斠', '' => '暡', '' => '暠', '' => '暟', '' => '朅', '' => '朄', '' => '朢', '' => '榱', '' => '榶', '' => '槉', '@' => '榠', 'A' => '槎', 'B' => '榖', 'C' => '榰', 'D' => '榬', 'E' => '榼', 'F' => '榑', 'G' => '榙', 'H' => '榎', 'I' => '榧', 'J' => '榍', 'K' => '榩', 'L' => '榾', 'M' => '榯', 'N' => '榿', 'O' => '槄', 'P' => '榽', 'Q' => '榤', 'R' => '槔', 'S' => '榹', 'T' => '槊', 'U' => '榚', 'V' => '槏', 'W' => '榳', 'X' => '榓', 'Y' => '榪', 'Z' => '榡', '[' => '榞', '\\' => '槙', ']' => '榗', '^' => '榐', '_' => '槂', '`' => '榵', 'a' => '榥', 'b' => '槆', 'c' => '歊', 'd' => '歍', 'e' => '歋', 'f' => '殞', 'g' => '殟', 'h' => '殠', 'i' => '毃', 'j' => '毄', 'k' => '毾', 'l' => '滎', 'm' => '滵', 'n' => '滱', 'o' => '漃', 'p' => '漥', 'q' => '滸', 'r' => '漷', 's' => '滻', 't' => '漮', 'u' => '漉', 'v' => '潎', 'w' => '漙', 'x' => '漚', 'y' => '漧', 'z' => '漘', '{' => '漻', '|' => '漒', '}' => '滭', '~' => '漊', '' => '漶', '' => '潳', '' => '滹', '' => '滮', '' => '漭', '' => '潀', '' => '漰', '' => '漼', '' => '漵', '' => '滫', '' => '漇', '' => '漎', '' => '潃', '' => '漅', '' => '滽', '' => '滶', '' => '漹', '' => '漜', '' => '滼', '' => '漺', '' => '漟', '' => '漍', '' => '漞', '' => '漈', '' => '漡', '' => '熇', '' => '熐', '' => '熉', '' => '熀', '' => '熅', '' => '熂', '' => '熏', '' => '煻', '' => '熆', '' => '熁', '' => '熗', '' => '牄', '' => '牓', '' => '犗', '' => '犕', '' => '犓', '' => '獃', '' => '獍', '' => '獑', '' => '獌', '' => '瑢', '' => '瑳', '' => '瑱', '' => '瑵', '' => '瑲', '' => '瑧', '' => '瑮', '' => '甀', '' => '甂', '' => '甃', '' => '畽', '' => '疐', '' => '瘖', '' => '瘈', '' => '瘌', '' => '瘕', '' => '瘑', '' => '瘊', '' => '瘔', '' => '皸', '' => '瞁', '' => '睼', '' => '瞅', '' => '瞂', '' => '睮', '' => '瞀', '' => '睯', '' => '睾', '' => '瞃', '' => '碲', '' => '碪', '' => '碴', '' => '碭', '' => '碨', '' => '硾', '' => '碫', '' => '碞', '' => '碥', '' => '碠', '' => '碬', '' => '碢', '' => '碤', '' => '禘', '' => '禊', '' => '禋', '' => '禖', '' => '禕', '' => '禔', '' => '禓', '@' => '禗', 'A' => '禈', 'B' => '禒', 'C' => '禐', 'D' => '稫', 'E' => '穊', 'F' => '稰', 'G' => '稯', 'H' => '稨', 'I' => '稦', 'J' => '窨', 'K' => '窫', 'L' => '窬', 'M' => '竮', 'N' => '箈', 'O' => '箜', 'P' => '箊', 'Q' => '箑', 'R' => '箐', 'S' => '箖', 'T' => '箍', 'U' => '箌', 'V' => '箛', 'W' => '箎', 'X' => '箅', 'Y' => '箘', 'Z' => '劄', '[' => '箙', '\\' => '箤', ']' => '箂', '^' => '粻', '_' => '粿', '`' => '粼', 'a' => '粺', 'b' => '綧', 'c' => '綷', 'd' => '緂', 'e' => '綣', 'f' => '綪', 'g' => '緁', 'h' => '緀', 'i' => '緅', 'j' => '綝', 'k' => '緎', 'l' => '緄', 'm' => '緆', 'n' => '緋', 'o' => '緌', 'p' => '綯', 'q' => '綹', 'r' => '綖', 's' => '綼', 't' => '綟', 'u' => '綦', 'v' => '綮', 'w' => '綩', 'x' => '綡', 'y' => '緉', 'z' => '罳', '{' => '翢', '|' => '翣', '}' => '翥', '~' => '翞', '' => '耤', '' => '聝', '' => '聜', '' => '膉', '' => '膆', '' => '膃', '' => '膇', '' => '膍', '' => '膌', '' => '膋', '' => '舕', '' => '蒗', '' => '蒤', '' => '蒡', '' => '蒟', '' => '蒺', '' => '蓎', '' => '蓂', '' => '蒬', '' => '蒮', '' => '蒫', '' => '蒹', '' => '蒴', '' => '蓁', '' => '蓍', '' => '蒪', '' => '蒚', '' => '蒱', '' => '蓐', '' => '蒝', '' => '蒧', '' => '蒻', '' => '蒢', '' => '蒔', '' => '蓇', '' => '蓌', '' => '蒛', '' => '蒩', '' => '蒯', '' => '蒨', '' => '蓖', '' => '蒘', '' => '蒶', '' => '蓏', '' => '蒠', '' => '蓗', '' => '蓔', '' => '蓒', '' => '蓛', '' => '蒰', '' => '蒑', '' => '虡', '' => '蜳', '' => '蜣', '' => '蜨', '' => '蝫', '' => '蝀', '' => '蜮', '' => '蜞', '' => '蜡', '' => '蜙', '' => '蜛', '' => '蝃', '' => '蜬', '' => '蝁', '' => '蜾', '' => '蝆', '' => '蜠', '' => '蜲', '' => '蜪', '' => '蜭', '' => '蜼', '' => '蜒', '' => '蜺', '' => '蜱', '' => '蜵', '' => '蝂', '' => '蜦', '' => '蜧', '' => '蜸', '' => '蜤', '' => '蜚', '' => '蜰', '' => '蜑', '' => '裷', '' => '裧', '' => '裱', '' => '裲', '' => '裺', '' => '裾', '' => '裮', '' => '裼', '' => '裶', '' => '裻', '@' => '裰', 'A' => '裬', 'B' => '裫', 'C' => '覝', 'D' => '覡', 'E' => '覟', 'F' => '覞', 'G' => '觩', 'H' => '觫', 'I' => '觨', 'J' => '誫', 'K' => '誙', 'L' => '誋', 'M' => '誒', 'N' => '誏', 'O' => '誖', 'P' => '谽', 'Q' => '豨', 'R' => '豩', 'S' => '賕', 'T' => '賏', 'U' => '賗', 'V' => '趖', 'W' => '踉', 'X' => '踂', 'Y' => '跿', 'Z' => '踍', '[' => '跽', '\\' => '踊', ']' => '踃', '^' => '踇', '_' => '踆', '`' => '踅', 'a' => '跾', 'b' => '踀', 'c' => '踄', 'd' => '輐', 'e' => '輑', 'f' => '輎', 'g' => '輍', 'h' => '鄣', 'i' => '鄜', 'j' => '鄠', 'k' => '鄢', 'l' => '鄟', 'm' => '鄝', 'n' => '鄚', 'o' => '鄤', 'p' => '鄡', 'q' => '鄛', 'r' => '酺', 's' => '酲', 't' => '酹', 'u' => '酳', 'v' => '銥', 'w' => '銤', 'x' => '鉶', 'y' => '銛', 'z' => '鉺', '{' => '銠', '|' => '銔', '}' => '銪', '~' => '銍', '' => '銦', '' => '銚', '' => '銫', '' => '鉹', '' => '銗', '' => '鉿', '' => '銣', '' => '鋮', '' => '銎', '' => '銂', '' => '銕', '' => '銢', '' => '鉽', '' => '銈', '' => '銡', '' => '銊', '' => '銆', '' => '銌', '' => '銙', '' => '銧', '' => '鉾', '' => '銇', '' => '銩', '' => '銝', '' => '銋', '' => '鈭', '' => '隞', '' => '隡', '' => '雿', '' => '靘', '' => '靽', '' => '靺', '' => '靾', '' => '鞃', '' => '鞀', '' => '鞂', '' => '靻', '' => '鞄', '' => '鞁', '' => '靿', '' => '韎', '' => '韍', '' => '頖', '' => '颭', '' => '颮', '' => '餂', '' => '餀', '' => '餇', '' => '馝', '' => '馜', '' => '駃', '' => '馹', '' => '馻', '' => '馺', '' => '駂', '' => '馽', '' => '駇', '' => '骱', '' => '髣', '' => '髧', '' => '鬾', '' => '鬿', '' => '魠', '' => '魡', '' => '魟', '' => '鳱', '' => '鳲', '' => '鳵', '' => '麧', '' => '僿', '' => '儃', '' => '儰', '' => '僸', '' => '儆', '' => '儇', '' => '僶', '' => '僾', '' => '儋', '' => '儌', '' => '僽', '' => '儊', '' => '劋', '' => '劌', '' => '勱', '' => '勯', '' => '噈', '' => '噂', '' => '噌', '' => '嘵', '' => '噁', '' => '噊', '' => '噉', '' => '噆', '' => '噘', '@' => '噚', 'A' => '噀', 'B' => '嘳', 'C' => '嘽', 'D' => '嘬', 'E' => '嘾', 'F' => '嘸', 'G' => '嘪', 'H' => '嘺', 'I' => '圚', 'J' => '墫', 'K' => '墝', 'L' => '墱', 'M' => '墠', 'N' => '墣', 'O' => '墯', 'P' => '墬', 'Q' => '墥', 'R' => '墡', 'S' => '壿', 'T' => '嫿', 'U' => '嫴', 'V' => '嫽', 'W' => '嫷', 'X' => '嫶', 'Y' => '嬃', 'Z' => '嫸', '[' => '嬂', '\\' => '嫹', ']' => '嬁', '^' => '嬇', '_' => '嬅', '`' => '嬏', 'a' => '屧', 'b' => '嶙', 'c' => '嶗', 'd' => '嶟', 'e' => '嶒', 'f' => '嶢', 'g' => '嶓', 'h' => '嶕', 'i' => '嶠', 'j' => '嶜', 'k' => '嶡', 'l' => '嶚', 'm' => '嶞', 'n' => '幩', 'o' => '幝', 'p' => '幠', 'q' => '幜', 'r' => '緳', 's' => '廛', 't' => '廞', 'u' => '廡', 'v' => '彉', 'w' => '徲', 'x' => '憋', 'y' => '憃', 'z' => '慹', '{' => '憱', '|' => '憰', '}' => '憢', '~' => '憉', '' => '憛', '' => '憓', '' => '憯', '' => '憭', '' => '憟', '' => '憒', '' => '憪', '' => '憡', '' => '憍', '' => '慦', '' => '憳', '' => '戭', '' => '摮', '' => '摰', '' => '撖', '' => '撠', '' => '撅', '' => '撗', '' => '撜', '' => '撏', '' => '撋', '' => '撊', '' => '撌', '' => '撣', '' => '撟', '' => '摨', '' => '撱', '' => '撘', '' => '敶', '' => '敺', '' => '敹', '' => '敻', '' => '斲', '' => '斳', '' => '暵', '' => '暰', '' => '暩', '' => '暲', '' => '暷', '' => '暪', '' => '暯', '' => '樀', '' => '樆', '' => '樗', '' => '槥', '' => '槸', '' => '樕', '' => '槱', '' => '槤', '' => '樠', '' => '槿', '' => '槬', '' => '槢', '' => '樛', '' => '樝', '' => '槾', '' => '樧', '' => '槲', '' => '槮', '' => '樔', '' => '槷', '' => '槧', '' => '橀', '' => '樈', '' => '槦', '' => '槻', '' => '樍', '' => '槼', '' => '槫', '' => '樉', '' => '樄', '' => '樘', '' => '樥', '' => '樏', '' => '槶', '' => '樦', '' => '樇', '' => '槴', '' => '樖', '' => '歑', '' => '殥', '' => '殣', '' => '殢', '' => '殦', '' => '氁', '' => '氀', '' => '毿', '' => '氂', '' => '潁', '' => '漦', '' => '潾', '' => '澇', '' => '濆', '' => '澒', '@' => '澍', 'A' => '澉', 'B' => '澌', 'C' => '潢', 'D' => '潏', 'E' => '澅', 'F' => '潚', 'G' => '澖', 'H' => '潶', 'I' => '潬', 'J' => '澂', 'K' => '潕', 'L' => '潲', 'M' => '潒', 'N' => '潐', 'O' => '潗', 'P' => '澔', 'Q' => '澓', 'R' => '潝', 'S' => '漀', 'T' => '潡', 'U' => '潫', 'V' => '潽', 'W' => '潧', 'X' => '澐', 'Y' => '潓', 'Z' => '澋', '[' => '潩', '\\' => '潿', ']' => '澕', '^' => '潣', '_' => '潷', '`' => '潪', 'a' => '潻', 'b' => '熲', 'c' => '熯', 'd' => '熛', 'e' => '熰', 'f' => '熠', 'g' => '熚', 'h' => '熩', 'i' => '熵', 'j' => '熝', 'k' => '熥', 'l' => '熞', 'm' => '熤', 'n' => '熡', 'o' => '熪', 'p' => '熜', 'q' => '熧', 'r' => '熳', 's' => '犘', 't' => '犚', 'u' => '獘', 'v' => '獒', 'w' => '獞', 'x' => '獟', 'y' => '獠', 'z' => '獝', '{' => '獛', '|' => '獡', '}' => '獚', '~' => '獙', '' => '獢', '' => '璇', '' => '璉', '' => '璊', '' => '璆', '' => '璁', '' => '瑽', '' => '璅', '' => '璈', '' => '瑼', '' => '瑹', '' => '甈', '' => '甇', '' => '畾', '' => '瘥', '' => '瘞', '' => '瘙', '' => '瘝', '' => '瘜', '' => '瘣', '' => '瘚', '' => '瘨', '' => '瘛', '' => '皜', '' => '皝', '' => '皞', '' => '皛', '' => '瞍', '' => '瞏', '' => '瞉', '' => '瞈', '' => '磍', '' => '碻', '' => '磏', '' => '磌', '' => '磑', '' => '磎', '' => '磔', '' => '磈', '' => '磃', '' => '磄', '' => '磉', '' => '禚', '' => '禡', '' => '禠', '' => '禜', '' => '禢', '' => '禛', '' => '歶', '' => '稹', '' => '窲', '' => '窴', '' => '窳', '' => '箷', '' => '篋', '' => '箾', '' => '箬', '' => '篎', '' => '箯', '' => '箹', '' => '篊', '' => '箵', '' => '糅', '' => '糈', '' => '糌', '' => '糋', '' => '緷', '' => '緛', '' => '緪', '' => '緧', '' => '緗', '' => '緡', '' => '縃', '' => '緺', '' => '緦', '' => '緶', '' => '緱', '' => '緰', '' => '緮', '' => '緟', '' => '罶', '' => '羬', '' => '羰', '' => '羭', '' => '翭', '' => '翫', '' => '翪', '' => '翬', '' => '翦', '' => '翨', '' => '聤', '' => '聧', '' => '膣', '' => '膟', '@' => '膞', 'A' => '膕', 'B' => '膢', 'C' => '膙', 'D' => '膗', 'E' => '舖', 'F' => '艏', 'G' => '艓', 'H' => '艒', 'I' => '艐', 'J' => '艎', 'K' => '艑', 'L' => '蔤', 'M' => '蔻', 'N' => '蔏', 'O' => '蔀', 'P' => '蔩', 'Q' => '蔎', 'R' => '蔉', 'S' => '蔍', 'T' => '蔟', 'U' => '蔊', 'V' => '蔧', 'W' => '蔜', 'X' => '蓻', 'Y' => '蔫', 'Z' => '蓺', '[' => '蔈', '\\' => '蔌', ']' => '蓴', '^' => '蔪', '_' => '蓲', '`' => '蔕', 'a' => '蓷', 'b' => '蓫', 'c' => '蓳', 'd' => '蓼', 'e' => '蔒', 'f' => '蓪', 'g' => '蓩', 'h' => '蔖', 'i' => '蓾', 'j' => '蔨', 'k' => '蔝', 'l' => '蔮', 'm' => '蔂', 'n' => '蓽', 'o' => '蔞', 'p' => '蓶', 'q' => '蔱', 'r' => '蔦', 's' => '蓧', 't' => '蓨', 'u' => '蓰', 'v' => '蓯', 'w' => '蓹', 'x' => '蔘', 'y' => '蔠', 'z' => '蔰', '{' => '蔋', '|' => '蔙', '}' => '蔯', '~' => '虢', '' => '蝖', '' => '蝣', '' => '蝤', '' => '蝷', '' => '蟡', '' => '蝳', '' => '蝘', '' => '蝔', '' => '蝛', '' => '蝒', '' => '蝡', '' => '蝚', '' => '蝑', '' => '蝞', '' => '蝭', '' => '蝪', '' => '蝐', '' => '蝎', '' => '蝟', '' => '蝝', '' => '蝯', '' => '蝬', '' => '蝺', '' => '蝮', '' => '蝜', '' => '蝥', '' => '蝏', '' => '蝻', '' => '蝵', '' => '蝢', '' => '蝧', '' => '蝩', '' => '衚', '' => '褅', '' => '褌', '' => '褔', '' => '褋', '' => '褗', '' => '褘', '' => '褙', '' => '褆', '' => '褖', '' => '褑', '' => '褎', '' => '褉', '' => '覢', '' => '覤', '' => '覣', '' => '觭', '' => '觰', '' => '觬', '' => '諏', '' => '諆', '' => '誸', '' => '諓', '' => '諑', '' => '諔', '' => '諕', '' => '誻', '' => '諗', '' => '誾', '' => '諀', '' => '諅', '' => '諘', '' => '諃', '' => '誺', '' => '誽', '' => '諙', '' => '谾', '' => '豍', '' => '貏', '' => '賥', '' => '賟', '' => '賙', '' => '賨', '' => '賚', '' => '賝', '' => '賧', '' => '趠', '' => '趜', '' => '趡', '' => '趛', '' => '踠', '' => '踣', '' => '踥', '' => '踤', '' => '踮', '' => '踕', '' => '踛', '' => '踖', '' => '踑', '' => '踙', '' => '踦', '' => '踧', '@' => '踔', 'A' => '踒', 'B' => '踘', 'C' => '踓', 'D' => '踜', 'E' => '踗', 'F' => '踚', 'G' => '輬', 'H' => '輤', 'I' => '輘', 'J' => '輚', 'K' => '輠', 'L' => '輣', 'M' => '輖', 'N' => '輗', 'O' => '遳', 'P' => '遰', 'Q' => '遯', 'R' => '遧', 'S' => '遫', 'T' => '鄯', 'U' => '鄫', 'V' => '鄩', 'W' => '鄪', 'X' => '鄲', 'Y' => '鄦', 'Z' => '鄮', '[' => '醅', '\\' => '醆', ']' => '醊', '^' => '醁', '_' => '醂', '`' => '醄', 'a' => '醀', 'b' => '鋐', 'c' => '鋃', 'd' => '鋄', 'e' => '鋀', 'f' => '鋙', 'g' => '銶', 'h' => '鋏', 'i' => '鋱', 'j' => '鋟', 'k' => '鋘', 'l' => '鋩', 'm' => '鋗', 'n' => '鋝', 'o' => '鋌', 'p' => '鋯', 'q' => '鋂', 'r' => '鋨', 's' => '鋊', 't' => '鋈', 'u' => '鋎', 'v' => '鋦', 'w' => '鋍', 'x' => '鋕', 'y' => '鋉', 'z' => '鋠', '{' => '鋞', '|' => '鋧', '}' => '鋑', '~' => '鋓', '' => '銵', '' => '鋡', '' => '鋆', '' => '銴', '' => '镼', '' => '閬', '' => '閫', '' => '閮', '' => '閰', '' => '隤', '' => '隢', '' => '雓', '' => '霅', '' => '霈', '' => '霂', '' => '靚', '' => '鞊', '' => '鞎', '' => '鞈', '' => '韐', '' => '韏', '' => '頞', '' => '頝', '' => '頦', '' => '頩', '' => '頨', '' => '頠', '' => '頛', '' => '頧', '' => '颲', '' => '餈', '' => '飺', '' => '餑', '' => '餔', '' => '餖', '' => '餗', '' => '餕', '' => '駜', '' => '駍', '' => '駏', '' => '駓', '' => '駔', '' => '駎', '' => '駉', '' => '駖', '' => '駘', '' => '駋', '' => '駗', '' => '駌', '' => '骳', '' => '髬', '' => '髫', '' => '髳', '' => '髲', '' => '髱', '' => '魆', '' => '魃', '' => '魧', '' => '魴', '' => '魱', '' => '魦', '' => '魶', '' => '魵', '' => '魰', '' => '魨', '' => '魤', '' => '魬', '' => '鳼', '' => '鳺', '' => '鳽', '' => '鳿', '' => '鳷', '' => '鴇', '' => '鴀', '' => '鳹', '' => '鳻', '' => '鴈', '' => '鴅', '' => '鴄', '' => '麃', '' => '黓', '' => '鼏', '' => '鼐', '' => '儜', '' => '儓', '' => '儗', '' => '儚', '' => '儑', '' => '凞', '' => '匴', '' => '叡', '' => '噰', '' => '噠', '' => '噮', '@' => '噳', 'A' => '噦', 'B' => '噣', 'C' => '噭', 'D' => '噲', 'E' => '噞', 'F' => '噷', 'G' => '圜', 'H' => '圛', 'I' => '壈', 'J' => '墽', 'K' => '壉', 'L' => '墿', 'M' => '墺', 'N' => '壂', 'O' => '墼', 'P' => '壆', 'Q' => '嬗', 'R' => '嬙', 'S' => '嬛', 'T' => '嬡', 'U' => '嬔', 'V' => '嬓', 'W' => '嬐', 'X' => '嬖', 'Y' => '嬨', 'Z' => '嬚', '[' => '嬠', '\\' => '嬞', ']' => '寯', '^' => '嶬', '_' => '嶱', '`' => '嶩', 'a' => '嶧', 'b' => '嶵', 'c' => '嶰', 'd' => '嶮', 'e' => '嶪', 'f' => '嶨', 'g' => '嶲', 'h' => '嶭', 'i' => '嶯', 'j' => '嶴', 'k' => '幧', 'l' => '幨', 'm' => '幦', 'n' => '幯', 'o' => '廩', 'p' => '廧', 'q' => '廦', 'r' => '廨', 's' => '廥', 't' => '彋', 'u' => '徼', 'v' => '憝', 'w' => '憨', 'x' => '憖', 'y' => '懅', 'z' => '憴', '{' => '懆', '|' => '懁', '}' => '懌', '~' => '憺', '' => '憿', '' => '憸', '' => '憌', '' => '擗', '' => '擖', '' => '擐', '' => '擏', '' => '擉', '' => '撽', '' => '撉', '' => '擃', '' => '擛', '' => '擳', '' => '擙', '' => '攳', '' => '敿', '' => '敼', '' => '斢', '' => '曈', '' => '暾', '' => '曀', '' => '曊', '' => '曋', '' => '曏', '' => '暽', '' => '暻', '' => '暺', '' => '曌', '' => '朣', '' => '樴', '' => '橦', '' => '橉', '' => '橧', '' => '樲', '' => '橨', '' => '樾', '' => '橝', '' => '橭', '' => '橶', '' => '橛', '' => '橑', '' => '樨', '' => '橚', '' => '樻', '' => '樿', '' => '橁', '' => '橪', '' => '橤', '' => '橐', '' => '橏', '' => '橔', '' => '橯', '' => '橩', '' => '橠', '' => '樼', '' => '橞', '' => '橖', '' => '橕', '' => '橍', '' => '橎', '' => '橆', '' => '歕', '' => '歔', '' => '歖', '' => '殧', '' => '殪', '' => '殫', '' => '毈', '' => '毇', '' => '氄', '' => '氃', '' => '氆', '' => '澭', '' => '濋', '' => '澣', '' => '濇', '' => '澼', '' => '濎', '' => '濈', '' => '潞', '' => '濄', '' => '澽', '' => '澞', '' => '濊', '' => '澨', '' => '瀄', '' => '澥', '' => '澮', '' => '澺', '' => '澬', '' => '澪', '' => '濏', '' => '澿', '' => '澸', '@' => '澢', 'A' => '濉', 'B' => '澫', 'C' => '濍', 'D' => '澯', 'E' => '澲', 'F' => '澰', 'G' => '燅', 'H' => '燂', 'I' => '熿', 'J' => '熸', 'K' => '燖', 'L' => '燀', 'M' => '燁', 'N' => '燋', 'O' => '燔', 'P' => '燊', 'Q' => '燇', 'R' => '燏', 'S' => '熽', 'T' => '燘', 'U' => '熼', 'V' => '燆', 'W' => '燚', 'X' => '燛', 'Y' => '犝', 'Z' => '犞', '[' => '獩', '\\' => '獦', ']' => '獧', '^' => '獬', '_' => '獥', '`' => '獫', 'a' => '獪', 'b' => '瑿', 'c' => '璚', 'd' => '璠', 'e' => '璔', 'f' => '璒', 'g' => '璕', 'h' => '璡', 'i' => '甋', 'j' => '疀', 'k' => '瘯', 'l' => '瘭', 'm' => '瘱', 'n' => '瘽', 'o' => '瘳', 'p' => '瘼', 'q' => '瘵', 'r' => '瘲', 's' => '瘰', 't' => '皻', 'u' => '盦', 'v' => '瞚', 'w' => '瞝', 'x' => '瞡', 'y' => '瞜', 'z' => '瞛', '{' => '瞢', '|' => '瞣', '}' => '瞕', '~' => '瞙', '' => '瞗', '' => '磝', '' => '磩', '' => '磥', '' => '磪', '' => '磞', '' => '磣', '' => '磛', '' => '磡', '' => '磢', '' => '磭', '' => '磟', '' => '磠', '' => '禤', '' => '穄', '' => '穈', '' => '穇', '' => '窶', '' => '窸', '' => '窵', '' => '窱', '' => '窷', '' => '篞', '' => '篣', '' => '篧', '' => '篝', '' => '篕', '' => '篥', '' => '篚', '' => '篨', '' => '篹', '' => '篔', '' => '篪', '' => '篢', '' => '篜', '' => '篫', '' => '篘', '' => '篟', '' => '糒', '' => '糔', '' => '糗', '' => '糐', '' => '糑', '' => '縒', '' => '縡', '' => '縗', '' => '縌', '' => '縟', '' => '縠', '' => '縓', '' => '縎', '' => '縜', '' => '縕', '' => '縚', '' => '縢', '' => '縋', '' => '縏', '' => '縖', '' => '縍', '' => '縔', '' => '縥', '' => '縤', '' => '罃', '' => '罻', '' => '罼', '' => '罺', '' => '羱', '' => '翯', '' => '耪', '' => '耩', '' => '聬', '' => '膱', '' => '膦', '' => '膮', '' => '膹', '' => '膵', '' => '膫', '' => '膰', '' => '膬', '' => '膴', '' => '膲', '' => '膷', '' => '膧', '' => '臲', '' => '艕', '' => '艖', '' => '艗', '' => '蕖', '' => '蕅', '' => '蕫', '' => '蕍', '' => '蕓', '' => '蕡', '' => '蕘', '@' => '蕀', 'A' => '蕆', 'B' => '蕤', 'C' => '蕁', 'D' => '蕢', 'E' => '蕄', 'F' => '蕑', 'G' => '蕇', 'H' => '蕣', 'I' => '蔾', 'J' => '蕛', 'K' => '蕱', 'L' => '蕎', 'M' => '蕮', 'N' => '蕵', 'O' => '蕕', 'P' => '蕧', 'Q' => '蕠', 'R' => '薌', 'S' => '蕦', 'T' => '蕝', 'U' => '蕔', 'V' => '蕥', 'W' => '蕬', 'X' => '虣', 'Y' => '虥', 'Z' => '虤', '[' => '螛', '\\' => '螏', ']' => '螗', '^' => '螓', '_' => '螒', '`' => '螈', 'a' => '螁', 'b' => '螖', 'c' => '螘', 'd' => '蝹', 'e' => '螇', 'f' => '螣', 'g' => '螅', 'h' => '螐', 'i' => '螑', 'j' => '螝', 'k' => '螄', 'l' => '螔', 'm' => '螜', 'n' => '螚', 'o' => '螉', 'p' => '褞', 'q' => '褦', 'r' => '褰', 's' => '褭', 't' => '褮', 'u' => '褧', 'v' => '褱', 'w' => '褢', 'x' => '褩', 'y' => '褣', 'z' => '褯', '{' => '褬', '|' => '褟', '}' => '觱', '~' => '諠', '' => '諢', '' => '諲', '' => '諴', '' => '諵', '' => '諝', '' => '謔', '' => '諤', '' => '諟', '' => '諰', '' => '諈', '' => '諞', '' => '諡', '' => '諨', '' => '諿', '' => '諯', '' => '諻', '' => '貑', '' => '貒', '' => '貐', '' => '賵', '' => '賮', '' => '賱', '' => '賰', '' => '賳', '' => '赬', '' => '赮', '' => '趥', '' => '趧', '' => '踳', '' => '踾', '' => '踸', '' => '蹀', '' => '蹅', '' => '踶', '' => '踼', '' => '踽', '' => '蹁', '' => '踰', '' => '踿', '' => '躽', '' => '輶', '' => '輮', '' => '輵', '' => '輲', '' => '輹', '' => '輷', '' => '輴', '' => '遶', '' => '遹', '' => '遻', '' => '邆', '' => '郺', '' => '鄳', '' => '鄵', '' => '鄶', '' => '醓', '' => '醐', '' => '醑', '' => '醍', '' => '醏', '' => '錧', '' => '錞', '' => '錈', '' => '錟', '' => '錆', '' => '錏', '' => '鍺', '' => '錸', '' => '錼', '' => '錛', '' => '錣', '' => '錒', '' => '錁', '' => '鍆', '' => '錭', '' => '錎', '' => '錍', '' => '鋋', '' => '錝', '' => '鋺', '' => '錥', '' => '錓', '' => '鋹', '' => '鋷', '' => '錴', '' => '錂', '' => '錤', '' => '鋿', '' => '錩', '' => '錹', '' => '錵', '' => '錪', '' => '錔', '' => '錌', '@' => '錋', 'A' => '鋾', 'B' => '錉', 'C' => '錀', 'D' => '鋻', 'E' => '錖', 'F' => '閼', 'G' => '闍', 'H' => '閾', 'I' => '閹', 'J' => '閺', 'K' => '閶', 'L' => '閿', 'M' => '閵', 'N' => '閽', 'O' => '隩', 'P' => '雔', 'Q' => '霋', 'R' => '霒', 'S' => '霐', 'T' => '鞙', 'U' => '鞗', 'V' => '鞔', 'W' => '韰', 'X' => '韸', 'Y' => '頵', 'Z' => '頯', '[' => '頲', '\\' => '餤', ']' => '餟', '^' => '餧', '_' => '餩', '`' => '馞', 'a' => '駮', 'b' => '駬', 'c' => '駥', 'd' => '駤', 'e' => '駰', 'f' => '駣', 'g' => '駪', 'h' => '駩', 'i' => '駧', 'j' => '骹', 'k' => '骿', 'l' => '骴', 'm' => '骻', 'n' => '髶', 'o' => '髺', 'p' => '髹', 'q' => '髷', 'r' => '鬳', 's' => '鮀', 't' => '鮅', 'u' => '鮇', 'v' => '魼', 'w' => '魾', 'x' => '魻', 'y' => '鮂', 'z' => '鮓', '{' => '鮒', '|' => '鮐', '}' => '魺', '~' => '鮕', '' => '魽', '' => '鮈', '' => '鴥', '' => '鴗', '' => '鴠', '' => '鴞', '' => '鴔', '' => '鴩', '' => '鴝', '' => '鴘', '' => '鴢', '' => '鴐', '' => '鴙', '' => '鴟', '' => '麈', '' => '麆', '' => '麇', '' => '麮', '' => '麭', '' => '黕', '' => '黖', '' => '黺', '' => '鼒', '' => '鼽', '' => '儦', '' => '儥', '' => '儢', '' => '儤', '' => '儠', '' => '儩', '' => '勴', '' => '嚓', '' => '嚌', '' => '嚍', '' => '嚆', '' => '嚄', '' => '嚃', '' => '噾', '' => '嚂', '' => '噿', '' => '嚁', '' => '壖', '' => '壔', '' => '壏', '' => '壒', '' => '嬭', '' => '嬥', '' => '嬲', '' => '嬣', '' => '嬬', '' => '嬧', '' => '嬦', '' => '嬯', '' => '嬮', '' => '孻', '' => '寱', '' => '寲', '' => '嶷', '' => '幬', '' => '幪', '' => '徾', '' => '徻', '' => '懃', '' => '憵', '' => '憼', '' => '懧', '' => '懠', '' => '懥', '' => '懤', '' => '懨', '' => '懞', '' => '擯', '' => '擩', '' => '擣', '' => '擫', '' => '擤', '' => '擨', '' => '斁', '' => '斀', '' => '斶', '' => '旚', '' => '曒', '' => '檍', '' => '檖', '' => '檁', '' => '檥', '' => '檉', '' => '檟', '' => '檛', '' => '檡', '' => '檞', '' => '檇', '' => '檓', '' => '檎', '@' => '檕', 'A' => '檃', 'B' => '檨', 'C' => '檤', 'D' => '檑', 'E' => '橿', 'F' => '檦', 'G' => '檚', 'H' => '檅', 'I' => '檌', 'J' => '檒', 'K' => '歛', 'L' => '殭', 'M' => '氉', 'N' => '濌', 'O' => '澩', 'P' => '濴', 'Q' => '濔', 'R' => '濣', 'S' => '濜', 'T' => '濭', 'U' => '濧', 'V' => '濦', 'W' => '濞', 'X' => '濲', 'Y' => '濝', 'Z' => '濢', '[' => '濨', '\\' => '燡', ']' => '燱', '^' => '燨', '_' => '燲', '`' => '燤', 'a' => '燰', 'b' => '燢', 'c' => '獳', 'd' => '獮', 'e' => '獯', 'f' => '璗', 'g' => '璲', 'h' => '璫', 'i' => '璐', 'j' => '璪', 'k' => '璭', 'l' => '璱', 'm' => '璥', 'n' => '璯', 'o' => '甐', 'p' => '甑', 'q' => '甒', 'r' => '甏', 's' => '疄', 't' => '癃', 'u' => '癈', 'v' => '癉', 'w' => '癇', 'x' => '皤', 'y' => '盩', 'z' => '瞵', '{' => '瞫', '|' => '瞲', '}' => '瞷', '~' => '瞶', '' => '瞴', '' => '瞱', '' => '瞨', '' => '矰', '' => '磳', '' => '磽', '' => '礂', '' => '磻', '' => '磼', '' => '磲', '' => '礅', '' => '磹', '' => '磾', '' => '礄', '' => '禫', '' => '禨', '' => '穜', '' => '穛', '' => '穖', '' => '穘', '' => '穔', '' => '穚', '' => '窾', '' => '竀', '' => '竁', '' => '簅', '' => '簏', '' => '篲', '' => '簀', '' => '篿', '' => '篻', '' => '簎', '' => '篴', '' => '簋', '' => '篳', '' => '簂', '' => '簉', '' => '簃', '' => '簁', '' => '篸', '' => '篽', '' => '簆', '' => '篰', '' => '篱', '' => '簐', '' => '簊', '' => '糨', '' => '縭', '' => '縼', '' => '繂', '' => '縳', '' => '顈', '' => '縸', '' => '縪', '' => '繉', '' => '繀', '' => '繇', '' => '縩', '' => '繌', '' => '縰', '' => '縻', '' => '縶', '' => '繄', '' => '縺', '' => '罅', '' => '罿', '' => '罾', '' => '罽', '' => '翴', '' => '翲', '' => '耬', '' => '膻', '' => '臄', '' => '臌', '' => '臊', '' => '臅', '' => '臇', '' => '膼', '' => '臩', '' => '艛', '' => '艚', '' => '艜', '' => '薃', '' => '薀', '' => '薏', '' => '薧', '' => '薕', '' => '薠', '' => '薋', '' => '薣', '' => '蕻', '' => '薤', '' => '薚', '' => '薞', '@' => '蕷', 'A' => '蕼', 'B' => '薉', 'C' => '薡', 'D' => '蕺', 'E' => '蕸', 'F' => '蕗', 'G' => '薎', 'H' => '薖', 'I' => '薆', 'J' => '薍', 'K' => '薙', 'L' => '薝', 'M' => '薁', 'N' => '薢', 'O' => '薂', 'P' => '薈', 'Q' => '薅', 'R' => '蕹', 'S' => '蕶', 'T' => '薘', 'U' => '薐', 'V' => '薟', 'W' => '虨', 'X' => '螾', 'Y' => '螪', 'Z' => '螭', '[' => '蟅', '\\' => '螰', ']' => '螬', '^' => '螹', '_' => '螵', '`' => '螼', 'a' => '螮', 'b' => '蟉', 'c' => '蟃', 'd' => '蟂', 'e' => '蟌', 'f' => '螷', 'g' => '螯', 'h' => '蟄', 'i' => '蟊', 'j' => '螴', 'k' => '螶', 'l' => '螿', 'm' => '螸', 'n' => '螽', 'o' => '蟞', 'p' => '螲', 'q' => '褵', 'r' => '褳', 's' => '褼', 't' => '褾', 'u' => '襁', 'v' => '襒', 'w' => '褷', 'x' => '襂', 'y' => '覭', 'z' => '覯', '{' => '覮', '|' => '觲', '}' => '觳', '~' => '謞', '' => '謘', '' => '謖', '' => '謑', '' => '謅', '' => '謋', '' => '謢', '' => '謏', '' => '謒', '' => '謕', '' => '謇', '' => '謍', '' => '謈', '' => '謆', '' => '謜', '' => '謓', '' => '謚', '' => '豏', '' => '豰', '' => '豲', '' => '豱', '' => '豯', '' => '貕', '' => '貔', '' => '賹', '' => '赯', '' => '蹎', '' => '蹍', '' => '蹓', '' => '蹐', '' => '蹌', '' => '蹇', '' => '轃', '' => '轀', '' => '邅', '' => '遾', '' => '鄸', '' => '醚', '' => '醢', '' => '醛', '' => '醙', '' => '醟', '' => '醡', '' => '醝', '' => '醠', '' => '鎡', '' => '鎃', '' => '鎯', '' => '鍤', '' => '鍖', '' => '鍇', '' => '鍼', '' => '鍘', '' => '鍜', '' => '鍶', '' => '鍉', '' => '鍐', '' => '鍑', '' => '鍠', '' => '鍭', '' => '鎏', '' => '鍌', '' => '鍪', '' => '鍹', '' => '鍗', '' => '鍕', '' => '鍒', '' => '鍏', '' => '鍱', '' => '鍷', '' => '鍻', '' => '鍡', '' => '鍞', '' => '鍣', '' => '鍧', '' => '鎀', '' => '鍎', '' => '鍙', '' => '闇', '' => '闀', '' => '闉', '' => '闃', '' => '闅', '' => '閷', '' => '隮', '' => '隰', '' => '隬', '' => '霠', '' => '霟', '' => '霘', '' => '霝', '' => '霙', '' => '鞚', '' => '鞡', '' => '鞜', '@' => '鞞', 'A' => '鞝', 'B' => '韕', 'C' => '韔', 'D' => '韱', 'E' => '顁', 'F' => '顄', 'G' => '顊', 'H' => '顉', 'I' => '顅', 'J' => '顃', 'K' => '餥', 'L' => '餫', 'M' => '餬', 'N' => '餪', 'O' => '餳', 'P' => '餲', 'Q' => '餯', 'R' => '餭', 'S' => '餱', 'T' => '餰', 'U' => '馘', 'V' => '馣', 'W' => '馡', 'X' => '騂', 'Y' => '駺', 'Z' => '駴', '[' => '駷', '\\' => '駹', ']' => '駸', '^' => '駶', '_' => '駻', '`' => '駽', 'a' => '駾', 'b' => '駼', 'c' => '騃', 'd' => '骾', 'e' => '髾', 'f' => '髽', 'g' => '鬁', 'h' => '髼', 'i' => '魈', 'j' => '鮚', 'k' => '鮨', 'l' => '鮞', 'm' => '鮛', 'n' => '鮦', 'o' => '鮡', 'p' => '鮥', 'q' => '鮤', 'r' => '鮆', 's' => '鮢', 't' => '鮠', 'u' => '鮯', 'v' => '鴳', 'w' => '鵁', 'x' => '鵧', 'y' => '鴶', 'z' => '鴮', '{' => '鴯', '|' => '鴱', '}' => '鴸', '~' => '鴰', '' => '鵅', '' => '鵂', '' => '鵃', '' => '鴾', '' => '鴷', '' => '鵀', '' => '鴽', '' => '翵', '' => '鴭', '' => '麊', '' => '麉', '' => '麍', '' => '麰', '' => '黈', '' => '黚', '' => '黻', '' => '黿', '' => '鼤', '' => '鼣', '' => '鼢', '' => '齔', '' => '龠', '' => '儱', '' => '儭', '' => '儮', '' => '嚘', '' => '嚜', '' => '嚗', '' => '嚚', '' => '嚝', '' => '嚙', '' => '奰', '' => '嬼', '' => '屩', '' => '屪', '' => '巀', '' => '幭', '' => '幮', '' => '懘', '' => '懟', '' => '懭', '' => '懮', '' => '懱', '' => '懪', '' => '懰', '' => '懫', '' => '懖', '' => '懩', '' => '擿', '' => '攄', '' => '擽', '' => '擸', '' => '攁', '' => '攃', '' => '擼', '' => '斔', '' => '旛', '' => '曚', '' => '曛', '' => '曘', '' => '櫅', '' => '檹', '' => '檽', '' => '櫡', '' => '櫆', '' => '檺', '' => '檶', '' => '檷', '' => '櫇', '' => '檴', '' => '檭', '' => '歞', '' => '毉', '' => '氋', '' => '瀇', '' => '瀌', '' => '瀍', '' => '瀁', '' => '瀅', '' => '瀔', '' => '瀎', '' => '濿', '' => '瀀', '' => '濻', '' => '瀦', '' => '濼', '' => '濷', '' => '瀊', '' => '爁', '' => '燿', '' => '燹', '' => '爃', '' => '燽', '' => '獶', '@' => '璸', 'A' => '瓀', 'B' => '璵', 'C' => '瓁', 'D' => '璾', 'E' => '璶', 'F' => '璻', 'G' => '瓂', 'H' => '甔', 'I' => '甓', 'J' => '癜', 'K' => '癤', 'L' => '癙', 'M' => '癐', 'N' => '癓', 'O' => '癗', 'P' => '癚', 'Q' => '皦', 'R' => '皽', 'S' => '盬', 'T' => '矂', 'U' => '瞺', 'V' => '磿', 'W' => '礌', 'X' => '礓', 'Y' => '礔', 'Z' => '礉', '[' => '礐', '\\' => '礒', ']' => '礑', '^' => '禭', '_' => '禬', '`' => '穟', 'a' => '簜', 'b' => '簩', 'c' => '簙', 'd' => '簠', 'e' => '簟', 'f' => '簭', 'g' => '簝', 'h' => '簦', 'i' => '簨', 'j' => '簢', 'k' => '簥', 'l' => '簰', 'm' => '繜', 'n' => '繐', 'o' => '繖', 'p' => '繣', 'q' => '繘', 'r' => '繢', 's' => '繟', 't' => '繑', 'u' => '繠', 'v' => '繗', 'w' => '繓', 'x' => '羵', 'y' => '羳', 'z' => '翷', '{' => '翸', '|' => '聵', '}' => '臑', '~' => '臒', '' => '臐', '' => '艟', '' => '艞', '' => '薴', '' => '藆', '' => '藀', '' => '藃', '' => '藂', '' => '薳', '' => '薵', '' => '薽', '' => '藇', '' => '藄', '' => '薿', '' => '藋', '' => '藎', '' => '藈', '' => '藅', '' => '薱', '' => '薶', '' => '藒', '' => '蘤', '' => '薸', '' => '薷', '' => '薾', '' => '虩', '' => '蟧', '' => '蟦', '' => '蟢', '' => '蟛', '' => '蟫', '' => '蟪', '' => '蟥', '' => '蟟', '' => '蟳', '' => '蟤', '' => '蟔', '' => '蟜', '' => '蟓', '' => '蟭', '' => '蟘', '' => '蟣', '' => '螤', '' => '蟗', '' => '蟙', '' => '蠁', '' => '蟴', '' => '蟨', '' => '蟝', '' => '襓', '' => '襋', '' => '襏', '' => '襌', '' => '襆', '' => '襐', '' => '襑', '' => '襉', '' => '謪', '' => '謧', '' => '謣', '' => '謳', '' => '謰', '' => '謵', '' => '譇', '' => '謯', '' => '謼', '' => '謾', '' => '謱', '' => '謥', '' => '謷', '' => '謦', '' => '謶', '' => '謮', '' => '謤', '' => '謻', '' => '謽', '' => '謺', '' => '豂', '' => '豵', '' => '貙', '' => '貘', '' => '貗', '' => '賾', '' => '贄', '' => '贂', '' => '贀', '' => '蹜', '' => '蹢', '' => '蹠', '' => '蹗', '' => '蹖', '' => '蹞', '' => '蹥', '' => '蹧', '@' => '蹛', 'A' => '蹚', 'B' => '蹡', 'C' => '蹝', 'D' => '蹩', 'E' => '蹔', 'F' => '轆', 'G' => '轇', 'H' => '轈', 'I' => '轋', 'J' => '鄨', 'K' => '鄺', 'L' => '鄻', 'M' => '鄾', 'N' => '醨', 'O' => '醥', 'P' => '醧', 'Q' => '醯', 'R' => '醪', 'S' => '鎵', 'T' => '鎌', 'U' => '鎒', 'V' => '鎷', 'W' => '鎛', 'X' => '鎝', 'Y' => '鎉', 'Z' => '鎧', '[' => '鎎', '\\' => '鎪', ']' => '鎞', '^' => '鎦', '_' => '鎕', '`' => '鎈', 'a' => '鎙', 'b' => '鎟', 'c' => '鎍', 'd' => '鎱', 'e' => '鎑', 'f' => '鎲', 'g' => '鎤', 'h' => '鎨', 'i' => '鎴', 'j' => '鎣', 'k' => '鎥', 'l' => '闒', 'm' => '闓', 'n' => '闑', 'o' => '隳', 'p' => '雗', 'q' => '雚', 'r' => '巂', 's' => '雟', 't' => '雘', 'u' => '雝', 'v' => '霣', 'w' => '霢', 'x' => '霥', 'y' => '鞬', 'z' => '鞮', '{' => '鞨', '|' => '鞫', '}' => '鞤', '~' => '鞪', '' => '鞢', '' => '鞥', '' => '韗', '' => '韙', '' => '韖', '' => '韘', '' => '韺', '' => '顐', '' => '顑', '' => '顒', '' => '颸', '' => '饁', '' => '餼', '' => '餺', '' => '騏', '' => '騋', '' => '騉', '' => '騍', '' => '騄', '' => '騑', '' => '騊', '' => '騅', '' => '騇', '' => '騆', '' => '髀', '' => '髜', '' => '鬈', '' => '鬄', '' => '鬅', '' => '鬩', '' => '鬵', '' => '魊', '' => '魌', '' => '魋', '' => '鯇', '' => '鯆', '' => '鯃', '' => '鮿', '' => '鯁', '' => '鮵', '' => '鮸', '' => '鯓', '' => '鮶', '' => '鯄', '' => '鮹', '' => '鮽', '' => '鵜', '' => '鵓', '' => '鵏', '' => '鵊', '' => '鵛', '' => '鵋', '' => '鵙', '' => '鵖', '' => '鵌', '' => '鵗', '' => '鵒', '' => '鵔', '' => '鵟', '' => '鵘', '' => '鵚', '' => '麎', '' => '麌', '' => '黟', '' => '鼁', '' => '鼀', '' => '鼖', '' => '鼥', '' => '鼫', '' => '鼪', '' => '鼩', '' => '鼨', '' => '齌', '' => '齕', '' => '儴', '' => '儵', '' => '劖', '' => '勷', '' => '厴', '' => '嚫', '' => '嚭', '' => '嚦', '' => '嚧', '' => '嚪', '' => '嚬', '' => '壚', '' => '壝', '' => '壛', '' => '夒', '' => '嬽', '' => '嬾', '' => '嬿', '' => '巃', '' => '幰', '@' => '徿', 'A' => '懻', 'B' => '攇', 'C' => '攐', 'D' => '攍', 'E' => '攉', 'F' => '攌', 'G' => '攎', 'H' => '斄', 'I' => '旞', 'J' => '旝', 'K' => '曞', 'L' => '櫧', 'M' => '櫠', 'N' => '櫌', 'O' => '櫑', 'P' => '櫙', 'Q' => '櫋', 'R' => '櫟', 'S' => '櫜', 'T' => '櫐', 'U' => '櫫', 'V' => '櫏', 'W' => '櫍', 'X' => '櫞', 'Y' => '歠', 'Z' => '殰', '[' => '氌', '\\' => '瀙', ']' => '瀧', '^' => '瀠', '_' => '瀖', '`' => '瀫', 'a' => '瀡', 'b' => '瀢', 'c' => '瀣', 'd' => '瀩', 'e' => '瀗', 'f' => '瀤', 'g' => '瀜', 'h' => '瀪', 'i' => '爌', 'j' => '爊', 'k' => '爇', 'l' => '爂', 'm' => '爅', 'n' => '犥', 'o' => '犦', 'p' => '犤', 'q' => '犣', 'r' => '犡', 's' => '瓋', 't' => '瓅', 'u' => '璷', 'v' => '瓃', 'w' => '甖', 'x' => '癠', 'y' => '矉', 'z' => '矊', '{' => '矄', '|' => '矱', '}' => '礝', '~' => '礛', '' => '礡', '' => '礜', '' => '礗', '' => '礞', '' => '禰', '' => '穧', '' => '穨', '' => '簳', '' => '簼', '' => '簹', '' => '簬', '' => '簻', '' => '糬', '' => '糪', '' => '繶', '' => '繵', '' => '繸', '' => '繰', '' => '繷', '' => '繯', '' => '繺', '' => '繲', '' => '繴', '' => '繨', '' => '罋', '' => '罊', '' => '羃', '' => '羆', '' => '羷', '' => '翽', '' => '翾', '' => '聸', '' => '臗', '' => '臕', '' => '艤', '' => '艡', '' => '艣', '' => '藫', '' => '藱', '' => '藭', '' => '藙', '' => '藡', '' => '藨', '' => '藚', '' => '藗', '' => '藬', '' => '藲', '' => '藸', '' => '藘', '' => '藟', '' => '藣', '' => '藜', '' => '藑', '' => '藰', '' => '藦', '' => '藯', '' => '藞', '' => '藢', '' => '蠀', '' => '蟺', '' => '蠃', '' => '蟶', '' => '蟷', '' => '蠉', '' => '蠌', '' => '蠋', '' => '蠆', '' => '蟼', '' => '蠈', '' => '蟿', '' => '蠊', '' => '蠂', '' => '襢', '' => '襚', '' => '襛', '' => '襗', '' => '襡', '' => '襜', '' => '襘', '' => '襝', '' => '襙', '' => '覈', '' => '覷', '' => '覶', '' => '觶', '' => '譐', '' => '譈', '' => '譊', '' => '譀', '' => '譓', '' => '譖', '' => '譔', '' => '譋', '' => '譕', '@' => '譑', 'A' => '譂', 'B' => '譒', 'C' => '譗', 'D' => '豃', 'E' => '豷', 'F' => '豶', 'G' => '貚', 'H' => '贆', 'I' => '贇', 'J' => '贉', 'K' => '趬', 'L' => '趪', 'M' => '趭', 'N' => '趫', 'O' => '蹭', 'P' => '蹸', 'Q' => '蹳', 'R' => '蹪', 'S' => '蹯', 'T' => '蹻', 'U' => '軂', 'V' => '轒', 'W' => '轑', 'X' => '轏', 'Y' => '轐', 'Z' => '轓', '[' => '辴', '\\' => '酀', ']' => '鄿', '^' => '醰', '_' => '醭', '`' => '鏞', 'a' => '鏇', 'b' => '鏏', 'c' => '鏂', 'd' => '鏚', 'e' => '鏐', 'f' => '鏹', 'g' => '鏬', 'h' => '鏌', 'i' => '鏙', 'j' => '鎩', 'k' => '鏦', 'l' => '鏊', 'm' => '鏔', 'n' => '鏮', 'o' => '鏣', 'p' => '鏕', 'q' => '鏄', 'r' => '鏎', 's' => '鏀', 't' => '鏒', 'u' => '鏧', 'v' => '镽', 'w' => '闚', 'x' => '闛', 'y' => '雡', 'z' => '霩', '{' => '霫', '|' => '霬', '}' => '霨', '~' => '霦', '' => '鞳', '' => '鞷', '' => '鞶', '' => '韝', '' => '韞', '' => '韟', '' => '顜', '' => '顙', '' => '顝', '' => '顗', '' => '颿', '' => '颽', '' => '颻', '' => '颾', '' => '饈', '' => '饇', '' => '饃', '' => '馦', '' => '馧', '' => '騚', '' => '騕', '' => '騥', '' => '騝', '' => '騤', '' => '騛', '' => '騢', '' => '騠', '' => '騧', '' => '騣', '' => '騞', '' => '騜', '' => '騔', '' => '髂', '' => '鬋', '' => '鬊', '' => '鬎', '' => '鬌', '' => '鬷', '' => '鯪', '' => '鯫', '' => '鯠', '' => '鯞', '' => '鯤', '' => '鯦', '' => '鯢', '' => '鯰', '' => '鯔', '' => '鯗', '' => '鯬', '' => '鯜', '' => '鯙', '' => '鯥', '' => '鯕', '' => '鯡', '' => '鯚', '' => '鵷', '' => '鶁', '' => '鶊', '' => '鶄', '' => '鶈', '' => '鵱', '' => '鶀', '' => '鵸', '' => '鶆', '' => '鶋', '' => '鶌', '' => '鵽', '' => '鵫', '' => '鵴', '' => '鵵', '' => '鵰', '' => '鵩', '' => '鶅', '' => '鵳', '' => '鵻', '' => '鶂', '' => '鵯', '' => '鵹', '' => '鵿', '' => '鶇', '' => '鵨', '' => '麔', '' => '麑', '' => '黀', '' => '黼', '' => '鼭', '' => '齀', '' => '齁', '' => '齍', '' => '齖', '' => '齗', '' => '齘', '' => '匷', '' => '嚲', '@' => '嚵', 'A' => '嚳', 'B' => '壣', 'C' => '孅', 'D' => '巆', 'E' => '巇', 'F' => '廮', 'G' => '廯', 'H' => '忀', 'I' => '忁', 'J' => '懹', 'K' => '攗', 'L' => '攖', 'M' => '攕', 'N' => '攓', 'O' => '旟', 'P' => '曨', 'Q' => '曣', 'R' => '曤', 'S' => '櫳', 'T' => '櫰', 'U' => '櫪', 'V' => '櫨', 'W' => '櫹', 'X' => '櫱', 'Y' => '櫮', 'Z' => '櫯', '[' => '瀼', '\\' => '瀵', ']' => '瀯', '^' => '瀷', '_' => '瀴', '`' => '瀱', 'a' => '灂', 'b' => '瀸', 'c' => '瀿', 'd' => '瀺', 'e' => '瀹', 'f' => '灀', 'g' => '瀻', 'h' => '瀳', 'i' => '灁', 'j' => '爓', 'k' => '爔', 'l' => '犨', 'm' => '獽', 'n' => '獼', 'o' => '璺', 'p' => '皫', 'q' => '皪', 'r' => '皾', 's' => '盭', 't' => '矌', 'u' => '矎', 'v' => '矏', 'w' => '矍', 'x' => '矲', 'y' => '礥', 'z' => '礣', '{' => '礧', '|' => '礨', '}' => '礤', '~' => '礩', '' => '禲', '' => '穮', '' => '穬', '' => '穭', '' => '竷', '' => '籉', '' => '籈', '' => '籊', '' => '籇', '' => '籅', '' => '糮', '' => '繻', '' => '繾', '' => '纁', '' => '纀', '' => '羺', '' => '翿', '' => '聹', '' => '臛', '' => '臙', '' => '舋', '' => '艨', '' => '艩', '' => '蘢', '' => '藿', '' => '蘁', '' => '藾', '' => '蘛', '' => '蘀', '' => '藶', '' => '蘄', '' => '蘉', '' => '蘅', '' => '蘌', '' => '藽', '' => '蠙', '' => '蠐', '' => '蠑', '' => '蠗', '' => '蠓', '' => '蠖', '' => '襣', '' => '襦', '' => '覹', '' => '觷', '' => '譠', '' => '譪', '' => '譝', '' => '譨', '' => '譣', '' => '譥', '' => '譧', '' => '譭', '' => '趮', '' => '躆', '' => '躈', '' => '躄', '' => '轙', '' => '轖', '' => '轗', '' => '轕', '' => '轘', '' => '轚', '' => '邍', '' => '酃', '' => '酁', '' => '醷', '' => '醵', '' => '醲', '' => '醳', '' => '鐋', '' => '鐓', '' => '鏻', '' => '鐠', '' => '鐏', '' => '鐔', '' => '鏾', '' => '鐕', '' => '鐐', '' => '鐨', '' => '鐙', '' => '鐍', '' => '鏵', '' => '鐀', '' => '鏷', '' => '鐇', '' => '鐎', '' => '鐖', '' => '鐒', '' => '鏺', '' => '鐉', '' => '鏸', '' => '鐊', '' => '鏿', '@' => '鏼', 'A' => '鐌', 'B' => '鏶', 'C' => '鐑', 'D' => '鐆', 'E' => '闞', 'F' => '闠', 'G' => '闟', 'H' => '霮', 'I' => '霯', 'J' => '鞹', 'K' => '鞻', 'L' => '韽', 'M' => '韾', 'N' => '顠', 'O' => '顢', 'P' => '顣', 'Q' => '顟', 'R' => '飁', 'S' => '飂', 'T' => '饐', 'U' => '饎', 'V' => '饙', 'W' => '饌', 'X' => '饋', 'Y' => '饓', 'Z' => '騲', '[' => '騴', '\\' => '騱', ']' => '騬', '^' => '騪', '_' => '騶', '`' => '騩', 'a' => '騮', 'b' => '騸', 'c' => '騭', 'd' => '髇', 'e' => '髊', 'f' => '髆', 'g' => '鬐', 'h' => '鬒', 'i' => '鬑', 'j' => '鰋', 'k' => '鰈', 'l' => '鯷', 'm' => '鰅', 'n' => '鰒', 'o' => '鯸', 'p' => '鱀', 'q' => '鰇', 'r' => '鰎', 's' => '鰆', 't' => '鰗', 'u' => '鰔', 'v' => '鰉', 'w' => '鶟', 'x' => '鶙', 'y' => '鶤', 'z' => '鶝', '{' => '鶒', '|' => '鶘', '}' => '鶐', '~' => '鶛', '' => '鶠', '' => '鶔', '' => '鶜', '' => '鶪', '' => '鶗', '' => '鶡', '' => '鶚', '' => '鶢', '' => '鶨', '' => '鶞', '' => '鶣', '' => '鶿', '' => '鶩', '' => '鶖', '' => '鶦', '' => '鶧', '' => '麙', '' => '麛', '' => '麚', '' => '黥', '' => '黤', '' => '黧', '' => '黦', '' => '鼰', '' => '鼮', '' => '齛', '' => '齠', '' => '齞', '' => '齝', '' => '齙', '' => '龑', '' => '儺', '' => '儹', '' => '劘', '' => '劗', '' => '囃', '' => '嚽', '' => '嚾', '' => '孈', '' => '孇', '' => '巋', '' => '巏', '' => '廱', '' => '懽', '' => '攛', '' => '欂', '' => '櫼', '' => '欃', '' => '櫸', '' => '欀', '' => '灃', '' => '灄', '' => '灊', '' => '灈', '' => '灉', '' => '灅', '' => '灆', '' => '爝', '' => '爚', '' => '爙', '' => '獾', '' => '甗', '' => '癪', '' => '矐', '' => '礭', '' => '礱', '' => '礯', '' => '籔', '' => '籓', '' => '糲', '' => '纊', '' => '纇', '' => '纈', '' => '纋', '' => '纆', '' => '纍', '' => '罍', '' => '羻', '' => '耰', '' => '臝', '' => '蘘', '' => '蘪', '' => '蘦', '' => '蘟', '' => '蘣', '' => '蘜', '' => '蘙', '' => '蘧', '' => '蘮', '' => '蘡', '' => '蘠', '' => '蘩', '' => '蘞', '' => '蘥', '@' => '蠩', 'A' => '蠝', 'B' => '蠛', 'C' => '蠠', 'D' => '蠤', 'E' => '蠜', 'F' => '蠫', 'G' => '衊', 'H' => '襭', 'I' => '襩', 'J' => '襮', 'K' => '襫', 'L' => '觺', 'M' => '譹', 'N' => '譸', 'O' => '譅', 'P' => '譺', 'Q' => '譻', 'R' => '贐', 'S' => '贔', 'T' => '趯', 'U' => '躎', 'V' => '躌', 'W' => '轞', 'X' => '轛', 'Y' => '轝', 'Z' => '酆', '[' => '酄', '\\' => '酅', ']' => '醹', '^' => '鐿', '_' => '鐻', '`' => '鐶', 'a' => '鐩', 'b' => '鐽', 'c' => '鐼', 'd' => '鐰', 'e' => '鐹', 'f' => '鐪', 'g' => '鐷', 'h' => '鐬', 'i' => '鑀', 'j' => '鐱', 'k' => '闥', 'l' => '闤', 'm' => '闣', 'n' => '霵', 'o' => '霺', 'p' => '鞿', 'q' => '韡', 'r' => '顤', 's' => '飉', 't' => '飆', 'u' => '飀', 'v' => '饘', 'w' => '饖', 'x' => '騹', 'y' => '騽', 'z' => '驆', '{' => '驄', '|' => '驂', '}' => '驁', '~' => '騺', '' => '騿', '' => '髍', '' => '鬕', '' => '鬗', '' => '鬘', '' => '鬖', '' => '鬺', '' => '魒', '' => '鰫', '' => '鰝', '' => '鰜', '' => '鰬', '' => '鰣', '' => '鰨', '' => '鰩', '' => '鰤', '' => '鰡', '' => '鶷', '' => '鶶', '' => '鶼', '' => '鷁', '' => '鷇', '' => '鷊', '' => '鷏', '' => '鶾', '' => '鷅', '' => '鷃', '' => '鶻', '' => '鶵', '' => '鷎', '' => '鶹', '' => '鶺', '' => '鶬', '' => '鷈', '' => '鶱', '' => '鶭', '' => '鷌', '' => '鶳', '' => '鷍', '' => '鶲', '' => '鹺', '' => '麜', '' => '黫', '' => '黮', '' => '黭', '' => '鼛', '' => '鼘', '' => '鼚', '' => '鼱', '' => '齎', '' => '齥', '' => '齤', '' => '龒', '' => '亹', '' => '囆', '' => '囅', '' => '囋', '' => '奱', '' => '孋', '' => '孌', '' => '巕', '' => '巑', '' => '廲', '' => '攡', '' => '攠', '' => '攦', '' => '攢', '' => '欋', '' => '欈', '' => '欉', '' => '氍', '' => '灕', '' => '灖', '' => '灗', '' => '灒', '' => '爞', '' => '爟', '' => '犩', '' => '獿', '' => '瓘', '' => '瓕', '' => '瓙', '' => '瓗', '' => '癭', '' => '皭', '' => '礵', '' => '禴', '' => '穰', '' => '穱', '' => '籗', '' => '籜', '' => '籙', '' => '籛', '' => '籚', '@' => '糴', 'A' => '糱', 'B' => '纑', 'C' => '罏', 'D' => '羇', 'E' => '臞', 'F' => '艫', 'G' => '蘴', 'H' => '蘵', 'I' => '蘳', 'J' => '蘬', 'K' => '蘲', 'L' => '蘶', 'M' => '蠬', 'N' => '蠨', 'O' => '蠦', 'P' => '蠪', 'Q' => '蠥', 'R' => '襱', 'S' => '覿', 'T' => '覾', 'U' => '觻', 'V' => '譾', 'W' => '讄', 'X' => '讂', 'Y' => '讆', 'Z' => '讅', '[' => '譿', '\\' => '贕', ']' => '躕', '^' => '躔', '_' => '躚', '`' => '躒', 'a' => '躐', 'b' => '躖', 'c' => '躗', 'd' => '轠', 'e' => '轢', 'f' => '酇', 'g' => '鑌', 'h' => '鑐', 'i' => '鑊', 'j' => '鑋', 'k' => '鑏', 'l' => '鑇', 'm' => '鑅', 'n' => '鑈', 'o' => '鑉', 'p' => '鑆', 'q' => '霿', 'r' => '韣', 's' => '顪', 't' => '顩', 'u' => '飋', 'v' => '饔', 'w' => '饛', 'x' => '驎', 'y' => '驓', 'z' => '驔', '{' => '驌', '|' => '驏', '}' => '驈', '~' => '驊', '' => '驉', '' => '驒', '' => '驐', '' => '髐', '' => '鬙', '' => '鬫', '' => '鬻', '' => '魖', '' => '魕', '' => '鱆', '' => '鱈', '' => '鰿', '' => '鱄', '' => '鰹', '' => '鰳', '' => '鱁', '' => '鰼', '' => '鰷', '' => '鰴', '' => '鰲', '' => '鰽', '' => '鰶', '' => '鷛', '' => '鷒', '' => '鷞', '' => '鷚', '' => '鷋', '' => '鷐', '' => '鷜', '' => '鷑', '' => '鷟', '' => '鷩', '' => '鷙', '' => '鷘', '' => '鷖', '' => '鷵', '' => '鷕', '' => '鷝', '' => '麶', '' => '黰', '' => '鼵', '' => '鼳', '' => '鼲', '' => '齂', '' => '齫', '' => '龕', '' => '龢', '' => '儽', '' => '劙', '' => '壨', '' => '壧', '' => '奲', '' => '孍', '' => '巘', '' => '蠯', '' => '彏', '' => '戁', '' => '戃', '' => '戄', '' => '攩', '' => '攥', '' => '斖', '' => '曫', '' => '欑', '' => '欒', '' => '欏', '' => '毊', '' => '灛', '' => '灚', '' => '爢', '' => '玂', '' => '玁', '' => '玃', '' => '癰', '' => '矔', '' => '籧', '' => '籦', '' => '纕', '' => '艬', '' => '蘺', '' => '虀', '' => '蘹', '' => '蘼', '' => '蘱', '' => '蘻', '' => '蘾', '' => '蠰', '' => '蠲', '' => '蠮', '' => '蠳', '' => '襶', '' => '襴', '' => '襳', '' => '觾', '@' => '讌', 'A' => '讎', 'B' => '讋', 'C' => '讈', 'D' => '豅', 'E' => '贙', 'F' => '躘', 'G' => '轤', 'H' => '轣', 'I' => '醼', 'J' => '鑢', 'K' => '鑕', 'L' => '鑝', 'M' => '鑗', 'N' => '鑞', 'O' => '韄', 'P' => '韅', 'Q' => '頀', 'R' => '驖', 'S' => '驙', 'T' => '鬞', 'U' => '鬟', 'V' => '鬠', 'W' => '鱒', 'X' => '鱘', 'Y' => '鱐', 'Z' => '鱊', '[' => '鱍', '\\' => '鱋', ']' => '鱕', '^' => '鱙', '_' => '鱌', '`' => '鱎', 'a' => '鷻', 'b' => '鷷', 'c' => '鷯', 'd' => '鷣', 'e' => '鷫', 'f' => '鷸', 'g' => '鷤', 'h' => '鷶', 'i' => '鷡', 'j' => '鷮', 'k' => '鷦', 'l' => '鷲', 'm' => '鷰', 'n' => '鷢', 'o' => '鷬', 'p' => '鷴', 'q' => '鷳', 'r' => '鷨', 's' => '鷭', 't' => '黂', 'u' => '黐', 'v' => '黲', 'w' => '黳', 'x' => '鼆', 'y' => '鼜', 'z' => '鼸', '{' => '鼷', '|' => '鼶', '}' => '齃', '~' => '齏', '' => '齱', '' => '齰', '' => '齮', '' => '齯', '' => '囓', '' => '囍', '' => '孎', '' => '屭', '' => '攭', '' => '曭', '' => '曮', '' => '欓', '' => '灟', '' => '灡', '' => '灝', '' => '灠', '' => '爣', '' => '瓛', '' => '瓥', '' => '矕', '' => '礸', '' => '禷', '' => '禶', '' => '籪', '' => '纗', '' => '羉', '' => '艭', '' => '虃', '' => '蠸', '' => '蠷', '' => '蠵', '' => '衋', '' => '讔', '' => '讕', '' => '躞', '' => '躟', '' => '躠', '' => '躝', '' => '醾', '' => '醽', '' => '釂', '' => '鑫', '' => '鑨', '' => '鑩', '' => '雥', '' => '靆', '' => '靃', '' => '靇', '' => '韇', '' => '韥', '' => '驞', '' => '髕', '' => '魙', '' => '鱣', '' => '鱧', '' => '鱦', '' => '鱢', '' => '鱞', '' => '鱠', '' => '鸂', '' => '鷾', '' => '鸇', '' => '鸃', '' => '鸆', '' => '鸅', '' => '鸀', '' => '鸁', '' => '鸉', '' => '鷿', '' => '鷽', '' => '鸄', '' => '麠', '' => '鼞', '' => '齆', '' => '齴', '' => '齵', '' => '齶', '' => '囔', '' => '攮', '' => '斸', '' => '欘', '' => '欙', '' => '欗', '' => '欚', '' => '灢', '' => '爦', '' => '犪', '' => '矘', '' => '矙', '' => '礹', '' => '籩', '' => '籫', '' => '糶', '' => '纚', '@' => '纘', 'A' => '纛', 'B' => '纙', 'C' => '臠', 'D' => '臡', 'E' => '虆', 'F' => '虇', 'G' => '虈', 'H' => '襹', 'I' => '襺', 'J' => '襼', 'K' => '襻', 'L' => '觿', 'M' => '讘', 'N' => '讙', 'O' => '躥', 'P' => '躤', 'Q' => '躣', 'R' => '鑮', 'S' => '鑭', 'T' => '鑯', 'U' => '鑱', 'V' => '鑳', 'W' => '靉', 'X' => '顲', 'Y' => '饟', 'Z' => '鱨', '[' => '鱮', '\\' => '鱭', ']' => '鸋', '^' => '鸍', '_' => '鸐', '`' => '鸏', 'a' => '鸒', 'b' => '鸑', '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; '', '' => '', '' => '', '' => '', '' => 'œ', '' => ' ', '' => '†', '' => '', '' => '—', ' ' => '', ' ' => 'Ž', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '…', '' => '', '' => '‡', '' => '', '' => '', '' => '’', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => '€', '!' => '', '"' => '‚', '#' => 'ƒ', '$' => '„', '%' => ' ', '&' => '', '\'' => '', '(' => 'ˆ', ')' => '‰', '*' => 'Š', '+' => '‹', ',' => 'Œ', '-' => '', '.' => '', '/' => '', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => 'œ', '' => ' ', '' => '†', '' => '', '' => '—', ' ' => '', ' ' => 'Ž', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '…', '' => '', '' => '‡', '' => '', '' => '', '' => '’', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => '€', '!' => '', '"' => '‚', '#' => 'ƒ', '$' => '„', '%' => ' ', '&' => '', '\'' => '', '(' => 'ˆ', ')' => '‰', '*' => 'Š', '+' => '‹', ',' => 'Œ', '-' => '', '.' => '', '/' => '', 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; '', '' => '', '' => '', '' => '', '' => 'œ', '' => ' ', '' => '†', '' => '', '' => '—', ' ' => '', ' ' => 'Ž', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '…', '' => '', '' => '‡', '' => '', '' => '', '' => '’', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => '€', '!' => '', '"' => '‚', '#' => 'ƒ', '$' => '„', '%' => ' ', '&' => '', '\'' => '', '(' => 'ˆ', ')' => '‰', '*' => 'Š', '+' => '‹', ',' => 'Œ', '-' => '', '.' => '', '/' => '', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => 'œ', '' => ' ', '' => '†', '' => '', '' => '—', ' ' => '', ' ' => 'Ž', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '…', '' => '', '' => '‡', '' => '', '' => '', '' => '’', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => '€', '!' => '', '"' => '‚', '#' => 'ƒ', '$' => '„', '%' => ' ', '&' => '', '\'' => '', '(' => 'ˆ', ')' => '‰', '*' => 'Š', '+' => '‹', ',' => 'Œ', '-' => '', '.' => '', '/' => '', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '٪', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => 'œ', '' => ' ', '' => '†', '' => '', '' => '—', ' ' => '', ' ' => 'Ž', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '…', '' => '', '' => '‡', '' => '', '' => '', '' => '’', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => '€', '!' => '', '"' => '‚', '#' => 'ƒ', '$' => '„', '%' => ' ', '&' => '', '\'' => '', '(' => 'ˆ', ')' => '‰', '*' => 'Š', '+' => '‹', ',' => 'Œ', '-' => '', '.' => '', '/' => '', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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' => '0', 'P' => '1', 'Q' => '2', 'R' => '3', 'S' => '4', 'T' => '5', 'U' => '6', 'V' => '7', 'W' => '8', 'X' => '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', '' => 'a', '' => 'b', '' => 'c', '' => 'd', '' => 'e', '' => 'f', '' => 'g', '' => 'h', '' => 'i', '' => 'j', '' => 'k', '' => 'l', '' => 'm', '' => 'n', '' => 'o', '' => 'p', '' => 'q', '' => 'r', '' => 's', '' => 't', '' => 'u', '' => 'v', '' => 'w', '' => 'x', '' => 'y', '' => 'z', '' => 'ぁ', '' => 'あ', '' => 'ぃ', '' => 'い', '' => 'ぅ', '' => 'う', '' => 'ぇ', '' => 'え', '' => 'ぉ', '' => 'お', '' => 'か', '' => 'が', '' => 'き', '' => 'ぎ', '' => 'く', '' => 'ぐ', '' => 'け', '' => 'げ', '' => 'こ', '' => 'ご', '' => 'さ', '' => 'ざ', '' => 'し', '' => 'じ', '' => 'す', '' => 'ず', '' => 'せ', '' => 'ぜ', '' => 'そ', '' => 'ぞ', '' => 'た', '' => 'だ', '' => 'ち', '' => 'ぢ', '' => 'っ', '' => 'つ', '' => 'づ', '' => 'て', '' => 'で', '' => 'と', '' => 'ど', '' => 'な', '' => 'に', '' => 'ぬ', '' => 'ね', '' => 'の', '' => 'は', '' => 'ば', '' => 'ぱ', '' => 'ひ', '' => 'び', '' => 'ぴ', '' => 'ふ', '' => 'ぶ', '' => 'ぷ', '' => 'へ', '' => 'べ', '' => 'ぺ', '' => 'ほ', '' => 'ぼ', '' => 'ぽ', '' => 'ま', '' => 'み', '' => 'む', '' => 'め', '' => 'も', '' => 'ゃ', '' => 'や', '' => 'ゅ', '' => 'ゆ', '' => 'ょ', '' => 'よ', '' => 'ら', '' => 'り', '' => 'る', '' => 'れ', '' => 'ろ', '' => 'ゎ', '' => 'わ', '' => 'ゐ', '' => 'ゑ', '' => 'を', '' => 'ん', '@' => 'ァ', 'A' => 'ア', 'B' => 'ィ', 'C' => 'イ', 'D' => 'ゥ', 'E' => 'ウ', 'F' => 'ェ', 'G' => 'エ', 'H' => 'ォ', 'I' => 'オ', 'J' => 'カ', 'K' => 'ガ', 'L' => 'キ', 'M' => 'ギ', 'N' => 'ク', 'O' => 'グ', 'P' => 'ケ', 'Q' => 'ゲ', 'R' => 'コ', 'S' => 'ゴ', 'T' => 'サ', 'U' => 'ザ', 'V' => 'シ', 'W' => 'ジ', 'X' => 'ス', 'Y' => 'ズ', 'Z' => 'セ', '[' => 'ゼ', '\\' => 'ソ', ']' => 'ゾ', '^' => 'タ', '_' => 'ダ', '`' => 'チ', 'a' => 'ヂ', 'b' => 'ッ', 'c' => 'ツ', 'd' => 'ヅ', 'e' => 'テ', 'f' => 'デ', 'g' => 'ト', 'h' => 'ド', 'i' => 'ナ', 'j' => 'ニ', 'k' => 'ヌ', 'l' => 'ネ', 'm' => 'ノ', 'n' => 'ハ', 'o' => 'バ', 'p' => 'パ', 'q' => 'ヒ', 'r' => 'ビ', 's' => 'ピ', 't' => 'フ', 'u' => 'ブ', 'v' => 'プ', 'w' => 'ヘ', 'x' => 'ベ', 'y' => 'ペ', 'z' => 'ホ', '{' => 'ボ', '|' => 'ポ', '}' => 'マ', '~' => 'ミ', '' => 'ム', '' => 'メ', '' => 'モ', '' => 'ャ', '' => 'ヤ', '' => 'ュ', '' => 'ユ', '' => 'ョ', '' => 'ヨ', '' => 'ラ', '' => 'リ', '' => 'ル', '' => 'レ', '' => 'ロ', '' => 'ヮ', '' => 'ワ', '' => 'ヰ', '' => 'ヱ', '' => 'ヲ', '' => 'ン', '' => 'ヴ', '' => 'ヵ', '' => 'ヶ', '' => 'Α', '' => 'Β', '' => 'Γ', '' => 'Δ', '' => 'Ε', '' => 'Ζ', '' => 'Η', '' => 'Θ', '' => 'Ι', '' => 'Κ', '' => 'Λ', '' => 'Μ', '' => 'Ν', '' => 'Ξ', '' => 'Ο', '' => 'Π', '' => 'Ρ', '' => 'Σ', '' => 'Τ', '' => 'Υ', '' => 'Φ', '' => 'Χ', '' => 'Ψ', '' => 'Ω', '' => 'α', '' => 'β', '' => 'γ', '' => 'δ', '' => 'ε', '' => 'ζ', '' => 'η', '' => 'θ', '' => 'ι', '' => 'κ', '' => 'λ', '' => 'μ', '' => 'ν', '' => 'ξ', '' => 'ο', '' => 'π', '' => 'ρ', '' => 'σ', '' => 'τ', '' => 'υ', '' => 'φ', '' => 'χ', '' => 'ψ', '' => 'ω', '@' => 'А', 'A' => 'Б', 'B' => 'В', '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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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' => '爖', '{' => '爗', '|' => '爘', '}' => '爙', '~' => '爚', '' => '爛', '' => '爜', '' => '爞', '' => '爟', '' => '爠', '' => '爡', '' => '爢', '' => '爣', '' => '爤', '' => '爥', '' => '爦', '' => '爧', '' => '爩', '' => '爫', '' => '爭', '' => '爮', '' => '爯', '' => '爲', '' => '爳', '' => '爴', '' => '爺', '' => '爼', '' => '爾', '' => '牀', '' => '牁', '' => '牂', '' => '牃', '' => '牄', '' => '牅', '' => '牆', '' => '牉', '' => '牊', '' => '牋', '' => '牎', '' => '牏', '' => '牐', '' => '牑', '' => '牓', '' => '牔', '' => '牕', '' => '牗', '' => '牘', '' => '牚', '' => '牜', '' => '牞', '' => '牠', '' => '牣', '' => '牤', '' => '牥', '' => '牨', '' => '牪', '' => '牫', '' => '牬', '' => '牭', '' => '牰', '' => '牱', '' => '牳', '' => '牴', '' => '牶', '' => '牷', '' => '牸', '' => '牻', '' => '牼', '' => '牽', '' => '犂', '' => '犃', '' => '犅', '' => '犆', '' => '犇', '' => '犈', '' => '犉', '' => '犌', '' => '犎', '' => '犐', '' => '犑', '' => '犓', '' => '犔', '' => '犕', '' => '犖', '' => '犗', '' => '犘', '' => '犙', '' => '犚', '' => '犛', '' => '犜', '' => '犝', '' => '犞', '' => '犠', '' => '犡', '' => '犢', '' => '犣', '' => '犤', '' => '犥', '' => '犦', '' => '犧', '' => '犨', '' => '犩', '' => '犪', '' => '犫', '' => '犮', '' => '犱', '' => '犲', '' => '犳', '' => '犵', '' => '犺', '' => '犻', '' => '犼', '' => '犽', '' => '犾', '' => '犿', '' => '狀', '' => '狅', '' => '狆', '' => '狇', '' => '狉', '' => '狊', '' => '狋', '' => '狌', '' => '狏', '' => '狑', '' => '狓', '' => '狔', '' => '狕', '' => '狖', '' => '狘', '' => '狚', '' => '狛', '' => ' ', '' => '、', '' => '。', '' => '·', '' => 'ˉ', '' => 'ˇ', '' => '¨', '' => '〃', '' => '々', '' => '—', '' => '~', '' => '‖', '' => '…', '' => '‘', '' => '’', '' => '“', '' => '”', '' => '〔', '' => '〕', '' => '〈', '' => '〉', '' => '《', '' => '》', '' => '「', '' => '」', '' => '『', '' => '』', '' => '〖', '' => '〗', '' => '【', '' => '】', '' => '±', '' => '×', '' => '÷', '' => '∶', '' => '∧', '' => '∨', '' => '∑', '' => '∏', '' => '∪', '' => '∩', '' => '∈', '' => '∷', '' => '√', '' => '⊥', '' => '∥', '' => '∠', '' => '⌒', '' => '⊙', '' => '∫', '' => '∮', '' => '≡', '' => '≌', '' => '≈', '' => '∽', '' => '∝', '' => '≠', '' => '≮', '' => '≯', '' => '≤', '' => '≥', '' => '∞', '' => '∵', '' => '∴', '' => '♂', '' => '♀', '' => '°', '' => '′', '' => '″', '' => '℃', '' => '$', '' => '¤', '' => '¢', '' => '£', '' => '‰', '' => '§', '' => '№', '' => '☆', '' => '★', '' => '○', '' => '●', '' => '◎', '' => '◇', '' => '◆', '' => '□', '' => '■', '' => '△', '' => '▲', '' => '※', '' => '→', '' => '←', '' => '↑', '' => '↓', '' => '〓', '' => 'ⅰ', '' => 'ⅱ', '' => 'ⅲ', '' => 'ⅳ', '' => 'ⅴ', '' => 'ⅵ', '' => 'ⅶ', '' => 'ⅷ', '' => 'ⅸ', '' => 'ⅹ', '' => '⒈', '' => '⒉', '' => '⒊', '' => '⒋', '' => '⒌', '' => '⒍', '' => '⒎', '' => '⒏', '' => '⒐', '' => '⒑', '' => '⒒', '' => '⒓', '' => '⒔', '' => '⒕', '' => '⒖', '' => '⒗', '' => '⒘', '' => '⒙', '' => '⒚', '' => '⒛', '' => '⑴', '' => '⑵', '' => '⑶', '' => '⑷', '' => '⑸', '' => '⑹', '' => '⑺', '' => '⑻', '' => '⑼', '' => '⑽', '' => '⑾', '' => '⑿', '' => '⒀', '' => '⒁', '' => '⒂', '' => '⒃', '' => '⒄', '' => '⒅', '' => '⒆', '' => '⒇', '' => '①', '' => '②', '' => '③', '' => '④', '' => '⑤', '' => '⑥', '' => '⑦', '' => '⑧', '' => '⑨', '' => '⑩', '' => '㈠', '' => '㈡', '' => '㈢', '' => '㈣', '' => '㈤', '' => '㈥', '' => '㈦', '' => '㈧', '' => '㈨', '' => '㈩', '' => 'Ⅰ', '' => 'Ⅱ', '' => 'Ⅲ', '' => 'Ⅳ', '' => 'Ⅴ', '' => 'Ⅵ', '' => 'Ⅶ', '' => 'Ⅷ', '' => 'Ⅸ', '' => 'Ⅹ', '' => 'Ⅺ', '' => 'Ⅻ', '' => '!', '' => '"', '' => '#', '' => '¥', '' => '%', '' => '&', '' => ''', '' => '(', '' => ')', '' => '*', '' => '+', '' => ',', '' => '-', '' => '.', '' => '/', '' => '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' => '¦', 'Y' => '℡', 'Z' => '㈱', '\\' => '‐', '`' => 'ー', 'a' => '゛', 'b' => '゜', 'c' => 'ヽ', 'd' => 'ヾ', 'e' => '〆', 'f' => 'ゝ', 'g' => 'ゞ', 'h' => '﹉', 'i' => '﹊', 'j' => '﹋', 'k' => '﹌', 'l' => '﹍', 'm' => '﹎', 'n' => '﹏', 'o' => '﹐', 'p' => '﹑', 'q' => '﹒', 'r' => '﹔', 's' => '﹕', 't' => '﹖', 'u' => '﹗', 'v' => '﹙', 'w' => '﹚', 'x' => '﹛', 'y' => '﹜', 'z' => '﹝', '{' => '﹞', '|' => '﹟', '}' => '﹠', '~' => '﹡', '' => '﹢', '' => '﹣', '' => '﹤', '' => '﹥', '' => '﹦', '' => '﹨', '' => '﹩', '' => '﹪', '' => '﹫', '' => '〇', '' => '─', '' => '━', '' => '│', '' => '┃', '' => '┄', '' => '┅', '' => '┆', '' => '┇', '' => '┈', '' => '┉', '' => '┊', '' => '┋', '' => '┌', '' => '┍', '' => '┎', '' => '┏', '' => '┐', '' => '┑', '' => '┒', '' => '┓', '' => '└', '' => '┕', '' => '┖', '' => '┗', '' => '┘', '' => '┙', '' => '┚', '' => '┛', '' => '├', '' => '┝', '' => '┞', '' => '┟', '' => '┠', '' => '┡', '' => '┢', '' => '┣', '' => '┤', '' => '┥', '' => '┦', '' => '┧', '' => '┨', '' => '┩', '' => '┪', '' => '┫', '' => '┬', '' => '┭', '' => '┮', '' => '┯', '' => '┰', '' => '┱', '' => '┲', '' => '┳', '' => '┴', '' => '┵', '' => '┶', '' => '┷', '' => '┸', '' => '┹', '' => '┺', '' => '┻', '' => '┼', '' => '┽', '' => '┾', '' => '┿', '' => '╀', '' => '╁', '' => '╂', '' => '╃', '' => '╄', '' => '╅', '' => '╆', '' => '╇', '' => '╈', '' => '╉', '' => '╊', '' => '╋', '@' => '狜', 'A' => '狝', 'B' => '狟', 'C' => '狢', 'D' => '狣', 'E' => '狤', 'F' => '狥', 'G' => '狦', 'H' => '狧', 'I' => '狪', 'J' => '狫', 'K' => '狵', 'L' => '狶', 'M' => '狹', 'N' => '狽', 'O' => '狾', 'P' => '狿', 'Q' => '猀', 'R' => '猂', 'S' => '猄', 'T' => '猅', 'U' => '猆', 'V' => '猇', 'W' => '猈', 'X' => '猉', 'Y' => '猋', 'Z' => '猌', '[' => '猍', '\\' => '猏', ']' => '猐', '^' => '猑', '_' => '猒', '`' => '猔', 'a' => '猘', 'b' => '猙', 'c' => '猚', 'd' => '猟', 'e' => '猠', 'f' => '猣', 'g' => '猤', 'h' => '猦', 'i' => '猧', 'j' => '猨', 'k' => '猭', 'l' => '猯', 'm' => '猰', 'n' => '猲', 'o' => '猳', 'p' => '猵', 'q' => '猶', 'r' => '猺', 's' => '猻', 't' => '猼', 'u' => '猽', 'v' => '獀', 'w' => '獁', 'x' => '獂', 'y' => '獃', 'z' => '獄', '{' => '獅', '|' => '獆', '}' => '獇', '~' => '獈', '' => '獉', '' => '獊', '' => '獋', '' => '獌', '' => '獎', '' => '獏', '' => '獑', '' => '獓', '' => '獔', '' => '獕', '' => '獖', '' => '獘', '' => '獙', '' => '獚', '' => '獛', '' => '獜', '' => '獝', '' => '獞', '' => '獟', '' => '獡', '' => '獢', '' => '獣', '' => '獤', '' => '獥', '' => '獦', '' => '獧', '' => '獨', '' => '獩', '' => '獪', '' => '獫', '' => '獮', '' => '獰', '' => '獱', '@' => '獲', 'A' => '獳', 'B' => '獴', 'C' => '獵', 'D' => '獶', 'E' => '獷', 'F' => '獸', 'G' => '獹', 'H' => '獺', 'I' => '獻', 'J' => '獼', 'K' => '獽', 'L' => '獿', 'M' => '玀', 'N' => '玁', 'O' => '玂', 'P' => '玃', 'Q' => '玅', 'R' => '玆', 'S' => '玈', 'T' => '玊', 'U' => '玌', 'V' => '玍', 'W' => '玏', 'X' => '玐', 'Y' => '玒', 'Z' => '玓', '[' => '玔', '\\' => '玕', ']' => '玗', '^' => '玘', '_' => '玙', '`' => '玚', 'a' => '玜', 'b' => '玝', 'c' => '玞', 'd' => '玠', 'e' => '玡', 'f' => '玣', 'g' => '玤', 'h' => '玥', 'i' => '玦', 'j' => '玧', 'k' => '玨', 'l' => '玪', 'm' => '玬', 'n' => '玭', 'o' => '玱', 'p' => '玴', 'q' => '玵', 'r' => '玶', 's' => '玸', 't' => '玹', 'u' => '玼', 'v' => '玽', 'w' => '玾', 'x' => '玿', 'y' => '珁', 'z' => '珃', '{' => '珄', '|' => '珅', '}' => '珆', '~' => '珇', '' => '珋', '' => '珌', '' => '珎', '' => '珒', '' => '珓', '' => '珔', '' => '珕', '' => '珖', '' => '珗', '' => '珘', '' => '珚', '' => '珛', '' => '珜', '' => '珝', '' => '珟', '' => '珡', '' => '珢', '' => '珣', '' => '珤', '' => '珦', '' => '珨', '' => '珪', '' => '珫', '' => '珬', '' => '珮', '' => '珯', '' => '珰', '' => '珱', '' => '珳', '' => '珴', '' => '珵', '' => '珶', '' => '珷', '@' => '珸', 'A' => '珹', 'B' => '珺', 'C' => '珻', 'D' => '珼', 'E' => '珽', 'F' => '現', 'G' => '珿', 'H' => '琀', 'I' => '琁', 'J' => '琂', 'K' => '琄', 'L' => '琇', 'M' => '琈', 'N' => '琋', 'O' => '琌', 'P' => '琍', 'Q' => '琎', 'R' => '琑', 'S' => '琒', 'T' => '琓', 'U' => '琔', 'V' => '琕', 'W' => '琖', 'X' => '琗', 'Y' => '琘', 'Z' => '琙', '[' => '琜', '\\' => '琝', ']' => '琞', '^' => '琟', '_' => '琠', '`' => '琡', 'a' => '琣', 'b' => '琤', 'c' => '琧', 'd' => '琩', 'e' => '琫', 'f' => '琭', 'g' => '琯', 'h' => '琱', 'i' => '琲', 'j' => '琷', 'k' => '琸', 'l' => '琹', 'm' => '琺', 'n' => '琻', 'o' => '琽', 'p' => '琾', 'q' => '琿', 'r' => '瑀', 's' => '瑂', 't' => '瑃', 'u' => '瑄', 'v' => '瑅', 'w' => '瑆', 'x' => '瑇', 'y' => '瑈', 'z' => '瑉', '{' => '瑊', '|' => '瑋', '}' => '瑌', '~' => '瑍', '' => '瑎', '' => '瑏', '' => '瑐', '' => '瑑', '' => '瑒', '' => '瑓', '' => '瑔', '' => '瑖', '' => '瑘', '' => '瑝', '' => '瑠', '' => '瑡', '' => '瑢', '' => '瑣', '' => '瑤', '' => '瑥', '' => '瑦', '' => '瑧', '' => '瑨', '' => '瑩', '' => '瑪', '' => '瑫', '' => '瑬', '' => '瑮', '' => '瑯', '' => '瑱', '' => '瑲', '' => '瑳', '' => '瑴', '' => '瑵', '' => '瑸', '' => '瑹', '' => '瑺', '@' => '瑻', 'A' => '瑼', 'B' => '瑽', 'C' => '瑿', 'D' => '璂', 'E' => '璄', 'F' => '璅', 'G' => '璆', 'H' => '璈', 'I' => '璉', 'J' => '璊', 'K' => '璌', 'L' => '璍', 'M' => '璏', 'N' => '璑', 'O' => '璒', 'P' => '璓', 'Q' => '璔', 'R' => '璕', 'S' => '璖', 'T' => '璗', 'U' => '璘', 'V' => '璙', 'W' => '璚', 'X' => '璛', 'Y' => '璝', 'Z' => '璟', '[' => '璠', '\\' => '璡', ']' => '璢', '^' => '璣', '_' => '璤', '`' => '璥', 'a' => '璦', 'b' => '璪', 'c' => '璫', 'd' => '璬', 'e' => '璭', 'f' => '璮', 'g' => '璯', 'h' => '環', 'i' => '璱', 'j' => '璲', 'k' => '璳', 'l' => '璴', 'm' => '璵', 'n' => '璶', 'o' => '璷', 'p' => '璸', 'q' => '璹', 'r' => '璻', 's' => '璼', 't' => '璽', 'u' => '璾', 'v' => '璿', 'w' => '瓀', 'x' => '瓁', 'y' => '瓂', 'z' => '瓃', '{' => '瓄', '|' => '瓅', '}' => '瓆', '~' => '瓇', '' => '瓈', '' => '瓉', '' => '瓊', '' => '瓋', '' => '瓌', '' => '瓍', '' => '瓎', '' => '瓏', '' => '瓐', '' => '瓑', '' => '瓓', '' => '瓔', '' => '瓕', '' => '瓖', '' => '瓗', '' => '瓘', '' => '瓙', '' => '瓚', '' => '瓛', '' => '瓝', '' => '瓟', '' => '瓡', '' => '瓥', '' => '瓧', '' => '瓨', '' => '瓩', '' => '瓪', '' => '瓫', '' => '瓬', '' => '瓭', '' => '瓰', '' => '瓱', '' => '瓲', '@' => '瓳', 'A' => '瓵', 'B' => '瓸', 'C' => '瓹', 'D' => '瓺', 'E' => '瓻', 'F' => '瓼', 'G' => '瓽', 'H' => '瓾', 'I' => '甀', 'J' => '甁', 'K' => '甂', 'L' => '甃', 'M' => '甅', 'N' => '甆', 'O' => '甇', 'P' => '甈', 'Q' => '甉', 'R' => '甊', 'S' => '甋', 'T' => '甌', 'U' => '甎', 'V' => '甐', 'W' => '甒', 'X' => '甔', 'Y' => '甕', 'Z' => '甖', '[' => '甗', '\\' => '甛', ']' => '甝', '^' => '甞', '_' => '甠', '`' => '甡', 'a' => '產', 'b' => '産', 'c' => '甤', 'd' => '甦', 'e' => '甧', 'f' => '甪', 'g' => '甮', 'h' => '甴', 'i' => '甶', 'j' => '甹', 'k' => '甼', 'l' => '甽', 'm' => '甿', 'n' => '畁', 'o' => '畂', 'p' => '畃', 'q' => '畄', 'r' => '畆', 's' => '畇', 't' => '畉', 'u' => '畊', 'v' => '畍', 'w' => '畐', 'x' => '畑', 'y' => '畒', 'z' => '畓', '{' => '畕', '|' => '畖', '}' => '畗', '~' => '畘', '' => '畝', '' => '畞', '' => '畟', '' => '畠', '' => '畡', '' => '畢', '' => '畣', '' => '畤', '' => '畧', '' => '畨', '' => '畩', '' => '畫', '' => '畬', '' => '畭', '' => '畮', '' => '畯', '' => '異', '' => '畱', '' => '畳', '' => '畵', '' => '當', '' => '畷', '' => '畺', '' => '畻', '' => '畼', '' => '畽', '' => '畾', '' => '疀', '' => '疁', '' => '疂', '' => '疄', '' => '疅', '' => '疇', '@' => '疈', 'A' => '疉', 'B' => '疊', 'C' => '疌', 'D' => '疍', 'E' => '疎', 'F' => '疐', 'G' => '疓', 'H' => '疕', 'I' => '疘', 'J' => '疛', 'K' => '疜', 'L' => '疞', 'M' => '疢', 'N' => '疦', 'O' => '疧', 'P' => '疨', 'Q' => '疩', 'R' => '疪', 'S' => '疭', 'T' => '疶', 'U' => '疷', 'V' => '疺', 'W' => '疻', 'X' => '疿', 'Y' => '痀', 'Z' => '痁', '[' => '痆', '\\' => '痋', ']' => '痌', '^' => '痎', '_' => '痏', '`' => '痐', 'a' => '痑', 'b' => '痓', 'c' => '痗', 'd' => '痙', 'e' => '痚', 'f' => '痜', 'g' => '痝', 'h' => '痟', 'i' => '痠', 'j' => '痡', 'k' => '痥', 'l' => '痩', 'm' => '痬', 'n' => '痭', 'o' => '痮', 'p' => '痯', 'q' => '痲', 'r' => '痳', 's' => '痵', 't' => '痶', 'u' => '痷', 'v' => '痸', 'w' => '痺', 'x' => '痻', 'y' => '痽', 'z' => '痾', '{' => '瘂', '|' => '瘄', '}' => '瘆', '~' => '瘇', '' => '瘈', '' => '瘉', '' => '瘋', '' => '瘍', '' => '瘎', '' => '瘏', '' => '瘑', '' => '瘒', '' => '瘓', '' => '瘔', '' => '瘖', '' => '瘚', '' => '瘜', '' => '瘝', '' => '瘞', '' => '瘡', '' => '瘣', '' => '瘧', '' => '瘨', '' => '瘬', '' => '瘮', '' => '瘯', '' => '瘱', '' => '瘲', '' => '瘶', '' => '瘷', '' => '瘹', '' => '瘺', '' => '瘻', '' => '瘽', '' => '癁', '' => '療', '' => '癄', '@' => '癅', 'A' => '癆', 'B' => '癇', 'C' => '癈', 'D' => '癉', 'E' => '癊', 'F' => '癋', 'G' => '癎', 'H' => '癏', 'I' => '癐', 'J' => '癑', 'K' => '癒', 'L' => '癓', 'M' => '癕', 'N' => '癗', 'O' => '癘', 'P' => '癙', 'Q' => '癚', 'R' => '癛', 'S' => '癝', 'T' => '癟', 'U' => '癠', 'V' => '癡', 'W' => '癢', 'X' => '癤', 'Y' => '癥', 'Z' => '癦', '[' => '癧', '\\' => '癨', ']' => '癩', '^' => '癪', '_' => '癬', '`' => '癭', 'a' => '癮', 'b' => '癰', 'c' => '癱', 'd' => '癲', 'e' => '癳', 'f' => '癴', 'g' => '癵', 'h' => '癶', 'i' => '癷', 'j' => '癹', 'k' => '発', 'l' => '發', 'm' => '癿', 'n' => '皀', 'o' => '皁', 'p' => '皃', 'q' => '皅', 'r' => '皉', 's' => '皊', 't' => '皌', 'u' => '皍', 'v' => '皏', 'w' => '皐', 'x' => '皒', 'y' => '皔', 'z' => '皕', '{' => '皗', '|' => '皘', '}' => '皚', '~' => '皛', '' => '皜', '' => '皝', '' => '皞', '' => '皟', '' => '皠', '' => '皡', '' => '皢', '' => '皣', '' => '皥', '' => '皦', '' => '皧', '' => '皨', '' => '皩', '' => '皪', '' => '皫', '' => '皬', '' => '皭', '' => '皯', '' => '皰', '' => '皳', '' => '皵', '' => '皶', '' => '皷', '' => '皸', '' => '皹', '' => '皺', '' => '皻', '' => '皼', '' => '皽', '' => '皾', '' => '盀', '' => '盁', '' => '盃', '' => '啊', '' => '阿', '' => '埃', '' => '挨', '' => '哎', '' => '唉', '' => '哀', '' => '皑', '' => '癌', '' => '蔼', '' => '矮', '' => '艾', '' => '碍', '' => '爱', '' => '隘', '' => '鞍', '' => '氨', '' => '安', '' => '俺', '' => '按', '' => '暗', '' => '岸', '' => '胺', '' => '案', '' => '肮', '' => '昂', '' => '盎', '' => '凹', '' => '敖', '' => '熬', '' => '翱', '' => '袄', '' => '傲', '' => '奥', '' => '懊', '' => '澳', '' => '芭', '' => '捌', '' => '扒', '' => '叭', '' => '吧', '' => '笆', '' => '八', '' => '疤', '' => '巴', '' => '拔', '' => '跋', '' => '靶', '' => '把', '' => '耙', '' => '坝', '' => '霸', '' => '罢', '' => '爸', '' => '白', '' => '柏', '' => '百', '' => '摆', '' => '佰', '' => '败', '' => '拜', '' => '稗', '' => '斑', '' => '班', '' => '搬', '' => '扳', '' => '般', '' => '颁', '' => '板', '' => '版', '' => '扮', '' => '拌', '' => '伴', '' => '瓣', '' => '半', '' => '办', '' => '绊', '' => '邦', '' => '帮', '' => '梆', '' => '榜', '' => '膀', '' => '绑', '' => '棒', '' => '磅', '' => '蚌', '' => '镑', '' => '傍', '' => '谤', '' => '苞', '' => '胞', '' => '包', '' => '褒', '' => '剥', '@' => '盄', 'A' => '盇', 'B' => '盉', 'C' => '盋', 'D' => '盌', 'E' => '盓', 'F' => '盕', 'G' => '盙', 'H' => '盚', 'I' => '盜', 'J' => '盝', 'K' => '盞', 'L' => '盠', 'M' => '盡', 'N' => '盢', 'O' => '監', 'P' => '盤', 'Q' => '盦', 'R' => '盧', 'S' => '盨', 'T' => '盩', 'U' => '盪', 'V' => '盫', 'W' => '盬', 'X' => '盭', 'Y' => '盰', 'Z' => '盳', '[' => '盵', '\\' => '盶', ']' => '盷', '^' => '盺', '_' => '盻', '`' => '盽', 'a' => '盿', 'b' => '眀', 'c' => '眂', 'd' => '眃', 'e' => '眅', 'f' => '眆', 'g' => '眊', 'h' => '県', 'i' => '眎', 'j' => '眏', 'k' => '眐', 'l' => '眑', 'm' => '眒', 'n' => '眓', 'o' => '眔', 'p' => '眕', 'q' => '眖', 'r' => '眗', 's' => '眘', 't' => '眛', 'u' => '眜', 'v' => '眝', 'w' => '眞', 'x' => '眡', 'y' => '眣', 'z' => '眤', '{' => '眥', '|' => '眧', '}' => '眪', '~' => '眫', '' => '眬', '' => '眮', '' => '眰', '' => '眱', '' => '眲', '' => '眳', '' => '眴', '' => '眹', '' => '眻', '' => '眽', '' => '眾', '' => '眿', '' => '睂', '' => '睄', '' => '睅', '' => '睆', '' => '睈', '' => '睉', '' => '睊', '' => '睋', '' => '睌', '' => '睍', '' => '睎', '' => '睏', '' => '睒', '' => '睓', '' => '睔', '' => '睕', '' => '睖', '' => '睗', '' => '睘', '' => '睙', '' => '睜', '' => '薄', '' => '雹', '' => '保', '' => '堡', '' => '饱', '' => '宝', '' => '抱', '' => '报', '' => '暴', '' => '豹', '' => '鲍', '' => '爆', '' => '杯', '' => '碑', '' => '悲', '' => '卑', '' => '北', '' => '辈', '' => '背', '' => '贝', '' => '钡', '' => '倍', '' => '狈', '' => '备', '' => '惫', '' => '焙', '' => '被', '' => '奔', '' => '苯', '' => '本', '' => '笨', '' => '崩', '' => '绷', '' => '甭', '' => '泵', '' => '蹦', '' => '迸', '' => '逼', '' => '鼻', '' => '比', '' => '鄙', '' => '笔', '' => '彼', '' => '碧', '' => '蓖', '' => '蔽', '' => '毕', '' => '毙', '' => '毖', '' => '币', '' => '庇', '' => '痹', '' => '闭', '' => '敝', '' => '弊', '' => '必', '' => '辟', '' => '壁', '' => '臂', '' => '避', '' => '陛', '' => '鞭', '' => '边', '' => '编', '' => '贬', '' => '扁', '' => '便', '' => '变', '' => '卞', '' => '辨', '' => '辩', '' => '辫', '' => '遍', '' => '标', '' => '彪', '' => '膘', '' => '表', '' => '鳖', '' => '憋', '' => '别', '' => '瘪', '' => '彬', '' => '斌', '' => '濒', '' => '滨', '' => '宾', '' => '摈', '' => '兵', '' => '冰', '' => '柄', '' => '丙', '' => '秉', '' => '饼', '' => '炳', '@' => '睝', 'A' => '睞', 'B' => '睟', 'C' => '睠', 'D' => '睤', 'E' => '睧', 'F' => '睩', 'G' => '睪', 'H' => '睭', 'I' => '睮', 'J' => '睯', 'K' => '睰', 'L' => '睱', 'M' => '睲', 'N' => '睳', 'O' => '睴', 'P' => '睵', 'Q' => '睶', 'R' => '睷', 'S' => '睸', 'T' => '睺', 'U' => '睻', 'V' => '睼', 'W' => '瞁', 'X' => '瞂', 'Y' => '瞃', 'Z' => '瞆', '[' => '瞇', '\\' => '瞈', ']' => '瞉', '^' => '瞊', '_' => '瞋', '`' => '瞏', 'a' => '瞐', 'b' => '瞓', 'c' => '瞔', 'd' => '瞕', 'e' => '瞖', 'f' => '瞗', 'g' => '瞘', 'h' => '瞙', 'i' => '瞚', 'j' => '瞛', 'k' => '瞜', 'l' => '瞝', 'm' => '瞞', 'n' => '瞡', 'o' => '瞣', 'p' => '瞤', 'q' => '瞦', 'r' => '瞨', 's' => '瞫', 't' => '瞭', 'u' => '瞮', 'v' => '瞯', 'w' => '瞱', 'x' => '瞲', 'y' => '瞴', 'z' => '瞶', '{' => '瞷', '|' => '瞸', '}' => '瞹', '~' => '瞺', '' => '瞼', '' => '瞾', '' => '矀', '' => '矁', '' => '矂', '' => '矃', '' => '矄', '' => '矅', '' => '矆', '' => '矇', '' => '矈', '' => '矉', '' => '矊', '' => '矋', '' => '矌', '' => '矎', '' => '矏', '' => '矐', '' => '矑', '' => '矒', '' => '矓', '' => '矔', '' => '矕', '' => '矖', '' => '矘', '' => '矙', '' => '矚', '' => '矝', '' => '矞', '' => '矟', '' => '矠', '' => '矡', '' => '矤', '' => '病', '' => '并', '' => '玻', '' => '菠', '' => '播', '' => '拨', '' => '钵', '' => '波', '' => '博', '' => '勃', '' => '搏', '' => '铂', '' => '箔', '' => '伯', '' => '帛', '' => '舶', '' => '脖', '' => '膊', '' => '渤', '' => '泊', '' => '驳', '' => '捕', '' => '卜', '' => '哺', '' => '补', '' => '埠', '' => '不', '' => '布', '' => '步', '' => '簿', '' => '部', '' => '怖', '' => '擦', '' => '猜', '' => '裁', '' => '材', '' => '才', '' => '财', '' => '睬', '' => '踩', '' => '采', '' => '彩', '' => '菜', '' => '蔡', '' => '餐', '' => '参', '' => '蚕', '' => '残', '' => '惭', '' => '惨', '' => '灿', '' => '苍', '' => '舱', '' => '仓', '' => '沧', '' => '藏', '' => '操', '' => '糙', '' => '槽', '' => '曹', '' => '草', '' => '厕', '' => '策', '' => '侧', '' => '册', '' => '测', '' => '层', '' => '蹭', '' => '插', '' => '叉', '' => '茬', '' => '茶', '' => '查', '' => '碴', '' => '搽', '' => '察', '' => '岔', '' => '差', '' => '诧', '' => '拆', '' => '柴', '' => '豺', '' => '搀', '' => '掺', '' => '蝉', '' => '馋', '' => '谗', '' => '缠', '' => '铲', '' => '产', '' => '阐', '' => '颤', '' => '昌', '' => '猖', '@' => '矦', 'A' => '矨', 'B' => '矪', 'C' => '矯', 'D' => '矰', 'E' => '矱', 'F' => '矲', 'G' => '矴', 'H' => '矵', 'I' => '矷', 'J' => '矹', 'K' => '矺', 'L' => '矻', 'M' => '矼', 'N' => '砃', 'O' => '砄', 'P' => '砅', 'Q' => '砆', 'R' => '砇', 'S' => '砈', 'T' => '砊', 'U' => '砋', 'V' => '砎', 'W' => '砏', 'X' => '砐', 'Y' => '砓', 'Z' => '砕', '[' => '砙', '\\' => '砛', ']' => '砞', '^' => '砠', '_' => '砡', '`' => '砢', 'a' => '砤', 'b' => '砨', 'c' => '砪', 'd' => '砫', 'e' => '砮', 'f' => '砯', 'g' => '砱', 'h' => '砲', 'i' => '砳', 'j' => '砵', 'k' => '砶', 'l' => '砽', 'm' => '砿', 'n' => '硁', 'o' => '硂', 'p' => '硃', 'q' => '硄', 'r' => '硆', 's' => '硈', 't' => '硉', 'u' => '硊', 'v' => '硋', 'w' => '硍', 'x' => '硏', 'y' => '硑', 'z' => '硓', '{' => '硔', '|' => '硘', '}' => '硙', '~' => '硚', '' => '硛', '' => '硜', '' => '硞', '' => '硟', '' => '硠', '' => '硡', '' => '硢', '' => '硣', '' => '硤', '' => '硥', '' => '硦', '' => '硧', '' => '硨', '' => '硩', '' => '硯', '' => '硰', '' => '硱', '' => '硲', '' => '硳', '' => '硴', '' => '硵', '' => '硶', '' => '硸', '' => '硹', '' => '硺', '' => '硻', '' => '硽', '' => '硾', '' => '硿', '' => '碀', '' => '碁', '' => '碂', '' => '碃', '' => '场', '' => '尝', '' => '常', '' => '长', '' => '偿', '' => '肠', '' => '厂', '' => '敞', '' => '畅', '' => '唱', '' => '倡', '' => '超', '' => '抄', '' => '钞', '' => '朝', '' => '嘲', '' => '潮', '' => '巢', '' => '吵', '' => '炒', '' => '车', '' => '扯', '' => '撤', '' => '掣', '' => '彻', '' => '澈', '' => '郴', '' => '臣', '' => '辰', '' => '尘', '' => '晨', '' => '忱', '' => '沉', '' => '陈', '' => '趁', '' => '衬', '' => '撑', '' => '称', '' => '城', '' => '橙', '' => '成', '' => '呈', '' => '乘', '' => '程', '' => '惩', '' => '澄', '' => '诚', '' => '承', '' => '逞', '' => '骋', '' => '秤', '' => '吃', '' => '痴', '' => '持', '' => '匙', '' => '池', '' => '迟', '' => '弛', '' => '驰', '' => '耻', '' => '齿', '' => '侈', '' => '尺', '' => '赤', '' => '翅', '' => '斥', '' => '炽', '' => '充', '' => '冲', '' => '虫', '' => '崇', '' => '宠', '' => '抽', '' => '酬', '' => '畴', '' => '踌', '' => '稠', '' => '愁', '' => '筹', '' => '仇', '' => '绸', '' => '瞅', '' => '丑', '' => '臭', '' => '初', '' => '出', '' => '橱', '' => '厨', '' => '躇', '' => '锄', '' => '雏', '' => '滁', '' => '除', '' => '楚', '@' => '碄', 'A' => '碅', 'B' => '碆', 'C' => '碈', 'D' => '碊', 'E' => '碋', 'F' => '碏', 'G' => '碐', 'H' => '碒', 'I' => '碔', 'J' => '碕', 'K' => '碖', 'L' => '碙', 'M' => '碝', 'N' => '碞', 'O' => '碠', 'P' => '碢', 'Q' => '碤', 'R' => '碦', 'S' => '碨', 'T' => '碩', 'U' => '碪', 'V' => '碫', 'W' => '碬', 'X' => '碭', 'Y' => '碮', 'Z' => '碯', '[' => '碵', '\\' => '碶', ']' => '碷', '^' => '碸', '_' => '確', '`' => '碻', 'a' => '碼', 'b' => '碽', 'c' => '碿', 'd' => '磀', 'e' => '磂', 'f' => '磃', 'g' => '磄', 'h' => '磆', 'i' => '磇', 'j' => '磈', 'k' => '磌', 'l' => '磍', 'm' => '磎', 'n' => '磏', 'o' => '磑', 'p' => '磒', 'q' => '磓', 'r' => '磖', 's' => '磗', 't' => '磘', 'u' => '磚', 'v' => '磛', 'w' => '磜', 'x' => '磝', 'y' => '磞', 'z' => '磟', '{' => '磠', '|' => '磡', '}' => '磢', '~' => '磣', '' => '磤', '' => '磥', '' => '磦', '' => '磧', '' => '磩', '' => '磪', '' => '磫', '' => '磭', '' => '磮', '' => '磯', '' => '磰', '' => '磱', '' => '磳', '' => '磵', '' => '磶', '' => '磸', '' => '磹', '' => '磻', '' => '磼', '' => '磽', '' => '磾', '' => '磿', '' => '礀', '' => '礂', '' => '礃', '' => '礄', '' => '礆', '' => '礇', '' => '礈', '' => '礉', '' => '礊', '' => '礋', '' => '礌', '' => '础', '' => '储', '' => '矗', '' => '搐', '' => '触', '' => '处', '' => '揣', '' => '川', '' => '穿', '' => '椽', '' => '传', '' => '船', '' => '喘', '' => '串', '' => '疮', '' => '窗', '' => '幢', '' => '床', '' => '闯', '' => '创', '' => '吹', '' => '炊', '' => '捶', '' => '锤', '' => '垂', '' => '春', '' => '椿', '' => '醇', '' => '唇', '' => '淳', '' => '纯', '' => '蠢', '' => '戳', '' => '绰', '' => '疵', '' => '茨', '' => '磁', '' => '雌', '' => '辞', '' => '慈', '' => '瓷', '' => '词', '' => '此', '' => '刺', '' => '赐', '' => '次', '' => '聪', '' => '葱', '' => '囱', '' => '匆', '' => '从', '' => '丛', '' => '凑', '' => '粗', '' => '醋', '' => '簇', '' => '促', '' => '蹿', '' => '篡', '' => '窜', '' => '摧', '' => '崔', '' => '催', '' => '脆', '' => '瘁', '' => '粹', '' => '淬', '' => '翠', '' => '村', '' => '存', '' => '寸', '' => '磋', '' => '撮', '' => '搓', '' => '措', '' => '挫', '' => '错', '' => '搭', '' => '达', '' => '答', '' => '瘩', '' => '打', '' => '大', '' => '呆', '' => '歹', '' => '傣', '' => '戴', '' => '带', '' => '殆', '' => '代', '' => '贷', '' => '袋', '' => '待', '' => '逮', '@' => '礍', 'A' => '礎', 'B' => '礏', 'C' => '礐', 'D' => '礑', 'E' => '礒', 'F' => '礔', 'G' => '礕', 'H' => '礖', 'I' => '礗', 'J' => '礘', 'K' => '礙', 'L' => '礚', 'M' => '礛', 'N' => '礜', 'O' => '礝', 'P' => '礟', 'Q' => '礠', 'R' => '礡', 'S' => '礢', 'T' => '礣', 'U' => '礥', 'V' => '礦', 'W' => '礧', 'X' => '礨', 'Y' => '礩', 'Z' => '礪', '[' => '礫', '\\' => '礬', ']' => '礭', '^' => '礮', '_' => '礯', '`' => '礰', 'a' => '礱', 'b' => '礲', 'c' => '礳', 'd' => '礵', 'e' => '礶', 'f' => '礷', 'g' => '礸', 'h' => '礹', 'i' => '礽', 'j' => '礿', 'k' => '祂', 'l' => '祃', 'm' => '祄', 'n' => '祅', 'o' => '祇', 'p' => '祊', 'q' => '祋', 'r' => '祌', 's' => '祍', 't' => '祎', 'u' => '祏', 'v' => '祐', 'w' => '祑', 'x' => '祒', 'y' => '祔', 'z' => '祕', '{' => '祘', '|' => '祙', '}' => '祡', '~' => '祣', '' => '祤', '' => '祦', '' => '祩', '' => '祪', '' => '祫', '' => '祬', '' => '祮', '' => '祰', '' => '祱', '' => '祲', '' => '祳', '' => '祴', '' => '祵', '' => '祶', '' => '祹', '' => '祻', '' => '祼', '' => '祽', '' => '祾', '' => '祿', '' => '禂', '' => '禃', '' => '禆', '' => '禇', '' => '禈', '' => '禉', '' => '禋', '' => '禌', '' => '禍', '' => '禎', '' => '禐', '' => '禑', '' => '禒', '' => '怠', '' => '耽', '' => '担', '' => '丹', '' => '单', '' => '郸', '' => '掸', '' => '胆', '' => '旦', '' => '氮', '' => '但', '' => '惮', '' => '淡', '' => '诞', '' => '弹', '' => '蛋', '' => '当', '' => '挡', '' => '党', '' => '荡', '' => '档', '' => '刀', '' => '捣', '' => '蹈', '' => '倒', '' => '岛', '' => '祷', '' => '导', '' => '到', '' => '稻', '' => '悼', '' => '道', '' => '盗', '' => '德', '' => '得', '' => '的', '' => '蹬', '' => '灯', '' => '登', '' => '等', '' => '瞪', '' => '凳', '' => '邓', '' => '堤', '' => '低', '' => '滴', '' => '迪', '' => '敌', '' => '笛', '' => '狄', '' => '涤', '' => '翟', '' => '嫡', '' => '抵', '' => '底', '' => '地', '' => '蒂', '' => '第', '' => '帝', '' => '弟', '' => '递', '' => '缔', '' => '颠', '' => '掂', '' => '滇', '' => '碘', '' => '点', '' => '典', '' => '靛', '' => '垫', '' => '电', '' => '佃', '' => '甸', '' => '店', '' => '惦', '' => '奠', '' => '淀', '' => '殿', '' => '碉', '' => '叼', '' => '雕', '' => '凋', '' => '刁', '' => '掉', '' => '吊', '' => '钓', '' => '调', '' => '跌', '' => '爹', '' => '碟', '' => '蝶', '' => '迭', '' => '谍', '' => '叠', '@' => '禓', 'A' => '禔', 'B' => '禕', 'C' => '禖', 'D' => '禗', 'E' => '禘', 'F' => '禙', 'G' => '禛', 'H' => '禜', 'I' => '禝', 'J' => '禞', 'K' => '禟', 'L' => '禠', 'M' => '禡', 'N' => '禢', 'O' => '禣', 'P' => '禤', 'Q' => '禥', 'R' => '禦', 'S' => '禨', 'T' => '禩', 'U' => '禪', 'V' => '禫', 'W' => '禬', 'X' => '禭', 'Y' => '禮', 'Z' => '禯', '[' => '禰', '\\' => '禱', ']' => '禲', '^' => '禴', '_' => '禵', '`' => '禶', 'a' => '禷', 'b' => '禸', 'c' => '禼', 'd' => '禿', 'e' => '秂', 'f' => '秄', 'g' => '秅', 'h' => '秇', 'i' => '秈', 'j' => '秊', 'k' => '秌', 'l' => '秎', 'm' => '秏', 'n' => '秐', 'o' => '秓', 'p' => '秔', 'q' => '秖', 'r' => '秗', 's' => '秙', 't' => '秚', 'u' => '秛', 'v' => '秜', 'w' => '秝', 'x' => '秞', 'y' => '秠', 'z' => '秡', '{' => '秢', '|' => '秥', '}' => '秨', '~' => '秪', '' => '秬', '' => '秮', '' => '秱', '' => '秲', '' => '秳', '' => '秴', '' => '秵', '' => '秶', '' => '秷', '' => '秹', '' => '秺', '' => '秼', '' => '秾', '' => '秿', '' => '稁', '' => '稄', '' => '稅', '' => '稇', '' => '稈', '' => '稉', '' => '稊', '' => '稌', '' => '稏', '' => '稐', '' => '稑', '' => '稒', '' => '稓', '' => '稕', '' => '稖', '' => '稘', '' => '稙', '' => '稛', '' => '稜', '' => '丁', '' => '盯', '' => '叮', '' => '钉', '' => '顶', '' => '鼎', '' => '锭', '' => '定', '' => '订', '' => '丢', '' => '东', '' => '冬', '' => '董', '' => '懂', '' => '动', '' => '栋', '' => '侗', '' => '恫', '' => '冻', '' => '洞', '' => '兜', '' => '抖', '' => '斗', '' => '陡', '' => '豆', '' => '逗', '' => '痘', '' => '都', '' => '督', '' => '毒', '' => '犊', '' => '独', '' => '读', '' => '堵', '' => '睹', '' => '赌', '' => '杜', '' => '镀', '' => '肚', '' => '度', '' => '渡', '' => '妒', '' => '端', '' => '短', '' => '锻', '' => '段', '' => '断', '' => '缎', '' => '堆', '' => '兑', '' => '队', '' => '对', '' => '墩', '' => '吨', '' => '蹲', '' => '敦', '' => '顿', '' => '囤', '' => '钝', '' => '盾', '' => '遁', '' => '掇', '' => '哆', '' => '多', '' => '夺', '' => '垛', '' => '躲', '' => '朵', '' => '跺', '' => '舵', '' => '剁', '' => '惰', '' => '堕', '' => '蛾', '' => '峨', '' => '鹅', '' => '俄', '' => '额', '' => '讹', '' => '娥', '' => '恶', '' => '厄', '' => '扼', '' => '遏', '' => '鄂', '' => '饿', '' => '恩', '' => '而', '' => '儿', '' => '耳', '' => '尔', '' => '饵', '' => '洱', '' => '二', '@' => '稝', 'A' => '稟', 'B' => '稡', 'C' => '稢', 'D' => '稤', 'E' => '稥', 'F' => '稦', 'G' => '稧', 'H' => '稨', 'I' => '稩', 'J' => '稪', 'K' => '稫', 'L' => '稬', 'M' => '稭', 'N' => '種', 'O' => '稯', 'P' => '稰', 'Q' => '稱', 'R' => '稲', 'S' => '稴', 'T' => '稵', 'U' => '稶', 'V' => '稸', 'W' => '稺', 'X' => '稾', 'Y' => '穀', 'Z' => '穁', '[' => '穂', '\\' => '穃', ']' => '穄', '^' => '穅', '_' => '穇', '`' => '穈', 'a' => '穉', 'b' => '穊', 'c' => '穋', 'd' => '穌', 'e' => '積', 'f' => '穎', 'g' => '穏', 'h' => '穐', 'i' => '穒', 'j' => '穓', 'k' => '穔', 'l' => '穕', 'm' => '穖', 'n' => '穘', 'o' => '穙', 'p' => '穚', 'q' => '穛', 'r' => '穜', 's' => '穝', 't' => '穞', 'u' => '穟', 'v' => '穠', 'w' => '穡', 'x' => '穢', 'y' => '穣', 'z' => '穤', '{' => '穥', '|' => '穦', '}' => '穧', '~' => '穨', '' => '穩', '' => '穪', '' => '穫', '' => '穬', '' => '穭', '' => '穮', '' => '穯', '' => '穱', '' => '穲', '' => '穳', '' => '穵', '' => '穻', '' => '穼', '' => '穽', '' => '穾', '' => '窂', '' => '窅', '' => '窇', '' => '窉', '' => '窊', '' => '窋', '' => '窌', '' => '窎', '' => '窏', '' => '窐', '' => '窓', '' => '窔', '' => '窙', '' => '窚', '' => '窛', '' => '窞', '' => '窡', '' => '窢', '' => '贰', '' => '发', '' => '罚', '' => '筏', '' => '伐', '' => '乏', '' => '阀', '' => '法', '' => '珐', '' => '藩', '' => '帆', '' => '番', '' => '翻', '' => '樊', '' => '矾', '' => '钒', '' => '繁', '' => '凡', '' => '烦', '' => '反', '' => '返', '' => '范', '' => '贩', '' => '犯', '' => '饭', '' => '泛', '' => '坊', '' => '芳', '' => '方', '' => '肪', '' => '房', '' => '防', '' => '妨', '' => '仿', '' => '访', '' => '纺', '' => '放', '' => '菲', '' => '非', '' => '啡', '' => '飞', '' => '肥', '' => '匪', '' => '诽', '' => '吠', '' => '肺', '' => '废', '' => '沸', '' => '费', '' => '芬', '' => '酚', '' => '吩', '' => '氛', '' => '分', '' => '纷', '' => '坟', '' => '焚', '' => '汾', '' => '粉', '' => '奋', '' => '份', '' => '忿', '' => '愤', '' => '粪', '' => '丰', '' => '封', '' => '枫', '' => '蜂', '' => '峰', '' => '锋', '' => '风', '' => '疯', '' => '烽', '' => '逢', '' => '冯', '' => '缝', '' => '讽', '' => '奉', '' => '凤', '' => '佛', '' => '否', '' => '夫', '' => '敷', '' => '肤', '' => '孵', '' => '扶', '' => '拂', '' => '辐', '' => '幅', '' => '氟', '' => '符', '' => '伏', '' => '俘', '' => '服', '@' => '窣', 'A' => '窤', 'B' => '窧', 'C' => '窩', 'D' => '窪', 'E' => '窫', 'F' => '窮', 'G' => '窯', 'H' => '窰', 'I' => '窱', 'J' => '窲', 'K' => '窴', 'L' => '窵', 'M' => '窶', 'N' => '窷', 'O' => '窸', 'P' => '窹', 'Q' => '窺', 'R' => '窻', 'S' => '窼', 'T' => '窽', 'U' => '窾', 'V' => '竀', 'W' => '竁', 'X' => '竂', 'Y' => '竃', 'Z' => '竄', '[' => '竅', '\\' => '竆', ']' => '竇', '^' => '竈', '_' => '竉', '`' => '竊', 'a' => '竌', 'b' => '竍', 'c' => '竎', 'd' => '竏', 'e' => '竐', 'f' => '竑', 'g' => '竒', 'h' => '竓', 'i' => '竔', 'j' => '竕', 'k' => '竗', 'l' => '竘', 'm' => '竚', 'n' => '竛', 'o' => '竜', 'p' => '竝', 'q' => '竡', 'r' => '竢', 's' => '竤', 't' => '竧', 'u' => '竨', 'v' => '竩', 'w' => '竪', 'x' => '竫', 'y' => '竬', 'z' => '竮', '{' => '竰', '|' => '竱', '}' => '竲', '~' => '竳', '' => '竴', '' => '竵', '' => '競', '' => '竷', '' => '竸', '' => '竻', '' => '竼', '' => '竾', '' => '笀', '' => '笁', '' => '笂', '' => '笅', '' => '笇', '' => '笉', '' => '笌', '' => '笍', '' => '笎', '' => '笐', '' => '笒', '' => '笓', '' => '笖', '' => '笗', '' => '笘', '' => '笚', '' => '笜', '' => '笝', '' => '笟', '' => '笡', '' => '笢', '' => '笣', '' => '笧', '' => '笩', '' => '笭', '' => '浮', '' => '涪', '' => '福', '' => '袱', '' => '弗', '' => '甫', '' => '抚', '' => '辅', '' => '俯', '' => '釜', '' => '斧', '' => '脯', '' => '腑', '' => '府', '' => '腐', '' => '赴', '' => '副', '' => '覆', '' => '赋', '' => '复', '' => '傅', '' => '付', '' => '阜', '' => '父', '' => '腹', '' => '负', '' => '富', '' => '讣', '' => '附', '' => '妇', '' => '缚', '' => '咐', '' => '噶', '' => '嘎', '' => '该', '' => '改', '' => '概', '' => '钙', '' => '盖', '' => '溉', '' => '干', '' => '甘', '' => '杆', '' => '柑', '' => '竿', '' => '肝', '' => '赶', '' => '感', '' => '秆', '' => '敢', '' => '赣', '' => '冈', '' => '刚', '' => '钢', '' => '缸', '' => '肛', '' => '纲', '' => '岗', '' => '港', '' => '杠', '' => '篙', '' => '皋', '' => '高', '' => '膏', '' => '羔', '' => '糕', '' => '搞', '' => '镐', '' => '稿', '' => '告', '' => '哥', '' => '歌', '' => '搁', '' => '戈', '' => '鸽', '' => '胳', '' => '疙', '' => '割', '' => '革', '' => '葛', '' => '格', '' => '蛤', '' => '阁', '' => '隔', '' => '铬', '' => '个', '' => '各', '' => '给', '' => '根', '' => '跟', '' => '耕', '' => '更', '' => '庚', '' => '羹', '@' => '笯', 'A' => '笰', 'B' => '笲', 'C' => '笴', 'D' => '笵', 'E' => '笶', 'F' => '笷', 'G' => '笹', 'H' => '笻', 'I' => '笽', 'J' => '笿', 'K' => '筀', 'L' => '筁', 'M' => '筂', 'N' => '筃', 'O' => '筄', 'P' => '筆', 'Q' => '筈', 'R' => '筊', 'S' => '筍', 'T' => '筎', 'U' => '筓', 'V' => '筕', 'W' => '筗', 'X' => '筙', 'Y' => '筜', 'Z' => '筞', '[' => '筟', '\\' => '筡', ']' => '筣', '^' => '筤', '_' => '筥', '`' => '筦', 'a' => '筧', 'b' => '筨', 'c' => '筩', 'd' => '筪', 'e' => '筫', 'f' => '筬', 'g' => '筭', 'h' => '筯', 'i' => '筰', 'j' => '筳', 'k' => '筴', 'l' => '筶', 'm' => '筸', 'n' => '筺', 'o' => '筼', 'p' => '筽', 'q' => '筿', 'r' => '箁', 's' => '箂', 't' => '箃', 'u' => '箄', 'v' => '箆', 'w' => '箇', 'x' => '箈', 'y' => '箉', 'z' => '箊', '{' => '箋', '|' => '箌', '}' => '箎', '~' => '箏', '' => '箑', '' => '箒', '' => '箓', '' => '箖', '' => '箘', '' => '箙', '' => '箚', '' => '箛', '' => '箞', '' => '箟', '' => '箠', '' => '箣', '' => '箤', '' => '箥', '' => '箮', '' => '箯', '' => '箰', '' => '箲', '' => '箳', '' => '箵', '' => '箶', '' => '箷', '' => '箹', '' => '箺', '' => '箻', '' => '箼', '' => '箽', '' => '箾', '' => '箿', '' => '節', '' => '篂', '' => '篃', '' => '範', '' => '埂', '' => '耿', '' => '梗', '' => '工', '' => '攻', '' => '功', '' => '恭', '' => '龚', '' => '供', '' => '躬', '' => '公', '' => '宫', '' => '弓', '' => '巩', '' => '汞', '' => '拱', '' => '贡', '' => '共', '' => '钩', '' => '勾', '' => '沟', '' => '苟', '' => '狗', '' => '垢', '' => '构', '' => '购', '' => '够', '' => '辜', '' => '菇', '' => '咕', '' => '箍', '' => '估', '' => '沽', '' => '孤', '' => '姑', '' => '鼓', '' => '古', '' => '蛊', '' => '骨', '' => '谷', '' => '股', '' => '故', '' => '顾', '' => '固', '' => '雇', '' => '刮', '' => '瓜', '' => '剐', '' => '寡', '' => '挂', '' => '褂', '' => '乖', '' => '拐', '' => '怪', '' => '棺', '' => '关', '' => '官', '' => '冠', '' => '观', '' => '管', '' => '馆', '' => '罐', '' => '惯', '' => '灌', '' => '贯', '' => '光', '' => '广', '' => '逛', '' => '瑰', '' => '规', '' => '圭', '' => '硅', '' => '归', '' => '龟', '' => '闺', '' => '轨', '' => '鬼', '' => '诡', '' => '癸', '' => '桂', '' => '柜', '' => '跪', '' => '贵', '' => '刽', '' => '辊', '' => '滚', '' => '棍', '' => '锅', '' => '郭', '' => '国', '' => '果', '' => '裹', '' => '过', '' => '哈', '@' => '篅', 'A' => '篈', 'B' => '築', 'C' => '篊', 'D' => '篋', 'E' => '篍', 'F' => '篎', 'G' => '篏', 'H' => '篐', 'I' => '篒', 'J' => '篔', 'K' => '篕', 'L' => '篖', 'M' => '篗', 'N' => '篘', 'O' => '篛', 'P' => '篜', 'Q' => '篞', 'R' => '篟', 'S' => '篠', 'T' => '篢', 'U' => '篣', 'V' => '篤', 'W' => '篧', 'X' => '篨', 'Y' => '篩', 'Z' => '篫', '[' => '篬', '\\' => '篭', ']' => '篯', '^' => '篰', '_' => '篲', '`' => '篳', 'a' => '篴', 'b' => '篵', 'c' => '篶', 'd' => '篸', 'e' => '篹', 'f' => '篺', 'g' => '篻', 'h' => '篽', 'i' => '篿', 'j' => '簀', 'k' => '簁', 'l' => '簂', 'm' => '簃', 'n' => '簄', 'o' => '簅', 'p' => '簆', 'q' => '簈', 'r' => '簉', 's' => '簊', 't' => '簍', 'u' => '簎', 'v' => '簐', 'w' => '簑', 'x' => '簒', 'y' => '簓', 'z' => '簔', '{' => '簕', '|' => '簗', '}' => '簘', '~' => '簙', '' => '簚', '' => '簛', '' => '簜', '' => '簝', '' => '簞', '' => '簠', '' => '簡', '' => '簢', '' => '簣', '' => '簤', '' => '簥', '' => '簨', '' => '簩', '' => '簫', '' => '簬', '' => '簭', '' => '簮', '' => '簯', '' => '簰', '' => '簱', '' => '簲', '' => '簳', '' => '簴', '' => '簵', '' => '簶', '' => '簷', '' => '簹', '' => '簺', '' => '簻', '' => '簼', '' => '簽', '' => '簾', '' => '籂', '' => '骸', '' => '孩', '' => '海', '' => '氦', '' => '亥', '' => '害', '' => '骇', '' => '酣', '' => '憨', '' => '邯', '' => '韩', '' => '含', '' => '涵', '' => '寒', '' => '函', '' => '喊', '' => '罕', '' => '翰', '' => '撼', '' => '捍', '' => '旱', '' => '憾', '' => '悍', '' => '焊', '' => '汗', '' => '汉', '' => '夯', '' => '杭', '' => '航', '' => '壕', '' => '嚎', '' => '豪', '' => '毫', '' => '郝', '' => '好', '' => '耗', '' => '号', '' => '浩', '' => '呵', '' => '喝', '' => '荷', '' => '菏', '' => '核', '' => '禾', '' => '和', '' => '何', '' => '合', '' => '盒', '' => '貉', '' => '阂', '' => '河', '' => '涸', '' => '赫', '' => '褐', '' => '鹤', '' => '贺', '' => '嘿', '' => '黑', '' => '痕', '' => '很', '' => '狠', '' => '恨', '' => '哼', '' => '亨', '' => '横', '' => '衡', '' => '恒', '' => '轰', '' => '哄', '' => '烘', '' => '虹', '' => '鸿', '' => '洪', '' => '宏', '' => '弘', '' => '红', '' => '喉', '' => '侯', '' => '猴', '' => '吼', '' => '厚', '' => '候', '' => '后', '' => '呼', '' => '乎', '' => '忽', '' => '瑚', '' => '壶', '' => '葫', '' => '胡', '' => '蝴', '' => '狐', '' => '糊', '' => '湖', '@' => '籃', 'A' => '籄', 'B' => '籅', 'C' => '籆', 'D' => '籇', 'E' => '籈', 'F' => '籉', 'G' => '籊', 'H' => '籋', 'I' => '籌', 'J' => '籎', 'K' => '籏', 'L' => '籐', 'M' => '籑', 'N' => '籒', 'O' => '籓', 'P' => '籔', 'Q' => '籕', 'R' => '籖', 'S' => '籗', 'T' => '籘', 'U' => '籙', 'V' => '籚', 'W' => '籛', 'X' => '籜', 'Y' => '籝', 'Z' => '籞', '[' => '籟', '\\' => '籠', ']' => '籡', '^' => '籢', '_' => '籣', '`' => '籤', 'a' => '籥', 'b' => '籦', 'c' => '籧', 'd' => '籨', 'e' => '籩', 'f' => '籪', 'g' => '籫', 'h' => '籬', 'i' => '籭', 'j' => '籮', 'k' => '籯', 'l' => '籰', 'm' => '籱', 'n' => '籲', 'o' => '籵', 'p' => '籶', 'q' => '籷', 'r' => '籸', 's' => '籹', 't' => '籺', 'u' => '籾', 'v' => '籿', 'w' => '粀', 'x' => '粁', 'y' => '粂', 'z' => '粃', '{' => '粄', '|' => '粅', '}' => '粆', '~' => '粇', '' => '粈', '' => '粊', '' => '粋', '' => '粌', '' => '粍', '' => '粎', '' => '粏', '' => '粐', '' => '粓', '' => '粔', '' => '粖', '' => '粙', '' => '粚', '' => '粛', '' => '粠', '' => '粡', '' => '粣', '' => '粦', '' => '粧', '' => '粨', '' => '粩', '' => '粫', '' => '粬', '' => '粭', '' => '粯', '' => '粰', '' => '粴', '' => '粵', '' => '粶', '' => '粷', '' => '粸', '' => '粺', '' => '粻', '' => '弧', '' => '虎', '' => '唬', '' => '护', '' => '互', '' => '沪', '' => '户', '' => '花', '' => '哗', '' => '华', '' => '猾', '' => '滑', '' => '画', '' => '划', '' => '化', '' => '话', '' => '槐', '' => '徊', '' => '怀', '' => '淮', '' => '坏', '' => '欢', '' => '环', '' => '桓', '' => '还', '' => '缓', '' => '换', '' => '患', '' => '唤', '' => '痪', '' => '豢', '' => '焕', '' => '涣', '' => '宦', '' => '幻', '' => '荒', '' => '慌', '' => '黄', '' => '磺', '' => '蝗', '' => '簧', '' => '皇', '' => '凰', '' => '惶', '' => '煌', '' => '晃', '' => '幌', '' => '恍', '' => '谎', '' => '灰', '' => '挥', '' => '辉', '' => '徽', '' => '恢', '' => '蛔', '' => '回', '' => '毁', '' => '悔', '' => '慧', '' => '卉', '' => '惠', '' => '晦', '' => '贿', '' => '秽', '' => '会', '' => '烩', '' => '汇', '' => '讳', '' => '诲', '' => '绘', '' => '荤', '' => '昏', '' => '婚', '' => '魂', '' => '浑', '' => '混', '' => '豁', '' => '活', '' => '伙', '' => '火', '' => '获', '' => '或', '' => '惑', '' => '霍', '' => '货', '' => '祸', '' => '击', '' => '圾', '' => '基', '' => '机', '' => '畸', '' => '稽', '' => '积', '' => '箕', '@' => '粿', 'A' => '糀', 'B' => '糂', 'C' => '糃', 'D' => '糄', 'E' => '糆', 'F' => '糉', 'G' => '糋', 'H' => '糎', 'I' => '糏', 'J' => '糐', 'K' => '糑', 'L' => '糒', 'M' => '糓', 'N' => '糔', 'O' => '糘', 'P' => '糚', 'Q' => '糛', 'R' => '糝', 'S' => '糞', 'T' => '糡', 'U' => '糢', 'V' => '糣', 'W' => '糤', 'X' => '糥', 'Y' => '糦', 'Z' => '糧', '[' => '糩', '\\' => '糪', ']' => '糫', '^' => '糬', '_' => '糭', '`' => '糮', 'a' => '糰', 'b' => '糱', 'c' => '糲', 'd' => '糳', 'e' => '糴', 'f' => '糵', 'g' => '糶', 'h' => '糷', 'i' => '糹', 'j' => '糺', 'k' => '糼', 'l' => '糽', 'm' => '糾', 'n' => '糿', 'o' => '紀', 'p' => '紁', 'q' => '紂', 'r' => '紃', 's' => '約', 't' => '紅', 'u' => '紆', 'v' => '紇', 'w' => '紈', 'x' => '紉', 'y' => '紋', 'z' => '紌', '{' => '納', '|' => '紎', '}' => '紏', '~' => '紐', '' => '紑', '' => '紒', '' => '紓', '' => '純', '' => '紕', '' => '紖', '' => '紗', '' => '紘', '' => '紙', '' => '級', '' => '紛', '' => '紜', '' => '紝', '' => '紞', '' => '紟', '' => '紡', '' => '紣', '' => '紤', '' => '紥', '' => '紦', '' => '紨', '' => '紩', '' => '紪', '' => '紬', '' => '紭', '' => '紮', '' => '細', '' => '紱', '' => '紲', '' => '紳', '' => '紴', '' => '紵', '' => '紶', '' => '肌', '' => '饥', '' => '迹', '' => '激', '' => '讥', '' => '鸡', '' => '姬', '' => '绩', '' => '缉', '' => '吉', '' => '极', '' => '棘', '' => '辑', '' => '籍', '' => '集', '' => '及', '' => '急', '' => '疾', '' => '汲', '' => '即', '' => '嫉', '' => '级', '' => '挤', '' => '几', '' => '脊', '' => '己', '' => '蓟', '' => '技', '' => '冀', '' => '季', '' => '伎', '' => '祭', '' => '剂', '' => '悸', '' => '济', '' => '寄', '' => '寂', '' => '计', '' => '记', '' => '既', '' => '忌', '' => '际', '' => '妓', '' => '继', '' => '纪', '' => '嘉', '' => '枷', '' => '夹', '' => '佳', '' => '家', '' => '加', '' => '荚', '' => '颊', '' => '贾', '' => '甲', '' => '钾', '' => '假', '' => '稼', '' => '价', '' => '架', '' => '驾', '' => '嫁', '' => '歼', '' => '监', '' => '坚', '' => '尖', '' => '笺', '' => '间', '' => '煎', '' => '兼', '' => '肩', '' => '艰', '' => '奸', '' => '缄', '' => '茧', '' => '检', '' => '柬', '' => '碱', '' => '硷', '' => '拣', '' => '捡', '' => '简', '' => '俭', '' => '剪', '' => '减', '' => '荐', '' => '槛', '' => '鉴', '' => '践', '' => '贱', '' => '见', '' => '键', '' => '箭', '' => '件', '@' => '紷', 'A' => '紸', 'B' => '紹', 'C' => '紺', 'D' => '紻', 'E' => '紼', 'F' => '紽', 'G' => '紾', 'H' => '紿', 'I' => '絀', 'J' => '絁', 'K' => '終', 'L' => '絃', 'M' => '組', 'N' => '絅', 'O' => '絆', 'P' => '絇', 'Q' => '絈', 'R' => '絉', 'S' => '絊', 'T' => '絋', 'U' => '経', 'V' => '絍', 'W' => '絎', 'X' => '絏', 'Y' => '結', 'Z' => '絑', '[' => '絒', '\\' => '絓', ']' => '絔', '^' => '絕', '_' => '絖', '`' => '絗', 'a' => '絘', 'b' => '絙', 'c' => '絚', 'd' => '絛', 'e' => '絜', 'f' => '絝', 'g' => '絞', 'h' => '絟', 'i' => '絠', 'j' => '絡', 'k' => '絢', 'l' => '絣', 'm' => '絤', 'n' => '絥', 'o' => '給', 'p' => '絧', 'q' => '絨', 'r' => '絩', 's' => '絪', 't' => '絫', 'u' => '絬', 'v' => '絭', 'w' => '絯', 'x' => '絰', 'y' => '統', 'z' => '絲', '{' => '絳', '|' => '絴', '}' => '絵', '~' => '絶', '' => '絸', '' => '絹', '' => '絺', '' => '絻', '' => '絼', '' => '絽', '' => '絾', '' => '絿', '' => '綀', '' => '綁', '' => '綂', '' => '綃', '' => '綄', '' => '綅', '' => '綆', '' => '綇', '' => '綈', '' => '綉', '' => '綊', '' => '綋', '' => '綌', '' => '綍', '' => '綎', '' => '綏', '' => '綐', '' => '綑', '' => '綒', '' => '經', '' => '綔', '' => '綕', '' => '綖', '' => '綗', '' => '綘', '' => '健', '' => '舰', '' => '剑', '' => '饯', '' => '渐', '' => '溅', '' => '涧', '' => '建', '' => '僵', '' => '姜', '' => '将', '' => '浆', '' => '江', '' => '疆', '' => '蒋', '' => '桨', '' => '奖', '' => '讲', '' => '匠', '' => '酱', '' => '降', '' => '蕉', '' => '椒', '' => '礁', '' => '焦', '' => '胶', '' => '交', '' => '郊', '' => '浇', '' => '骄', '' => '娇', '' => '嚼', '' => '搅', '' => '铰', '' => '矫', '' => '侥', '' => '脚', '' => '狡', '' => '角', '' => '饺', '' => '缴', '' => '绞', '' => '剿', '' => '教', '' => '酵', '' => '轿', '' => '较', '' => '叫', '' => '窖', '' => '揭', '' => '接', '' => '皆', '' => '秸', '' => '街', '' => '阶', '' => '截', '' => '劫', '' => '节', '' => '桔', '' => '杰', '' => '捷', '' => '睫', '' => '竭', '' => '洁', '' => '结', '' => '解', '' => '姐', '' => '戒', '' => '藉', '' => '芥', '' => '界', '' => '借', '' => '介', '' => '疥', '' => '诫', '' => '届', '' => '巾', '' => '筋', '' => '斤', '' => '金', '' => '今', '' => '津', '' => '襟', '' => '紧', '' => '锦', '' => '仅', '' => '谨', '' => '进', '' => '靳', '' => '晋', '' => '禁', '' => '近', '' => '烬', '' => '浸', '@' => '継', 'A' => '続', 'B' => '綛', 'C' => '綜', 'D' => '綝', 'E' => '綞', 'F' => '綟', 'G' => '綠', 'H' => '綡', 'I' => '綢', 'J' => '綣', 'K' => '綤', 'L' => '綥', 'M' => '綧', 'N' => '綨', 'O' => '綩', 'P' => '綪', 'Q' => '綫', 'R' => '綬', 'S' => '維', 'T' => '綯', 'U' => '綰', 'V' => '綱', 'W' => '網', 'X' => '綳', 'Y' => '綴', 'Z' => '綵', '[' => '綶', '\\' => '綷', ']' => '綸', '^' => '綹', '_' => '綺', '`' => '綻', 'a' => '綼', 'b' => '綽', 'c' => '綾', 'd' => '綿', 'e' => '緀', 'f' => '緁', 'g' => '緂', 'h' => '緃', 'i' => '緄', 'j' => '緅', 'k' => '緆', 'l' => '緇', 'm' => '緈', 'n' => '緉', 'o' => '緊', 'p' => '緋', 'q' => '緌', 'r' => '緍', 's' => '緎', 't' => '総', 'u' => '緐', 'v' => '緑', 'w' => '緒', 'x' => '緓', 'y' => '緔', 'z' => '緕', '{' => '緖', '|' => '緗', '}' => '緘', '~' => '緙', '' => '線', '' => '緛', '' => '緜', '' => '緝', '' => '緞', '' => '緟', '' => '締', '' => '緡', '' => '緢', '' => '緣', '' => '緤', '' => '緥', '' => '緦', '' => '緧', '' => '編', '' => '緩', '' => '緪', '' => '緫', '' => '緬', '' => '緭', '' => '緮', '' => '緯', '' => '緰', '' => '緱', '' => '緲', '' => '緳', '' => '練', '' => '緵', '' => '緶', '' => '緷', '' => '緸', '' => '緹', '' => '緺', '' => '尽', '' => '劲', '' => '荆', '' => '兢', '' => '茎', '' => '睛', '' => '晶', '' => '鲸', '' => '京', '' => '惊', '' => '精', '' => '粳', '' => '经', '' => '井', '' => '警', '' => '景', '' => '颈', '' => '静', '' => '境', '' => '敬', '' => '镜', '' => '径', '' => '痉', '' => '靖', '' => '竟', '' => '竞', '' => '净', '' => '炯', '' => '窘', '' => '揪', '' => '究', '' => '纠', '' => '玖', '' => '韭', '' => '久', '' => '灸', '' => '九', '' => '酒', '' => '厩', '' => '救', '' => '旧', '' => '臼', '' => '舅', '' => '咎', '' => '就', '' => '疚', '' => '鞠', '' => '拘', '' => '狙', '' => '疽', '' => '居', '' => '驹', '' => '菊', '' => '局', '' => '咀', '' => '矩', '' => '举', '' => '沮', '' => '聚', '' => '拒', '' => '据', '' => '巨', '' => '具', '' => '距', '' => '踞', '' => '锯', '' => '俱', '' => '句', '' => '惧', '' => '炬', '' => '剧', '' => '捐', '' => '鹃', '' => '娟', '' => '倦', '' => '眷', '' => '卷', '' => '绢', '' => '撅', '' => '攫', '' => '抉', '' => '掘', '' => '倔', '' => '爵', '' => '觉', '' => '决', '' => '诀', '' => '绝', '' => '均', '' => '菌', '' => '钧', '' => '军', '' => '君', '' => '峻', '@' => '緻', 'A' => '緼', 'B' => '緽', 'C' => '緾', 'D' => '緿', 'E' => '縀', 'F' => '縁', 'G' => '縂', 'H' => '縃', 'I' => '縄', 'J' => '縅', 'K' => '縆', 'L' => '縇', 'M' => '縈', 'N' => '縉', 'O' => '縊', 'P' => '縋', 'Q' => '縌', 'R' => '縍', 'S' => '縎', 'T' => '縏', 'U' => '縐', 'V' => '縑', 'W' => '縒', 'X' => '縓', 'Y' => '縔', 'Z' => '縕', '[' => '縖', '\\' => '縗', ']' => '縘', '^' => '縙', '_' => '縚', '`' => '縛', 'a' => '縜', 'b' => '縝', 'c' => '縞', 'd' => '縟', 'e' => '縠', 'f' => '縡', 'g' => '縢', 'h' => '縣', 'i' => '縤', 'j' => '縥', 'k' => '縦', 'l' => '縧', 'm' => '縨', 'n' => '縩', 'o' => '縪', 'p' => '縫', 'q' => '縬', 'r' => '縭', 's' => '縮', 't' => '縯', 'u' => '縰', 'v' => '縱', 'w' => '縲', 'x' => '縳', 'y' => '縴', 'z' => '縵', '{' => '縶', '|' => '縷', '}' => '縸', '~' => '縹', '' => '縺', '' => '縼', '' => '總', '' => '績', '' => '縿', '' => '繀', '' => '繂', '' => '繃', '' => '繄', '' => '繅', '' => '繆', '' => '繈', '' => '繉', '' => '繊', '' => '繋', '' => '繌', '' => '繍', '' => '繎', '' => '繏', '' => '繐', '' => '繑', '' => '繒', '' => '繓', '' => '織', '' => '繕', '' => '繖', '' => '繗', '' => '繘', '' => '繙', '' => '繚', '' => '繛', '' => '繜', '' => '繝', '' => '俊', '' => '竣', '' => '浚', '' => '郡', '' => '骏', '' => '喀', '' => '咖', '' => '卡', '' => '咯', '' => '开', '' => '揩', '' => '楷', '' => '凯', '' => '慨', '' => '刊', '' => '堪', '' => '勘', '' => '坎', '' => '砍', '' => '看', '' => '康', '' => '慷', '' => '糠', '' => '扛', '' => '抗', '' => '亢', '' => '炕', '' => '考', '' => '拷', '' => '烤', '' => '靠', '' => '坷', '' => '苛', '' => '柯', '' => '棵', '' => '磕', '' => '颗', '' => '科', '' => '壳', '' => '咳', '' => '可', '' => '渴', '' => '克', '' => '刻', '' => '客', '' => '课', '' => '肯', '' => '啃', '' => '垦', '' => '恳', '' => '坑', '' => '吭', '' => '空', '' => '恐', '' => '孔', '' => '控', '' => '抠', '' => '口', '' => '扣', '' => '寇', '' => '枯', '' => '哭', '' => '窟', '' => '苦', '' => '酷', '' => '库', '' => '裤', '' => '夸', '' => '垮', '' => '挎', '' => '跨', '' => '胯', '' => '块', '' => '筷', '' => '侩', '' => '快', '' => '宽', '' => '款', '' => '匡', '' => '筐', '' => '狂', '' => '框', '' => '矿', '' => '眶', '' => '旷', '' => '况', '' => '亏', '' => '盔', '' => '岿', '' => '窥', '' => '葵', '' => '奎', '' => '魁', '' => '傀', '@' => '繞', 'A' => '繟', 'B' => '繠', 'C' => '繡', 'D' => '繢', 'E' => '繣', 'F' => '繤', 'G' => '繥', 'H' => '繦', 'I' => '繧', 'J' => '繨', 'K' => '繩', 'L' => '繪', 'M' => '繫', 'N' => '繬', 'O' => '繭', 'P' => '繮', 'Q' => '繯', 'R' => '繰', 'S' => '繱', 'T' => '繲', 'U' => '繳', 'V' => '繴', 'W' => '繵', 'X' => '繶', 'Y' => '繷', 'Z' => '繸', '[' => '繹', '\\' => '繺', ']' => '繻', '^' => '繼', '_' => '繽', '`' => '繾', 'a' => '繿', 'b' => '纀', 'c' => '纁', 'd' => '纃', 'e' => '纄', 'f' => '纅', 'g' => '纆', 'h' => '纇', 'i' => '纈', 'j' => '纉', 'k' => '纊', 'l' => '纋', 'm' => '續', 'n' => '纍', 'o' => '纎', 'p' => '纏', 'q' => '纐', 'r' => '纑', 's' => '纒', 't' => '纓', 'u' => '纔', 'v' => '纕', 'w' => '纖', 'x' => '纗', 'y' => '纘', 'z' => '纙', '{' => '纚', '|' => '纜', '}' => '纝', '~' => '纞', '' => '纮', '' => '纴', '' => '纻', '' => '纼', '' => '绖', '' => '绤', '' => '绬', '' => '绹', '' => '缊', '' => '缐', '' => '缞', '' => '缷', '' => '缹', '' => '缻', '' => '缼', '' => '缽', '' => '缾', '' => '缿', '' => '罀', '' => '罁', '' => '罃', '' => '罆', '' => '罇', '' => '罈', '' => '罉', '' => '罊', '' => '罋', '' => '罌', '' => '罍', '' => '罎', '' => '罏', '' => '罒', '' => '罓', '' => '馈', '' => '愧', '' => '溃', '' => '坤', '' => '昆', '' => '捆', '' => '困', '' => '括', '' => '扩', '' => '廓', '' => '阔', '' => '垃', '' => '拉', '' => '喇', '' => '蜡', '' => '腊', '' => '辣', '' => '啦', '' => '莱', '' => '来', '' => '赖', '' => '蓝', '' => '婪', '' => '栏', '' => '拦', '' => '篮', '' => '阑', '' => '兰', '' => '澜', '' => '谰', '' => '揽', '' => '览', '' => '懒', '' => '缆', '' => '烂', '' => '滥', '' => '琅', '' => '榔', '' => '狼', '' => '廊', '' => '郎', '' => '朗', '' => '浪', '' => '捞', '' => '劳', '' => '牢', '' => '老', '' => '佬', '' => '姥', '' => '酪', '' => '烙', '' => '涝', '' => '勒', '' => '乐', '' => '雷', '' => '镭', '' => '蕾', '' => '磊', '' => '累', '' => '儡', '' => '垒', '' => '擂', '' => '肋', '' => '类', '' => '泪', '' => '棱', '' => '楞', '' => '冷', '' => '厘', '' => '梨', '' => '犁', '' => '黎', '' => '篱', '' => '狸', '' => '离', '' => '漓', '' => '理', '' => '李', '' => '里', '' => '鲤', '' => '礼', '' => '莉', '' => '荔', '' => '吏', '' => '栗', '' => '丽', '' => '厉', '' => '励', '' => '砾', '' => '历', '' => '利', '' => '傈', '' => '例', '' => '俐', '@' => '罖', 'A' => '罙', 'B' => '罛', 'C' => '罜', 'D' => '罝', 'E' => '罞', 'F' => '罠', 'G' => '罣', 'H' => '罤', 'I' => '罥', 'J' => '罦', 'K' => '罧', 'L' => '罫', 'M' => '罬', 'N' => '罭', 'O' => '罯', 'P' => '罰', 'Q' => '罳', 'R' => '罵', 'S' => '罶', 'T' => '罷', 'U' => '罸', 'V' => '罺', 'W' => '罻', 'X' => '罼', 'Y' => '罽', 'Z' => '罿', '[' => '羀', '\\' => '羂', ']' => '羃', '^' => '羄', '_' => '羅', '`' => '羆', 'a' => '羇', 'b' => '羈', 'c' => '羉', 'd' => '羋', 'e' => '羍', 'f' => '羏', 'g' => '羐', 'h' => '羑', 'i' => '羒', 'j' => '羓', 'k' => '羕', 'l' => '羖', 'm' => '羗', 'n' => '羘', 'o' => '羙', 'p' => '羛', 'q' => '羜', 'r' => '羠', 's' => '羢', 't' => '羣', 'u' => '羥', 'v' => '羦', 'w' => '羨', 'x' => '義', 'y' => '羪', 'z' => '羫', '{' => '羬', '|' => '羭', '}' => '羮', '~' => '羱', '' => '羳', '' => '羴', '' => '羵', '' => '羶', '' => '羷', '' => '羺', '' => '羻', '' => '羾', '' => '翀', '' => '翂', '' => '翃', '' => '翄', '' => '翆', '' => '翇', '' => '翈', '' => '翉', '' => '翋', '' => '翍', '' => '翏', '' => '翐', '' => '翑', '' => '習', '' => '翓', '' => '翖', '' => '翗', '' => '翙', '' => '翚', '' => '翛', '' => '翜', '' => '翝', '' => '翞', '' => '翢', '' => '翣', '' => '痢', '' => '立', '' => '粒', '' => '沥', '' => '隶', '' => '力', '' => '璃', '' => '哩', '' => '俩', '' => '联', '' => '莲', '' => '连', '' => '镰', '' => '廉', '' => '怜', '' => '涟', '' => '帘', '' => '敛', '' => '脸', '' => '链', '' => '恋', '' => '炼', '' => '练', '' => '粮', '' => '凉', '' => '梁', '' => '粱', '' => '良', '' => '两', '' => '辆', '' => '量', '' => '晾', '' => '亮', '' => '谅', '' => '撩', '' => '聊', '' => '僚', '' => '疗', '' => '燎', '' => '寥', '' => '辽', '' => '潦', '' => '了', '' => '撂', '' => '镣', '' => '廖', '' => '料', '' => '列', '' => '裂', '' => '烈', '' => '劣', '' => '猎', '' => '琳', '' => '林', '' => '磷', '' => '霖', '' => '临', '' => '邻', '' => '鳞', '' => '淋', '' => '凛', '' => '赁', '' => '吝', '' => '拎', '' => '玲', '' => '菱', '' => '零', '' => '龄', '' => '铃', '' => '伶', '' => '羚', '' => '凌', '' => '灵', '' => '陵', '' => '岭', '' => '领', '' => '另', '' => '令', '' => '溜', '' => '琉', '' => '榴', '' => '硫', '' => '馏', '' => '留', '' => '刘', '' => '瘤', '' => '流', '' => '柳', '' => '六', '' => '龙', '' => '聋', '' => '咙', '' => '笼', '' => '窿', '@' => '翤', 'A' => '翧', 'B' => '翨', 'C' => '翪', 'D' => '翫', 'E' => '翬', 'F' => '翭', 'G' => '翯', 'H' => '翲', 'I' => '翴', 'J' => '翵', 'K' => '翶', 'L' => '翷', 'M' => '翸', 'N' => '翹', 'O' => '翺', 'P' => '翽', 'Q' => '翾', 'R' => '翿', 'S' => '耂', 'T' => '耇', 'U' => '耈', 'V' => '耉', 'W' => '耊', 'X' => '耎', 'Y' => '耏', 'Z' => '耑', '[' => '耓', '\\' => '耚', ']' => '耛', '^' => '耝', '_' => '耞', '`' => '耟', 'a' => '耡', 'b' => '耣', 'c' => '耤', 'd' => '耫', 'e' => '耬', 'f' => '耭', 'g' => '耮', 'h' => '耯', 'i' => '耰', 'j' => '耲', 'k' => '耴', 'l' => '耹', 'm' => '耺', 'n' => '耼', 'o' => '耾', 'p' => '聀', 'q' => '聁', 'r' => '聄', 's' => '聅', 't' => '聇', 'u' => '聈', 'v' => '聉', 'w' => '聎', 'x' => '聏', 'y' => '聐', 'z' => '聑', '{' => '聓', '|' => '聕', '}' => '聖', '~' => '聗', '€' => '聙', '' => '聛', '‚' => '聜', 'ƒ' => '聝', '„' => '聞', '…' => '聟', '†' => '聠', '‡' => '聡', 'ˆ' => '聢', '‰' => '聣', 'Š' => '聤', '‹' => '聥', 'Œ' => '聦', '' => '聧', 'Ž' => '聨', '' => '聫', '' => '聬', '‘' => '聭', '’' => '聮', '“' => '聯', '”' => '聰', '•' => '聲', '–' => '聳', '—' => '聴', '˜' => '聵', '™' => '聶', 'š' => '職', '›' => '聸', 'œ' => '聹', '' => '聺', 'ž' => '聻', 'Ÿ' => '聼', ' ' => '聽', '¡' => '隆', '¢' => '垄', '£' => '拢', '¤' => '陇', '¥' => '楼', '¦' => '娄', '§' => '搂', '¨' => '篓', '©' => '漏', 'ª' => '陋', '«' => '芦', '¬' => '卢', '­' => '颅', '®' => '庐', '¯' => '炉', '°' => '掳', '±' => '卤', '²' => '虏', '³' => '鲁', '´' => '麓', 'µ' => '碌', '¶' => '露', '·' => '路', '¸' => '赂', '¹' => '鹿', 'º' => '潞', '»' => '禄', '¼' => '录', '½' => '陆', '¾' => '戮', '¿' => '驴', '' => '吕', '' => '铝', '' => '侣', '' => '旅', '' => '履', '' => '屡', '' => '缕', '' => '虑', '' => '氯', '' => '律', '' => '率', '' => '滤', '' => '绿', '' => '峦', '' => '挛', '' => '孪', '' => '滦', '' => '卵', '' => '乱', '' => '掠', '' => '略', '' => '抡', '' => '轮', '' => '伦', '' => '仑', '' => '沦', '' => '纶', '' => '论', '' => '萝', '' => '螺', '' => '罗', '' => '逻', '' => '锣', '' => '箩', '' => '骡', '' => '裸', '' => '落', '' => '洛', '' => '骆', '' => '络', '' => '妈', '' => '麻', '' => '玛', '' => '码', '' => '蚂', '' => '马', '' => '骂', '' => '嘛', '' => '吗', '' => '埋', '' => '买', '' => '麦', '' => '卖', '' => '迈', '' => '脉', '' => '瞒', '' => '馒', '' => '蛮', '' => '满', '' => '蔓', '' => '曼', '' => '慢', '' => '漫', '@' => '聾', 'A' => '肁', 'B' => '肂', 'C' => '肅', 'D' => '肈', 'E' => '肊', 'F' => '肍', 'G' => '肎', 'H' => '肏', 'I' => '肐', 'J' => '肑', 'K' => '肒', 'L' => '肔', 'M' => '肕', 'N' => '肗', 'O' => '肙', 'P' => '肞', 'Q' => '肣', 'R' => '肦', 'S' => '肧', 'T' => '肨', 'U' => '肬', 'V' => '肰', 'W' => '肳', 'X' => '肵', 'Y' => '肶', 'Z' => '肸', '[' => '肹', '\\' => '肻', ']' => '胅', '^' => '胇', '_' => '胈', '`' => '胉', 'a' => '胊', 'b' => '胋', 'c' => '胏', 'd' => '胐', 'e' => '胑', 'f' => '胒', 'g' => '胓', 'h' => '胔', 'i' => '胕', 'j' => '胘', 'k' => '胟', 'l' => '胠', 'm' => '胢', 'n' => '胣', 'o' => '胦', 'p' => '胮', 'q' => '胵', 'r' => '胷', 's' => '胹', 't' => '胻', 'u' => '胾', 'v' => '胿', 'w' => '脀', 'x' => '脁', 'y' => '脃', 'z' => '脄', '{' => '脅', '|' => '脇', '}' => '脈', '~' => '脋', 'À' => '脌', 'Á' => '脕', 'Â' => '脗', 'Ã' => '脙', 'Ä' => '脛', 'Å' => '脜', 'Æ' => '脝', 'Ç' => '脟', 'È' => '脠', 'É' => '脡', 'Ê' => '脢', 'Ë' => '脣', 'Ì' => '脤', 'Í' => '脥', 'Î' => '脦', 'Ï' => '脧', 'Ð' => '脨', 'Ñ' => '脩', 'Ò' => '脪', 'Ó' => '脫', 'Ô' => '脭', 'Õ' => '脮', 'Ö' => '脰', '×' => '脳', 'Ø' => '脴', 'Ù' => '脵', 'Ú' => '脷', 'Û' => '脹', 'Ü' => '脺', 'Ý' => '脻', 'Þ' => '脼', 'ß' => '脽', 'à' => '脿', 'á' => '谩', 'â' => '芒', 'ã' => '茫', 'ä' => '盲', 'å' => '氓', 'æ' => '忙', 'ç' => '莽', 'è' => '猫', 'é' => '茅', 'ê' => '锚', 'ë' => '毛', 'ì' => '矛', 'í' => '铆', 'î' => '卯', 'ï' => '茂', 'ð' => '冒', 'ñ' => '帽', 'ò' => '貌', 'ó' => '贸', 'ô' => '么', 'õ' => '玫', 'ö' => '枚', '÷' => '梅', 'ø' => '酶', 'ù' => '霉', 'ú' => '煤', 'û' => '没', 'ü' => '眉', 'ý' => '媒', 'þ' => '镁', 'ÿ' => '每', '' => '美', '' => '昧', '' => '寐', '' => '妹', '' => '媚', '' => '门', '' => '闷', '' => '们', '' => '萌', '' => '蒙', '' => '檬', '' => '盟', '' => '锰', '' => '猛', '' => '梦', '' => '孟', '' => '眯', '' => '醚', '' => '靡', '' => '糜', '' => '迷', '' => '谜', '' => '弥', '' => '米', '' => '秘', '' => '觅', '' => '泌', '' => '蜜', '' => '密', '' => '幂', '' => '棉', '' => '眠', '' => '绵', '' => '冕', '' => '免', '' => '勉', '' => '娩', '' => '缅', '' => '面', '' => '苗', '' => '描', '' => '瞄', '' => '藐', '' => '秒', '' => '渺', '' => '庙', '' => '妙', '' => '蔑', '' => '灭', '' => '民', '' => '抿', '' => '皿', '' => '敏', '' => '悯', '' => '闽', '' => '明', '' => '螟', '' => '鸣', '' => '铭', '' => '名', '' => '命', '' => '谬', '' => '摸', '@' => '腀', 'A' => '腁', 'B' => '腂', 'C' => '腃', 'D' => '腄', 'E' => '腅', 'F' => '腇', 'G' => '腉', 'H' => '腍', 'I' => '腎', 'J' => '腏', 'K' => '腒', 'L' => '腖', 'M' => '腗', 'N' => '腘', 'O' => '腛', 'P' => '腜', 'Q' => '腝', 'R' => '腞', 'S' => '腟', 'T' => '腡', 'U' => '腢', 'V' => '腣', 'W' => '腤', 'X' => '腦', 'Y' => '腨', 'Z' => '腪', '[' => '腫', '\\' => '腬', ']' => '腯', '^' => '腲', '_' => '腳', '`' => '腵', 'a' => '腶', 'b' => '腷', 'c' => '腸', 'd' => '膁', 'e' => '膃', 'f' => '膄', 'g' => '膅', 'h' => '膆', 'i' => '膇', 'j' => '膉', 'k' => '膋', 'l' => '膌', 'm' => '膍', 'n' => '膎', 'o' => '膐', 'p' => '膒', 'q' => '膓', 'r' => '膔', 's' => '膕', 't' => '膖', 'u' => '膗', 'v' => '膙', 'w' => '膚', 'x' => '膞', 'y' => '膟', 'z' => '膠', '{' => '膡', '|' => '膢', '}' => '膤', '~' => '膥', 'Ā' => '膧', 'ā' => '膩', 'Ă' => '膫', 'ă' => '膬', 'Ą' => '膭', 'ą' => '膮', 'Ć' => '膯', 'ć' => '膰', 'Ĉ' => '膱', 'ĉ' => '膲', 'Ċ' => '膴', 'ċ' => '膵', 'Č' => '膶', 'č' => '膷', 'Ď' => '膸', 'ď' => '膹', 'Đ' => '膼', 'đ' => '膽', 'Ē' => '膾', 'ē' => '膿', 'Ĕ' => '臄', 'ĕ' => '臅', 'Ė' => '臇', 'ė' => '臈', 'Ę' => '臉', 'ę' => '臋', 'Ě' => '臍', 'ě' => '臎', 'Ĝ' => '臏', 'ĝ' => '臐', 'Ğ' => '臑', 'ğ' => '臒', 'Ġ' => '臓', 'ġ' => '摹', 'Ģ' => '蘑', 'ģ' => '模', 'Ĥ' => '膜', 'ĥ' => '磨', 'Ħ' => '摩', 'ħ' => '魔', 'Ĩ' => '抹', 'ĩ' => '末', 'Ī' => '莫', 'ī' => '墨', 'Ĭ' => '默', 'ĭ' => '沫', 'Į' => '漠', 'į' => '寞', 'İ' => '陌', 'ı' => '谋', 'IJ' => '牟', 'ij' => '某', 'Ĵ' => '拇', 'ĵ' => '牡', 'Ķ' => '亩', 'ķ' => '姆', 'ĸ' => '母', 'Ĺ' => '墓', 'ĺ' => '暮', 'Ļ' => '幕', 'ļ' => '募', 'Ľ' => '慕', 'ľ' => '木', 'Ŀ' => '目', '' => '睦', '' => '牧', '' => '穆', '' => '拿', '' => '哪', '' => '呐', '' => '钠', '' => '那', '' => '娜', '' => '纳', '' => '氖', '' => '乃', '' => '奶', '' => '耐', '' => '奈', '' => '南', '' => '男', '' => '难', '' => '囊', '' => '挠', '' => '脑', '' => '恼', '' => '闹', '' => '淖', '' => '呢', '' => '馁', '' => '内', '' => '嫩', '' => '能', '' => '妮', '' => '霓', '' => '倪', '' => '泥', '' => '尼', '' => '拟', '' => '你', '' => '匿', '' => '腻', '' => '逆', '' => '溺', '' => '蔫', '' => '拈', '' => '年', '' => '碾', '' => '撵', '' => '捻', '' => '念', '' => '娘', '' => '酿', '' => '鸟', '' => '尿', '' => '捏', '' => '聂', '' => '孽', '' => '啮', '' => '镊', '' => '镍', '' => '涅', '' => '您', '' => '柠', '' => '狞', '' => '凝', '' => '宁', '@' => '臔', 'A' => '臕', 'B' => '臖', 'C' => '臗', 'D' => '臘', 'E' => '臙', 'F' => '臚', 'G' => '臛', 'H' => '臜', 'I' => '臝', 'J' => '臞', 'K' => '臟', 'L' => '臠', 'M' => '臡', 'N' => '臢', 'O' => '臤', 'P' => '臥', 'Q' => '臦', 'R' => '臨', 'S' => '臩', 'T' => '臫', 'U' => '臮', 'V' => '臯', 'W' => '臰', 'X' => '臱', 'Y' => '臲', 'Z' => '臵', '[' => '臶', '\\' => '臷', ']' => '臸', '^' => '臹', '_' => '臺', '`' => '臽', 'a' => '臿', 'b' => '舃', 'c' => '與', 'd' => '興', 'e' => '舉', 'f' => '舊', 'g' => '舋', 'h' => '舎', 'i' => '舏', 'j' => '舑', 'k' => '舓', 'l' => '舕', 'm' => '舖', 'n' => '舗', 'o' => '舘', 'p' => '舙', 'q' => '舚', 'r' => '舝', 's' => '舠', 't' => '舤', 'u' => '舥', 'v' => '舦', 'w' => '舧', 'x' => '舩', 'y' => '舮', 'z' => '舲', '{' => '舺', '|' => '舼', '}' => '舽', '~' => '舿', 'ŀ' => '艀', 'Ł' => '艁', 'ł' => '艂', 'Ń' => '艃', 'ń' => '艅', 'Ņ' => '艆', 'ņ' => '艈', 'Ň' => '艊', 'ň' => '艌', 'ʼn' => '艍', 'Ŋ' => '艎', 'ŋ' => '艐', 'Ō' => '艑', 'ō' => '艒', 'Ŏ' => '艓', 'ŏ' => '艔', 'Ő' => '艕', 'ő' => '艖', 'Œ' => '艗', 'œ' => '艙', 'Ŕ' => '艛', 'ŕ' => '艜', 'Ŗ' => '艝', 'ŗ' => '艞', 'Ř' => '艠', 'ř' => '艡', 'Ś' => '艢', 'ś' => '艣', 'Ŝ' => '艤', 'ŝ' => '艥', 'Ş' => '艦', 'ş' => '艧', 'Š' => '艩', 'š' => '拧', 'Ţ' => '泞', 'ţ' => '牛', 'Ť' => '扭', 'ť' => '钮', 'Ŧ' => '纽', 'ŧ' => '脓', 'Ũ' => '浓', 'ũ' => '农', 'Ū' => '弄', 'ū' => '奴', 'Ŭ' => '努', 'ŭ' => '怒', 'Ů' => '女', 'ů' => '暖', 'Ű' => '虐', 'ű' => '疟', 'Ų' => '挪', 'ų' => '懦', 'Ŵ' => '糯', 'ŵ' => '诺', 'Ŷ' => '哦', 'ŷ' => '欧', 'Ÿ' => '鸥', 'Ź' => '殴', 'ź' => '藕', 'Ż' => '呕', 'ż' => '偶', 'Ž' => '沤', 'ž' => '啪', 'ſ' => '趴', '' => '爬', '' => '帕', '' => '怕', '' => '琶', '' => '拍', '' => '排', '' => '牌', '' => '徘', '' => '湃', '' => '派', '' => '攀', '' => '潘', '' => '盘', '' => '磐', '' => '盼', '' => '畔', '' => '判', '' => '叛', '' => '乓', '' => '庞', '' => '旁', '' => '耪', '' => '胖', '' => '抛', '' => '咆', '' => '刨', '' => '炮', '' => '袍', '' => '跑', '' => '泡', '' => '呸', '' => '胚', '' => '培', '' => '裴', '' => '赔', '' => '陪', '' => '配', '' => '佩', '' => '沛', '' => '喷', '' => '盆', '' => '砰', '' => '抨', '' => '烹', '' => '澎', '' => '彭', '' => '蓬', '' => '棚', '' => '硼', '' => '篷', '' => '膨', '' => '朋', '' => '鹏', '' => '捧', '' => '碰', '' => '坯', '' => '砒', '' => '霹', '' => '批', '' => '披', '' => '劈', '' => '琵', '' => '毗', '@' => '艪', 'A' => '艫', 'B' => '艬', 'C' => '艭', 'D' => '艱', 'E' => '艵', 'F' => '艶', 'G' => '艷', 'H' => '艸', 'I' => '艻', 'J' => '艼', 'K' => '芀', 'L' => '芁', 'M' => '芃', 'N' => '芅', 'O' => '芆', 'P' => '芇', 'Q' => '芉', 'R' => '芌', 'S' => '芐', 'T' => '芓', 'U' => '芔', 'V' => '芕', 'W' => '芖', 'X' => '芚', 'Y' => '芛', 'Z' => '芞', '[' => '芠', '\\' => '芢', ']' => '芣', '^' => '芧', '_' => '芲', '`' => '芵', 'a' => '芶', 'b' => '芺', 'c' => '芻', 'd' => '芼', 'e' => '芿', 'f' => '苀', 'g' => '苂', 'h' => '苃', 'i' => '苅', 'j' => '苆', 'k' => '苉', 'l' => '苐', 'm' => '苖', 'n' => '苙', 'o' => '苚', 'p' => '苝', 'q' => '苢', 'r' => '苧', 's' => '苨', 't' => '苩', 'u' => '苪', 'v' => '苬', 'w' => '苭', 'x' => '苮', 'y' => '苰', 'z' => '苲', '{' => '苳', '|' => '苵', '}' => '苶', '~' => '苸', 'ƀ' => '苺', 'Ɓ' => '苼', 'Ƃ' => '苽', 'ƃ' => '苾', 'Ƅ' => '苿', 'ƅ' => '茀', 'Ɔ' => '茊', 'Ƈ' => '茋', 'ƈ' => '茍', 'Ɖ' => '茐', 'Ɗ' => '茒', 'Ƌ' => '茓', 'ƌ' => '茖', 'ƍ' => '茘', 'Ǝ' => '茙', 'Ə' => '茝', 'Ɛ' => '茞', 'Ƒ' => '茟', 'ƒ' => '茠', 'Ɠ' => '茡', 'Ɣ' => '茢', 'ƕ' => '茣', 'Ɩ' => '茤', 'Ɨ' => '茥', 'Ƙ' => '茦', 'ƙ' => '茩', 'ƚ' => '茪', 'ƛ' => '茮', 'Ɯ' => '茰', 'Ɲ' => '茲', 'ƞ' => '茷', 'Ɵ' => '茻', 'Ơ' => '茽', 'ơ' => '啤', 'Ƣ' => '脾', 'ƣ' => '疲', 'Ƥ' => '皮', 'ƥ' => '匹', 'Ʀ' => '痞', 'Ƨ' => '僻', 'ƨ' => '屁', 'Ʃ' => '譬', 'ƪ' => '篇', 'ƫ' => '偏', 'Ƭ' => '片', 'ƭ' => '骗', 'Ʈ' => '飘', 'Ư' => '漂', 'ư' => '瓢', 'Ʊ' => '票', 'Ʋ' => '撇', 'Ƴ' => '瞥', 'ƴ' => '拼', 'Ƶ' => '频', 'ƶ' => '贫', 'Ʒ' => '品', 'Ƹ' => '聘', 'ƹ' => '乒', 'ƺ' => '坪', 'ƻ' => '苹', 'Ƽ' => '萍', 'ƽ' => '平', 'ƾ' => '凭', 'ƿ' => '瓶', '' => '评', '' => '屏', '' => '坡', '' => '泼', '' => '颇', '' => '婆', '' => '破', '' => '魄', '' => '迫', '' => '粕', '' => '剖', '' => '扑', '' => '铺', '' => '仆', '' => '莆', '' => '葡', '' => '菩', '' => '蒲', '' => '埔', '' => '朴', '' => '圃', '' => '普', '' => '浦', '' => '谱', '' => '曝', '' => '瀑', '' => '期', '' => '欺', '' => '栖', '' => '戚', '' => '妻', '' => '七', '' => '凄', '' => '漆', '' => '柒', '' => '沏', '' => '其', '' => '棋', '' => '奇', '' => '歧', '' => '畦', '' => '崎', '' => '脐', '' => '齐', '' => '旗', '' => '祈', '' => '祁', '' => '骑', '' => '起', '' => '岂', '' => '乞', '' => '企', '' => '启', '' => '契', '' => '砌', '' => '器', '' => '气', '' => '迄', '' => '弃', '' => '汽', '' => '泣', '' => '讫', '' => '掐', '@' => '茾', 'A' => '茿', 'B' => '荁', 'C' => '荂', 'D' => '荄', 'E' => '荅', 'F' => '荈', 'G' => '荊', 'H' => '荋', 'I' => '荌', 'J' => '荍', 'K' => '荎', 'L' => '荓', 'M' => '荕', 'N' => '荖', 'O' => '荗', 'P' => '荘', 'Q' => '荙', 'R' => '荝', 'S' => '荢', 'T' => '荰', 'U' => '荱', 'V' => '荲', 'W' => '荳', 'X' => '荴', 'Y' => '荵', 'Z' => '荶', '[' => '荹', '\\' => '荺', ']' => '荾', '^' => '荿', '_' => '莀', '`' => '莁', 'a' => '莂', 'b' => '莃', 'c' => '莄', 'd' => '莇', 'e' => '莈', 'f' => '莊', 'g' => '莋', 'h' => '莌', 'i' => '莍', 'j' => '莏', 'k' => '莐', 'l' => '莑', 'm' => '莔', 'n' => '莕', 'o' => '莖', 'p' => '莗', 'q' => '莙', 'r' => '莚', 's' => '莝', 't' => '莟', 'u' => '莡', 'v' => '莢', 'w' => '莣', 'x' => '莤', 'y' => '莥', 'z' => '莦', '{' => '莧', '|' => '莬', '}' => '莭', '~' => '莮', 'ǀ' => '莯', 'ǁ' => '莵', 'ǂ' => '莻', 'ǃ' => '莾', 'DŽ' => '莿', 'Dž' => '菂', 'dž' => '菃', 'LJ' => '菄', 'Lj' => '菆', 'lj' => '菈', 'NJ' => '菉', 'Nj' => '菋', 'nj' => '菍', 'Ǎ' => '菎', 'ǎ' => '菐', 'Ǐ' => '菑', 'ǐ' => '菒', 'Ǒ' => '菓', 'ǒ' => '菕', 'Ǔ' => '菗', 'ǔ' => '菙', 'Ǖ' => '菚', 'ǖ' => '菛', 'Ǘ' => '菞', 'ǘ' => '菢', 'Ǚ' => '菣', 'ǚ' => '菤', 'Ǜ' => '菦', 'ǜ' => '菧', 'ǝ' => '菨', 'Ǟ' => '菫', 'ǟ' => '菬', 'Ǡ' => '菭', 'ǡ' => '恰', 'Ǣ' => '洽', 'ǣ' => '牵', 'Ǥ' => '扦', 'ǥ' => '钎', 'Ǧ' => '铅', 'ǧ' => '千', 'Ǩ' => '迁', 'ǩ' => '签', 'Ǫ' => '仟', 'ǫ' => '谦', 'Ǭ' => '乾', 'ǭ' => '黔', 'Ǯ' => '钱', 'ǯ' => '钳', 'ǰ' => '前', 'DZ' => '潜', 'Dz' => '遣', 'dz' => '浅', 'Ǵ' => '谴', 'ǵ' => '堑', 'Ƕ' => '嵌', 'Ƿ' => '欠', 'Ǹ' => '歉', 'ǹ' => '枪', 'Ǻ' => '呛', 'ǻ' => '腔', 'Ǽ' => '羌', 'ǽ' => '墙', 'Ǿ' => '蔷', 'ǿ' => '强', '' => '抢', '' => '橇', '' => '锹', '' => '敲', '' => '悄', '' => '桥', '' => '瞧', '' => '乔', '' => '侨', '' => '巧', '' => '鞘', '' => '撬', '' => '翘', '' => '峭', '' => '俏', '' => '窍', '' => '切', '' => '茄', '' => '且', '' => '怯', '' => '窃', '' => '钦', '' => '侵', '' => '亲', '' => '秦', '' => '琴', '' => '勤', '' => '芹', '' => '擒', '' => '禽', '' => '寝', '' => '沁', '' => '青', '' => '轻', '' => '氢', '' => '倾', '' => '卿', '' => '清', '' => '擎', '' => '晴', '' => '氰', '' => '情', '' => '顷', '' => '请', '' => '庆', '' => '琼', '' => '穷', '' => '秋', '' => '丘', '' => '邱', '' => '球', '' => '求', '' => '囚', '' => '酋', '' => '泅', '' => '趋', '' => '区', '' => '蛆', '' => '曲', '' => '躯', '' => '屈', '' => '驱', '' => '渠', '@' => '菮', 'A' => '華', 'B' => '菳', 'C' => '菴', 'D' => '菵', 'E' => '菶', 'F' => '菷', 'G' => '菺', 'H' => '菻', 'I' => '菼', 'J' => '菾', 'K' => '菿', 'L' => '萀', 'M' => '萂', 'N' => '萅', 'O' => '萇', 'P' => '萈', 'Q' => '萉', 'R' => '萊', 'S' => '萐', 'T' => '萒', 'U' => '萓', 'V' => '萔', 'W' => '萕', 'X' => '萖', 'Y' => '萗', 'Z' => '萙', '[' => '萚', '\\' => '萛', ']' => '萞', '^' => '萟', '_' => '萠', '`' => '萡', 'a' => '萢', 'b' => '萣', 'c' => '萩', 'd' => '萪', 'e' => '萫', 'f' => '萬', 'g' => '萭', 'h' => '萮', 'i' => '萯', 'j' => '萰', 'k' => '萲', 'l' => '萳', 'm' => '萴', 'n' => '萵', 'o' => '萶', 'p' => '萷', 'q' => '萹', 'r' => '萺', 's' => '萻', 't' => '萾', 'u' => '萿', 'v' => '葀', 'w' => '葁', 'x' => '葂', 'y' => '葃', 'z' => '葄', '{' => '葅', '|' => '葇', '}' => '葈', '~' => '葉', 'Ȁ' => '葊', 'ȁ' => '葋', 'Ȃ' => '葌', 'ȃ' => '葍', 'Ȅ' => '葎', 'ȅ' => '葏', 'Ȇ' => '葐', 'ȇ' => '葒', 'Ȉ' => '葓', 'ȉ' => '葔', 'Ȋ' => '葕', 'ȋ' => '葖', 'Ȍ' => '葘', 'ȍ' => '葝', 'Ȏ' => '葞', 'ȏ' => '葟', 'Ȑ' => '葠', 'ȑ' => '葢', 'Ȓ' => '葤', 'ȓ' => '葥', 'Ȕ' => '葦', 'ȕ' => '葧', 'Ȗ' => '葨', 'ȗ' => '葪', 'Ș' => '葮', 'ș' => '葯', 'Ț' => '葰', 'ț' => '葲', 'Ȝ' => '葴', 'ȝ' => '葷', 'Ȟ' => '葹', 'ȟ' => '葻', 'Ƞ' => '葼', 'ȡ' => '取', 'Ȣ' => '娶', 'ȣ' => '龋', 'Ȥ' => '趣', 'ȥ' => '去', 'Ȧ' => '圈', 'ȧ' => '颧', 'Ȩ' => '权', 'ȩ' => '醛', 'Ȫ' => '泉', 'ȫ' => '全', 'Ȭ' => '痊', 'ȭ' => '拳', 'Ȯ' => '犬', 'ȯ' => '券', 'Ȱ' => '劝', 'ȱ' => '缺', 'Ȳ' => '炔', 'ȳ' => '瘸', 'ȴ' => '却', 'ȵ' => '鹊', 'ȶ' => '榷', 'ȷ' => '确', 'ȸ' => '雀', 'ȹ' => '裙', 'Ⱥ' => '群', 'Ȼ' => '然', 'ȼ' => '燃', 'Ƚ' => '冉', 'Ⱦ' => '染', 'ȿ' => '瓤', '' => '壤', '' => '攘', '' => '嚷', '' => '让', '' => '饶', '' => '扰', '' => '绕', '' => '惹', '' => '热', '' => '壬', '' => '仁', '' => '人', '' => '忍', '' => '韧', '' => '任', '' => '认', '' => '刃', '' => '妊', '' => '纫', '' => '扔', '' => '仍', '' => '日', '' => '戎', '' => '茸', '' => '蓉', '' => '荣', '' => '融', '' => '熔', '' => '溶', '' => '容', '' => '绒', '' => '冗', '' => '揉', '' => '柔', '' => '肉', '' => '茹', '' => '蠕', '' => '儒', '' => '孺', '' => '如', '' => '辱', '' => '乳', '' => '汝', '' => '入', '' => '褥', '' => '软', '' => '阮', '' => '蕊', '' => '瑞', '' => '锐', '' => '闰', '' => '润', '' => '若', '' => '弱', '' => '撒', '' => '洒', '' => '萨', '' => '腮', '' => '鳃', '' => '塞', '' => '赛', '' => '三', '' => '叁', '@' => '葽', 'A' => '葾', 'B' => '葿', 'C' => '蒀', 'D' => '蒁', 'E' => '蒃', 'F' => '蒄', 'G' => '蒅', 'H' => '蒆', 'I' => '蒊', 'J' => '蒍', 'K' => '蒏', 'L' => '蒐', 'M' => '蒑', 'N' => '蒒', 'O' => '蒓', 'P' => '蒔', 'Q' => '蒕', 'R' => '蒖', 'S' => '蒘', 'T' => '蒚', 'U' => '蒛', 'V' => '蒝', 'W' => '蒞', 'X' => '蒟', 'Y' => '蒠', 'Z' => '蒢', '[' => '蒣', '\\' => '蒤', ']' => '蒥', '^' => '蒦', '_' => '蒧', '`' => '蒨', 'a' => '蒩', 'b' => '蒪', 'c' => '蒫', 'd' => '蒬', 'e' => '蒭', 'f' => '蒮', 'g' => '蒰', 'h' => '蒱', 'i' => '蒳', 'j' => '蒵', 'k' => '蒶', 'l' => '蒷', 'm' => '蒻', 'n' => '蒼', 'o' => '蒾', 'p' => '蓀', 'q' => '蓂', 'r' => '蓃', 's' => '蓅', 't' => '蓆', 'u' => '蓇', 'v' => '蓈', 'w' => '蓋', 'x' => '蓌', 'y' => '蓎', 'z' => '蓏', '{' => '蓒', '|' => '蓔', '}' => '蓕', '~' => '蓗', 'ɀ' => '蓘', 'Ɂ' => '蓙', 'ɂ' => '蓚', 'Ƀ' => '蓛', 'Ʉ' => '蓜', 'Ʌ' => '蓞', 'Ɇ' => '蓡', 'ɇ' => '蓢', 'Ɉ' => '蓤', 'ɉ' => '蓧', 'Ɋ' => '蓨', 'ɋ' => '蓩', 'Ɍ' => '蓪', 'ɍ' => '蓫', 'Ɏ' => '蓭', 'ɏ' => '蓮', 'ɐ' => '蓯', 'ɑ' => '蓱', 'ɒ' => '蓲', 'ɓ' => '蓳', 'ɔ' => '蓴', 'ɕ' => '蓵', 'ɖ' => '蓶', 'ɗ' => '蓷', 'ɘ' => '蓸', 'ə' => '蓹', 'ɚ' => '蓺', 'ɛ' => '蓻', 'ɜ' => '蓽', 'ɝ' => '蓾', 'ɞ' => '蔀', 'ɟ' => '蔁', 'ɠ' => '蔂', 'ɡ' => '伞', 'ɢ' => '散', 'ɣ' => '桑', 'ɤ' => '嗓', 'ɥ' => '丧', 'ɦ' => '搔', 'ɧ' => '骚', 'ɨ' => '扫', 'ɩ' => '嫂', 'ɪ' => '瑟', 'ɫ' => '色', 'ɬ' => '涩', 'ɭ' => '森', 'ɮ' => '僧', 'ɯ' => '莎', 'ɰ' => '砂', 'ɱ' => '杀', 'ɲ' => '刹', 'ɳ' => '沙', 'ɴ' => '纱', 'ɵ' => '傻', 'ɶ' => '啥', 'ɷ' => '煞', 'ɸ' => '筛', 'ɹ' => '晒', 'ɺ' => '珊', 'ɻ' => '苫', 'ɼ' => '杉', 'ɽ' => '山', 'ɾ' => '删', 'ɿ' => '煽', '' => '衫', '' => '闪', '' => '陕', '' => '擅', '' => '赡', '' => '膳', '' => '善', '' => '汕', '' => '扇', '' => '缮', '' => '墒', '' => '伤', '' => '商', '' => '赏', '' => '晌', '' => '上', '' => '尚', '' => '裳', '' => '梢', '' => '捎', '' => '稍', '' => '烧', '' => '芍', '' => '勺', '' => '韶', '' => '少', '' => '哨', '' => '邵', '' => '绍', '' => '奢', '' => '赊', '' => '蛇', '' => '舌', '' => '舍', '' => '赦', '' => '摄', '' => '射', '' => '慑', '' => '涉', '' => '社', '' => '设', '' => '砷', '' => '申', '' => '呻', '' => '伸', '' => '身', '' => '深', '' => '娠', '' => '绅', '' => '神', '' => '沈', '' => '审', '' => '婶', '' => '甚', '' => '肾', '' => '慎', '' => '渗', '' => '声', '' => '生', '' => '甥', '' => '牲', '' => '升', '' => '绳', '@' => '蔃', 'A' => '蔄', 'B' => '蔅', 'C' => '蔆', 'D' => '蔇', 'E' => '蔈', 'F' => '蔉', 'G' => '蔊', 'H' => '蔋', 'I' => '蔍', 'J' => '蔎', 'K' => '蔏', 'L' => '蔐', 'M' => '蔒', 'N' => '蔔', 'O' => '蔕', 'P' => '蔖', 'Q' => '蔘', 'R' => '蔙', 'S' => '蔛', 'T' => '蔜', 'U' => '蔝', 'V' => '蔞', 'W' => '蔠', 'X' => '蔢', 'Y' => '蔣', 'Z' => '蔤', '[' => '蔥', '\\' => '蔦', ']' => '蔧', '^' => '蔨', '_' => '蔩', '`' => '蔪', 'a' => '蔭', 'b' => '蔮', 'c' => '蔯', 'd' => '蔰', 'e' => '蔱', 'f' => '蔲', 'g' => '蔳', 'h' => '蔴', 'i' => '蔵', 'j' => '蔶', 'k' => '蔾', 'l' => '蔿', 'm' => '蕀', 'n' => '蕁', 'o' => '蕂', 'p' => '蕄', 'q' => '蕅', 'r' => '蕆', 's' => '蕇', 't' => '蕋', 'u' => '蕌', 'v' => '蕍', 'w' => '蕎', 'x' => '蕏', 'y' => '蕐', 'z' => '蕑', '{' => '蕒', '|' => '蕓', '}' => '蕔', '~' => '蕕', 'ʀ' => '蕗', 'ʁ' => '蕘', 'ʂ' => '蕚', 'ʃ' => '蕛', 'ʄ' => '蕜', 'ʅ' => '蕝', 'ʆ' => '蕟', 'ʇ' => '蕠', 'ʈ' => '蕡', 'ʉ' => '蕢', 'ʊ' => '蕣', 'ʋ' => '蕥', 'ʌ' => '蕦', 'ʍ' => '蕧', 'ʎ' => '蕩', 'ʏ' => '蕪', 'ʐ' => '蕫', 'ʑ' => '蕬', 'ʒ' => '蕭', 'ʓ' => '蕮', 'ʔ' => '蕯', 'ʕ' => '蕰', 'ʖ' => '蕱', 'ʗ' => '蕳', 'ʘ' => '蕵', 'ʙ' => '蕶', 'ʚ' => '蕷', 'ʛ' => '蕸', 'ʜ' => '蕼', 'ʝ' => '蕽', 'ʞ' => '蕿', 'ʟ' => '薀', 'ʠ' => '薁', 'ʡ' => '省', 'ʢ' => '盛', 'ʣ' => '剩', 'ʤ' => '胜', 'ʥ' => '圣', 'ʦ' => '师', 'ʧ' => '失', 'ʨ' => '狮', 'ʩ' => '施', 'ʪ' => '湿', 'ʫ' => '诗', 'ʬ' => '尸', 'ʭ' => '虱', 'ʮ' => '十', 'ʯ' => '石', 'ʰ' => '拾', 'ʱ' => '时', 'ʲ' => '什', 'ʳ' => '食', 'ʴ' => '蚀', 'ʵ' => '实', 'ʶ' => '识', 'ʷ' => '史', 'ʸ' => '矢', 'ʹ' => '使', 'ʺ' => '屎', 'ʻ' => '驶', 'ʼ' => '始', 'ʽ' => '式', 'ʾ' => '示', 'ʿ' => '士', '' => '世', '' => '柿', '' => '事', '' => '拭', '' => '誓', '' => '逝', '' => '势', '' => '是', '' => '嗜', '' => '噬', '' => '适', '' => '仕', '' => '侍', '' => '释', '' => '饰', '' => '氏', '' => '市', '' => '恃', '' => '室', '' => '视', '' => '试', '' => '收', '' => '手', '' => '首', '' => '守', '' => '寿', '' => '授', '' => '售', '' => '受', '' => '瘦', '' => '兽', '' => '蔬', '' => '枢', '' => '梳', '' => '殊', '' => '抒', '' => '输', '' => '叔', '' => '舒', '' => '淑', '' => '疏', '' => '书', '' => '赎', '' => '孰', '' => '熟', '' => '薯', '' => '暑', '' => '曙', '' => '署', '' => '蜀', '' => '黍', '' => '鼠', '' => '属', '' => '术', '' => '述', '' => '树', '' => '束', '' => '戍', '' => '竖', '' => '墅', '' => '庶', '' => '数', '' => '漱', '@' => '薂', 'A' => '薃', 'B' => '薆', 'C' => '薈', 'D' => '薉', 'E' => '薊', 'F' => '薋', 'G' => '薌', 'H' => '薍', 'I' => '薎', 'J' => '薐', 'K' => '薑', 'L' => '薒', 'M' => '薓', 'N' => '薔', 'O' => '薕', 'P' => '薖', 'Q' => '薗', 'R' => '薘', 'S' => '薙', 'T' => '薚', 'U' => '薝', 'V' => '薞', 'W' => '薟', 'X' => '薠', 'Y' => '薡', 'Z' => '薢', '[' => '薣', '\\' => '薥', ']' => '薦', '^' => '薧', '_' => '薩', '`' => '薫', 'a' => '薬', 'b' => '薭', 'c' => '薱', 'd' => '薲', 'e' => '薳', 'f' => '薴', 'g' => '薵', 'h' => '薶', 'i' => '薸', 'j' => '薺', 'k' => '薻', 'l' => '薼', 'm' => '薽', 'n' => '薾', 'o' => '薿', 'p' => '藀', 'q' => '藂', 'r' => '藃', 's' => '藄', 't' => '藅', 'u' => '藆', 'v' => '藇', 'w' => '藈', 'x' => '藊', 'y' => '藋', 'z' => '藌', '{' => '藍', '|' => '藎', '}' => '藑', '~' => '藒', 'ˀ' => '藔', 'ˁ' => '藖', '˂' => '藗', '˃' => '藘', '˄' => '藙', '˅' => '藚', 'ˆ' => '藛', 'ˇ' => '藝', 'ˈ' => '藞', 'ˉ' => '藟', 'ˊ' => '藠', 'ˋ' => '藡', 'ˌ' => '藢', 'ˍ' => '藣', 'ˎ' => '藥', 'ˏ' => '藦', 'ː' => '藧', 'ˑ' => '藨', '˒' => '藪', '˓' => '藫', '˔' => '藬', '˕' => '藭', '˖' => '藮', '˗' => '藯', '˘' => '藰', '˙' => '藱', '˚' => '藲', '˛' => '藳', '˜' => '藴', '˝' => '藵', '˞' => '藶', '˟' => '藷', 'ˠ' => '藸', 'ˡ' => '恕', 'ˢ' => '刷', 'ˣ' => '耍', 'ˤ' => '摔', '˥' => '衰', '˦' => '甩', '˧' => '帅', '˨' => '栓', '˩' => '拴', '˪' => '霜', '˫' => '双', 'ˬ' => '爽', '˭' => '谁', 'ˮ' => '水', '˯' => '睡', '˰' => '税', '˱' => '吮', '˲' => '瞬', '˳' => '顺', '˴' => '舜', '˵' => '说', '˶' => '硕', '˷' => '朔', '˸' => '烁', '˹' => '斯', '˺' => '撕', '˻' => '嘶', '˼' => '思', '˽' => '私', '˾' => '司', '˿' => '丝', '' => '死', '' => '肆', '' => '寺', '' => '嗣', '' => '四', '' => '伺', '' => '似', '' => '饲', '' => '巳', '' => '松', '' => '耸', '' => '怂', '' => '颂', '' => '送', '' => '宋', '' => '讼', '' => '诵', '' => '搜', '' => '艘', '' => '擞', '' => '嗽', '' => '苏', '' => '酥', '' => '俗', '' => '素', '' => '速', '' => '粟', '' => '僳', '' => '塑', '' => '溯', '' => '宿', '' => '诉', '' => '肃', '' => '酸', '' => '蒜', '' => '算', '' => '虽', '' => '隋', '' => '随', '' => '绥', '' => '髓', '' => '碎', '' => '岁', '' => '穗', '' => '遂', '' => '隧', '' => '祟', '' => '孙', '' => '损', '' => '笋', '' => '蓑', '' => '梭', '' => '唆', '' => '缩', '' => '琐', '' => '索', '' => '锁', '' => '所', '' => '塌', '' => '他', '' => '它', '' => '她', '' => '塔', '@' => '藹', 'A' => '藺', 'B' => '藼', 'C' => '藽', 'D' => '藾', 'E' => '蘀', 'F' => '蘁', 'G' => '蘂', 'H' => '蘃', 'I' => '蘄', 'J' => '蘆', 'K' => '蘇', 'L' => '蘈', 'M' => '蘉', 'N' => '蘊', 'O' => '蘋', 'P' => '蘌', 'Q' => '蘍', 'R' => '蘎', 'S' => '蘏', 'T' => '蘐', 'U' => '蘒', 'V' => '蘓', 'W' => '蘔', 'X' => '蘕', 'Y' => '蘗', 'Z' => '蘘', '[' => '蘙', '\\' => '蘚', ']' => '蘛', '^' => '蘜', '_' => '蘝', '`' => '蘞', 'a' => '蘟', 'b' => '蘠', 'c' => '蘡', 'd' => '蘢', 'e' => '蘣', 'f' => '蘤', 'g' => '蘥', 'h' => '蘦', 'i' => '蘨', 'j' => '蘪', 'k' => '蘫', 'l' => '蘬', 'm' => '蘭', 'n' => '蘮', 'o' => '蘯', 'p' => '蘰', 'q' => '蘱', 'r' => '蘲', 's' => '蘳', 't' => '蘴', 'u' => '蘵', 'v' => '蘶', 'w' => '蘷', 'x' => '蘹', 'y' => '蘺', 'z' => '蘻', '{' => '蘽', '|' => '蘾', '}' => '蘿', '~' => '虀', '̀' => '虁', '́' => '虂', '̂' => '虃', '̃' => '虄', '̄' => '虅', '̅' => '虆', '̆' => '虇', '̇' => '虈', '̈' => '虉', '̉' => '虊', '̊' => '虋', '̋' => '虌', '̌' => '虒', '̍' => '虓', '̎' => '處', '̏' => '虖', '̐' => '虗', '̑' => '虘', '̒' => '虙', '̓' => '虛', '̔' => '虜', '̕' => '虝', '̖' => '號', '̗' => '虠', '̘' => '虡', '̙' => '虣', '̚' => '虤', '̛' => '虥', '̜' => '虦', '̝' => '虧', '̞' => '虨', '̟' => '虩', '̠' => '虪', '̡' => '獭', '̢' => '挞', '̣' => '蹋', '̤' => '踏', '̥' => '胎', '̦' => '苔', '̧' => '抬', '̨' => '台', '̩' => '泰', '̪' => '酞', '̫' => '太', '̬' => '态', '̭' => '汰', '̮' => '坍', '̯' => '摊', '̰' => '贪', '̱' => '瘫', '̲' => '滩', '̳' => '坛', '̴' => '檀', '̵' => '痰', '̶' => '潭', '̷' => '谭', '̸' => '谈', '̹' => '坦', '̺' => '毯', '̻' => '袒', '̼' => '碳', '̽' => '探', '̾' => '叹', '̿' => '炭', '' => '汤', '' => '塘', '' => '搪', '' => '堂', '' => '棠', '' => '膛', '' => '唐', '' => '糖', '' => '倘', '' => '躺', '' => '淌', '' => '趟', '' => '烫', '' => '掏', '' => '涛', '' => '滔', '' => '绦', '' => '萄', '' => '桃', '' => '逃', '' => '淘', '' => '陶', '' => '讨', '' => '套', '' => '特', '' => '藤', '' => '腾', '' => '疼', '' => '誊', '' => '梯', '' => '剔', '' => '踢', '' => '锑', '' => '提', '' => '题', '' => '蹄', '' => '啼', '' => '体', '' => '替', '' => '嚏', '' => '惕', '' => '涕', '' => '剃', '' => '屉', '' => '天', '' => '添', '' => '填', '' => '田', '' => '甜', '' => '恬', '' => '舔', '' => '腆', '' => '挑', '' => '条', '' => '迢', '' => '眺', '' => '跳', '' => '贴', '' => '铁', '' => '帖', '' => '厅', '' => '听', '' => '烃', '@' => '虭', 'A' => '虯', 'B' => '虰', 'C' => '虲', 'D' => '虳', 'E' => '虴', 'F' => '虵', 'G' => '虶', 'H' => '虷', 'I' => '虸', 'J' => '蚃', 'K' => '蚄', 'L' => '蚅', 'M' => '蚆', 'N' => '蚇', 'O' => '蚈', 'P' => '蚉', 'Q' => '蚎', 'R' => '蚏', 'S' => '蚐', 'T' => '蚑', 'U' => '蚒', 'V' => '蚔', 'W' => '蚖', 'X' => '蚗', 'Y' => '蚘', 'Z' => '蚙', '[' => '蚚', '\\' => '蚛', ']' => '蚞', '^' => '蚟', '_' => '蚠', '`' => '蚡', 'a' => '蚢', 'b' => '蚥', 'c' => '蚦', 'd' => '蚫', 'e' => '蚭', 'f' => '蚮', 'g' => '蚲', 'h' => '蚳', 'i' => '蚷', 'j' => '蚸', 'k' => '蚹', 'l' => '蚻', 'm' => '蚼', 'n' => '蚽', 'o' => '蚾', 'p' => '蚿', 'q' => '蛁', 'r' => '蛂', 's' => '蛃', 't' => '蛅', 'u' => '蛈', 'v' => '蛌', 'w' => '蛍', 'x' => '蛒', 'y' => '蛓', 'z' => '蛕', '{' => '蛖', '|' => '蛗', '}' => '蛚', '~' => '蛜', '̀' => '蛝', '́' => '蛠', '͂' => '蛡', '̓' => '蛢', '̈́' => '蛣', 'ͅ' => '蛥', '͆' => '蛦', '͇' => '蛧', '͈' => '蛨', '͉' => '蛪', '͊' => '蛫', '͋' => '蛬', '͌' => '蛯', '͍' => '蛵', '͎' => '蛶', '͏' => '蛷', '͐' => '蛺', '͑' => '蛻', '͒' => '蛼', '͓' => '蛽', '͔' => '蛿', '͕' => '蜁', '͖' => '蜄', '͗' => '蜅', '͘' => '蜆', '͙' => '蜋', '͚' => '蜌', '͛' => '蜎', '͜' => '蜏', '͝' => '蜐', '͞' => '蜑', '͟' => '蜔', '͠' => '蜖', '͡' => '汀', '͢' => '廷', 'ͣ' => '停', 'ͤ' => '亭', 'ͥ' => '庭', 'ͦ' => '挺', 'ͧ' => '艇', 'ͨ' => '通', 'ͩ' => '桐', 'ͪ' => '酮', 'ͫ' => '瞳', 'ͬ' => '同', 'ͭ' => '铜', 'ͮ' => '彤', 'ͯ' => '童', 'Ͱ' => '桶', 'ͱ' => '捅', 'Ͳ' => '筒', 'ͳ' => '统', 'ʹ' => '痛', '͵' => '偷', 'Ͷ' => '投', 'ͷ' => '头', '͸' => '透', '͹' => '凸', 'ͺ' => '秃', 'ͻ' => '突', 'ͼ' => '图', 'ͽ' => '徒', ';' => '途', 'Ϳ' => '涂', '' => '屠', '' => '土', '' => '吐', '' => '兔', '' => '湍', '' => '团', '' => '推', '' => '颓', '' => '腿', '' => '蜕', '' => '褪', '' => '退', '' => '吞', '' => '屯', '' => '臀', '' => '拖', '' => '托', '' => '脱', '' => '鸵', '' => '陀', '' => '驮', '' => '驼', '' => '椭', '' => '妥', '' => '拓', '' => '唾', '' => '挖', '' => '哇', '' => '蛙', '' => '洼', '' => '娃', '' => '瓦', '' => '袜', '' => '歪', '' => '外', '' => '豌', '' => '弯', '' => '湾', '' => '玩', '' => '顽', '' => '丸', '' => '烷', '' => '完', '' => '碗', '' => '挽', '' => '晚', '' => '皖', '' => '惋', '' => '宛', '' => '婉', '' => '万', '' => '腕', '' => '汪', '' => '王', '' => '亡', '' => '枉', '' => '网', '' => '往', '' => '旺', '' => '望', '' => '忘', '' => '妄', '' => '威', '@' => '蜙', 'A' => '蜛', 'B' => '蜝', 'C' => '蜟', 'D' => '蜠', 'E' => '蜤', 'F' => '蜦', 'G' => '蜧', 'H' => '蜨', 'I' => '蜪', 'J' => '蜫', 'K' => '蜬', 'L' => '蜭', 'M' => '蜯', 'N' => '蜰', 'O' => '蜲', 'P' => '蜳', 'Q' => '蜵', 'R' => '蜶', 'S' => '蜸', 'T' => '蜹', 'U' => '蜺', 'V' => '蜼', 'W' => '蜽', 'X' => '蝀', 'Y' => '蝁', 'Z' => '蝂', '[' => '蝃', '\\' => '蝄', ']' => '蝅', '^' => '蝆', '_' => '蝊', '`' => '蝋', 'a' => '蝍', 'b' => '蝏', 'c' => '蝐', 'd' => '蝑', 'e' => '蝒', 'f' => '蝔', 'g' => '蝕', 'h' => '蝖', 'i' => '蝘', 'j' => '蝚', 'k' => '蝛', 'l' => '蝜', 'm' => '蝝', 'n' => '蝞', 'o' => '蝟', 'p' => '蝡', 'q' => '蝢', 'r' => '蝦', 's' => '蝧', 't' => '蝨', 'u' => '蝩', 'v' => '蝪', 'w' => '蝫', 'x' => '蝬', 'y' => '蝭', 'z' => '蝯', '{' => '蝱', '|' => '蝲', '}' => '蝳', '~' => '蝵', '΀' => '蝷', '΁' => '蝸', '΂' => '蝹', '΃' => '蝺', '΄' => '蝿', '΅' => '螀', 'Ά' => '螁', '·' => '螄', 'Έ' => '螆', 'Ή' => '螇', 'Ί' => '螉', '΋' => '螊', 'Ό' => '螌', '΍' => '螎', 'Ύ' => '螏', 'Ώ' => '螐', 'ΐ' => '螑', 'Α' => '螒', 'Β' => '螔', 'Γ' => '螕', 'Δ' => '螖', 'Ε' => '螘', 'Ζ' => '螙', 'Η' => '螚', 'Θ' => '螛', 'Ι' => '螜', 'Κ' => '螝', 'Λ' => '螞', 'Μ' => '螠', 'Ν' => '螡', 'Ξ' => '螢', 'Ο' => '螣', 'Π' => '螤', 'Ρ' => '巍', '΢' => '微', 'Σ' => '危', 'Τ' => '韦', 'Υ' => '违', 'Φ' => '桅', 'Χ' => '围', 'Ψ' => '唯', 'Ω' => '惟', 'Ϊ' => '为', 'Ϋ' => '潍', 'ά' => '维', 'έ' => '苇', 'ή' => '萎', 'ί' => '委', 'ΰ' => '伟', 'α' => '伪', 'β' => '尾', 'γ' => '纬', 'δ' => '未', 'ε' => '蔚', 'ζ' => '味', 'η' => '畏', 'θ' => '胃', 'ι' => '喂', 'κ' => '魏', 'λ' => '位', 'μ' => '渭', 'ν' => '谓', 'ξ' => '尉', 'ο' => '慰', '' => '卫', '' => '瘟', '' => '温', '' => '蚊', '' => '文', '' => '闻', '' => '纹', '' => '吻', '' => '稳', '' => '紊', '' => '问', '' => '嗡', '' => '翁', '' => '瓮', '' => '挝', '' => '蜗', '' => '涡', '' => '窝', '' => '我', '' => '斡', '' => '卧', '' => '握', '' => '沃', '' => '巫', '' => '呜', '' => '钨', '' => '乌', '' => '污', '' => '诬', '' => '屋', '' => '无', '' => '芜', '' => '梧', '' => '吾', '' => '吴', '' => '毋', '' => '武', '' => '五', '' => '捂', '' => '午', '' => '舞', '' => '伍', '' => '侮', '' => '坞', '' => '戊', '' => '雾', '' => '晤', '' => '物', '' => '勿', '' => '务', '' => '悟', '' => '误', '' => '昔', '' => '熙', '' => '析', '' => '西', '' => '硒', '' => '矽', '' => '晰', '' => '嘻', '' => '吸', '' => '锡', '' => '牺', '@' => '螥', 'A' => '螦', 'B' => '螧', 'C' => '螩', 'D' => '螪', 'E' => '螮', 'F' => '螰', 'G' => '螱', 'H' => '螲', 'I' => '螴', 'J' => '螶', 'K' => '螷', 'L' => '螸', 'M' => '螹', 'N' => '螻', 'O' => '螼', 'P' => '螾', 'Q' => '螿', 'R' => '蟁', 'S' => '蟂', 'T' => '蟃', 'U' => '蟄', 'V' => '蟅', 'W' => '蟇', 'X' => '蟈', 'Y' => '蟉', 'Z' => '蟌', '[' => '蟍', '\\' => '蟎', ']' => '蟏', '^' => '蟐', '_' => '蟔', '`' => '蟕', 'a' => '蟖', 'b' => '蟗', 'c' => '蟘', 'd' => '蟙', 'e' => '蟚', 'f' => '蟜', 'g' => '蟝', 'h' => '蟞', 'i' => '蟟', 'j' => '蟡', 'k' => '蟢', 'l' => '蟣', 'm' => '蟤', 'n' => '蟦', 'o' => '蟧', 'p' => '蟨', 'q' => '蟩', 'r' => '蟫', 's' => '蟬', 't' => '蟭', 'u' => '蟯', 'v' => '蟰', 'w' => '蟱', 'x' => '蟲', 'y' => '蟳', 'z' => '蟴', '{' => '蟵', '|' => '蟶', '}' => '蟷', '~' => '蟸', 'π' => '蟺', 'ρ' => '蟻', 'ς' => '蟼', 'σ' => '蟽', 'τ' => '蟿', 'υ' => '蠀', 'φ' => '蠁', 'χ' => '蠂', 'ψ' => '蠄', 'ω' => '蠅', 'ϊ' => '蠆', 'ϋ' => '蠇', 'ό' => '蠈', 'ύ' => '蠉', 'ώ' => '蠋', 'Ϗ' => '蠌', 'ϐ' => '蠍', 'ϑ' => '蠎', 'ϒ' => '蠏', 'ϓ' => '蠐', 'ϔ' => '蠑', 'ϕ' => '蠒', 'ϖ' => '蠔', 'ϗ' => '蠗', 'Ϙ' => '蠘', 'ϙ' => '蠙', 'Ϛ' => '蠚', 'ϛ' => '蠜', 'Ϝ' => '蠝', 'ϝ' => '蠞', 'Ϟ' => '蠟', 'ϟ' => '蠠', 'Ϡ' => '蠣', 'ϡ' => '稀', 'Ϣ' => '息', 'ϣ' => '希', 'Ϥ' => '悉', 'ϥ' => '膝', 'Ϧ' => '夕', 'ϧ' => '惜', 'Ϩ' => '熄', 'ϩ' => '烯', 'Ϫ' => '溪', 'ϫ' => '汐', 'Ϭ' => '犀', 'ϭ' => '檄', 'Ϯ' => '袭', 'ϯ' => '席', 'ϰ' => '习', 'ϱ' => '媳', 'ϲ' => '喜', 'ϳ' => '铣', 'ϴ' => '洗', 'ϵ' => '系', '϶' => '隙', 'Ϸ' => '戏', 'ϸ' => '细', 'Ϲ' => '瞎', 'Ϻ' => '虾', 'ϻ' => '匣', 'ϼ' => '霞', 'Ͻ' => '辖', 'Ͼ' => '暇', 'Ͽ' => '峡', '' => '侠', '' => '狭', '' => '下', '' => '厦', '' => '夏', '' => '吓', '' => '掀', '' => '锨', '' => '先', '' => '仙', '' => '鲜', '' => '纤', '' => '咸', '' => '贤', '' => '衔', '' => '舷', '' => '闲', '' => '涎', '' => '弦', '' => '嫌', '' => '显', '' => '险', '' => '现', '' => '献', '' => '县', '' => '腺', '' => '馅', '' => '羡', '' => '宪', '' => '陷', '' => '限', '' => '线', '' => '相', '' => '厢', '' => '镶', '' => '香', '' => '箱', '' => '襄', '' => '湘', '' => '乡', '' => '翔', '' => '祥', '' => '详', '' => '想', '' => '响', '' => '享', '' => '项', '' => '巷', '' => '橡', '' => '像', '' => '向', '' => '象', '' => '萧', '' => '硝', '' => '霄', '' => '削', '' => '哮', '' => '嚣', '' => '销', '' => '消', '' => '宵', '' => '淆', '' => '晓', '@' => '蠤', 'A' => '蠥', 'B' => '蠦', 'C' => '蠧', 'D' => '蠨', 'E' => '蠩', 'F' => '蠪', 'G' => '蠫', 'H' => '蠬', 'I' => '蠭', 'J' => '蠮', 'K' => '蠯', 'L' => '蠰', 'M' => '蠱', 'N' => '蠳', 'O' => '蠴', 'P' => '蠵', 'Q' => '蠶', 'R' => '蠷', 'S' => '蠸', 'T' => '蠺', 'U' => '蠻', 'V' => '蠽', 'W' => '蠾', 'X' => '蠿', 'Y' => '衁', 'Z' => '衂', '[' => '衃', '\\' => '衆', ']' => '衇', '^' => '衈', '_' => '衉', '`' => '衊', 'a' => '衋', 'b' => '衎', 'c' => '衏', 'd' => '衐', 'e' => '衑', 'f' => '衒', 'g' => '術', 'h' => '衕', 'i' => '衖', 'j' => '衘', 'k' => '衚', 'l' => '衛', 'm' => '衜', 'n' => '衝', 'o' => '衞', 'p' => '衟', 'q' => '衠', 'r' => '衦', 's' => '衧', 't' => '衪', 'u' => '衭', 'v' => '衯', 'w' => '衱', 'x' => '衳', 'y' => '衴', 'z' => '衵', '{' => '衶', '|' => '衸', '}' => '衹', '~' => '衺', 'Ѐ' => '衻', 'Ё' => '衼', 'Ђ' => '袀', 'Ѓ' => '袃', 'Є' => '袆', 'Ѕ' => '袇', 'І' => '袉', 'Ї' => '袊', 'Ј' => '袌', 'Љ' => '袎', 'Њ' => '袏', 'Ћ' => '袐', 'Ќ' => '袑', 'Ѝ' => '袓', 'Ў' => '袔', 'Џ' => '袕', 'А' => '袗', 'Б' => '袘', 'В' => '袙', 'Г' => '袚', 'Д' => '袛', 'Е' => '袝', 'Ж' => '袞', 'З' => '袟', 'И' => '袠', 'Й' => '袡', 'К' => '袣', 'Л' => '袥', 'М' => '袦', 'Н' => '袧', 'О' => '袨', 'П' => '袩', 'Р' => '袪', 'С' => '小', 'Т' => '孝', 'У' => '校', 'Ф' => '肖', 'Х' => '啸', 'Ц' => '笑', 'Ч' => '效', 'Ш' => '楔', 'Щ' => '些', 'Ъ' => '歇', 'Ы' => '蝎', 'Ь' => '鞋', 'Э' => '协', 'Ю' => '挟', 'Я' => '携', 'а' => '邪', 'б' => '斜', 'в' => '胁', 'г' => '谐', 'д' => '写', 'е' => '械', 'ж' => '卸', 'з' => '蟹', 'и' => '懈', 'й' => '泄', 'к' => '泻', 'л' => '谢', 'м' => '屑', 'н' => '薪', 'о' => '芯', 'п' => '锌', '' => '欣', '' => '辛', '' => '新', '' => '忻', '' => '心', '' => '信', '' => '衅', '' => '星', '' => '腥', '' => '猩', '' => '惺', '' => '兴', '' => '刑', '' => '型', '' => '形', '' => '邢', '' => '行', '' => '醒', '' => '幸', '' => '杏', '' => '性', '' => '姓', '' => '兄', '' => '凶', '' => '胸', '' => '匈', '' => '汹', '' => '雄', '' => '熊', '' => '休', '' => '修', '' => '羞', '' => '朽', '' => '嗅', '' => '锈', '' => '秀', '' => '袖', '' => '绣', '' => '墟', '' => '戌', '' => '需', '' => '虚', '' => '嘘', '' => '须', '' => '徐', '' => '许', '' => '蓄', '' => '酗', '' => '叙', '' => '旭', '' => '序', '' => '畜', '' => '恤', '' => '絮', '' => '婿', '' => '绪', '' => '续', '' => '轩', '' => '喧', '' => '宣', '' => '悬', '' => '旋', '' => '玄', '@' => '袬', 'A' => '袮', 'B' => '袯', 'C' => '袰', 'D' => '袲', 'E' => '袳', 'F' => '袴', 'G' => '袵', 'H' => '袶', 'I' => '袸', 'J' => '袹', 'K' => '袺', 'L' => '袻', 'M' => '袽', 'N' => '袾', 'O' => '袿', 'P' => '裀', 'Q' => '裃', 'R' => '裄', 'S' => '裇', 'T' => '裈', 'U' => '裊', 'V' => '裋', 'W' => '裌', 'X' => '裍', 'Y' => '裏', 'Z' => '裐', '[' => '裑', '\\' => '裓', ']' => '裖', '^' => '裗', '_' => '裚', '`' => '裛', 'a' => '補', 'b' => '裝', 'c' => '裞', 'd' => '裠', 'e' => '裡', 'f' => '裦', 'g' => '裧', 'h' => '裩', 'i' => '裪', 'j' => '裫', 'k' => '裬', 'l' => '裭', 'm' => '裮', 'n' => '裯', 'o' => '裲', 'p' => '裵', 'q' => '裶', 'r' => '裷', 's' => '裺', 't' => '裻', 'u' => '製', 'v' => '裿', 'w' => '褀', 'x' => '褁', 'y' => '褃', 'z' => '褄', '{' => '褅', '|' => '褆', '}' => '複', '~' => '褈', 'р' => '褉', 'с' => '褋', 'т' => '褌', 'у' => '褍', 'ф' => '褎', 'х' => '褏', 'ц' => '褑', 'ч' => '褔', 'ш' => '褕', 'щ' => '褖', 'ъ' => '褗', 'ы' => '褘', 'ь' => '褜', 'э' => '褝', 'ю' => '褞', 'я' => '褟', 'ѐ' => '褠', 'ё' => '褢', 'ђ' => '褣', 'ѓ' => '褤', 'є' => '褦', 'ѕ' => '褧', 'і' => '褨', 'ї' => '褩', 'ј' => '褬', 'љ' => '褭', 'њ' => '褮', 'ћ' => '褯', 'ќ' => '褱', 'ѝ' => '褲', 'ў' => '褳', 'џ' => '褵', 'Ѡ' => '褷', 'ѡ' => '选', 'Ѣ' => '癣', 'ѣ' => '眩', 'Ѥ' => '绚', 'ѥ' => '靴', 'Ѧ' => '薛', 'ѧ' => '学', 'Ѩ' => '穴', 'ѩ' => '雪', 'Ѫ' => '血', 'ѫ' => '勋', 'Ѭ' => '熏', 'ѭ' => '循', 'Ѯ' => '旬', 'ѯ' => '询', 'Ѱ' => '寻', 'ѱ' => '驯', 'Ѳ' => '巡', 'ѳ' => '殉', 'Ѵ' => '汛', 'ѵ' => '训', 'Ѷ' => '讯', 'ѷ' => '逊', 'Ѹ' => '迅', 'ѹ' => '压', 'Ѻ' => '押', 'ѻ' => '鸦', 'Ѽ' => '鸭', 'ѽ' => '呀', 'Ѿ' => '丫', 'ѿ' => '芽', '' => '牙', '' => '蚜', '' => '崖', '' => '衙', '' => '涯', '' => '雅', '' => '哑', '' => '亚', '' => '讶', '' => '焉', '' => '咽', '' => '阉', '' => '烟', '' => '淹', '' => '盐', '' => '严', '' => '研', '' => '蜒', '' => '岩', '' => '延', '' => '言', '' => '颜', '' => '阎', '' => '炎', '' => '沿', '' => '奄', '' => '掩', '' => '眼', '' => '衍', '' => '演', '' => '艳', '' => '堰', '' => '燕', '' => '厌', '' => '砚', '' => '雁', '' => '唁', '' => '彦', '' => '焰', '' => '宴', '' => '谚', '' => '验', '' => '殃', '' => '央', '' => '鸯', '' => '秧', '' => '杨', '' => '扬', '' => '佯', '' => '疡', '' => '羊', '' => '洋', '' => '阳', '' => '氧', '' => '仰', '' => '痒', '' => '养', '' => '样', '' => '漾', '' => '邀', '' => '腰', '' => '妖', '' => '瑶', '@' => '褸', 'A' => '褹', 'B' => '褺', 'C' => '褻', 'D' => '褼', 'E' => '褽', 'F' => '褾', 'G' => '褿', 'H' => '襀', 'I' => '襂', 'J' => '襃', 'K' => '襅', 'L' => '襆', 'M' => '襇', 'N' => '襈', 'O' => '襉', 'P' => '襊', 'Q' => '襋', 'R' => '襌', 'S' => '襍', 'T' => '襎', 'U' => '襏', 'V' => '襐', 'W' => '襑', 'X' => '襒', 'Y' => '襓', 'Z' => '襔', '[' => '襕', '\\' => '襖', ']' => '襗', '^' => '襘', '_' => '襙', '`' => '襚', 'a' => '襛', 'b' => '襜', 'c' => '襝', 'd' => '襠', 'e' => '襡', 'f' => '襢', 'g' => '襣', 'h' => '襤', 'i' => '襥', 'j' => '襧', 'k' => '襨', 'l' => '襩', 'm' => '襪', 'n' => '襫', 'o' => '襬', 'p' => '襭', 'q' => '襮', 'r' => '襯', 's' => '襰', 't' => '襱', 'u' => '襲', 'v' => '襳', 'w' => '襴', 'x' => '襵', 'y' => '襶', 'z' => '襷', '{' => '襸', '|' => '襹', '}' => '襺', '~' => '襼', 'Ҁ' => '襽', 'ҁ' => '襾', '҂' => '覀', '҃' => '覂', '҄' => '覄', '҅' => '覅', '҆' => '覇', '҇' => '覈', '҈' => '覉', '҉' => '覊', 'Ҋ' => '見', 'ҋ' => '覌', 'Ҍ' => '覍', 'ҍ' => '覎', 'Ҏ' => '規', 'ҏ' => '覐', 'Ґ' => '覑', 'ґ' => '覒', 'Ғ' => '覓', 'ғ' => '覔', 'Ҕ' => '覕', 'ҕ' => '視', 'Җ' => '覗', 'җ' => '覘', 'Ҙ' => '覙', 'ҙ' => '覚', 'Қ' => '覛', 'қ' => '覜', 'Ҝ' => '覝', 'ҝ' => '覞', 'Ҟ' => '覟', 'ҟ' => '覠', 'Ҡ' => '覡', 'ҡ' => '摇', 'Ң' => '尧', 'ң' => '遥', 'Ҥ' => '窑', 'ҥ' => '谣', 'Ҧ' => '姚', 'ҧ' => '咬', 'Ҩ' => '舀', 'ҩ' => '药', 'Ҫ' => '要', 'ҫ' => '耀', 'Ҭ' => '椰', 'ҭ' => '噎', 'Ү' => '耶', 'ү' => '爷', 'Ұ' => '野', 'ұ' => '冶', 'Ҳ' => '也', 'ҳ' => '页', 'Ҵ' => '掖', 'ҵ' => '业', 'Ҷ' => '叶', 'ҷ' => '曳', 'Ҹ' => '腋', 'ҹ' => '夜', 'Һ' => '液', 'һ' => '一', 'Ҽ' => '壹', 'ҽ' => '医', 'Ҿ' => '揖', 'ҿ' => '铱', '' => '依', '' => '伊', '' => '衣', '' => '颐', '' => '夷', '' => '遗', '' => '移', '' => '仪', '' => '胰', '' => '疑', '' => '沂', '' => '宜', '' => '姨', '' => '彝', '' => '椅', '' => '蚁', '' => '倚', '' => '已', '' => '乙', '' => '矣', '' => '以', '' => '艺', '' => '抑', '' => '易', '' => '邑', '' => '屹', '' => '亿', '' => '役', '' => '臆', '' => '逸', '' => '肄', '' => '疫', '' => '亦', '' => '裔', '' => '意', '' => '毅', '' => '忆', '' => '义', '' => '益', '' => '溢', '' => '诣', '' => '议', '' => '谊', '' => '译', '' => '异', '' => '翼', '' => '翌', '' => '绎', '' => '茵', '' => '荫', '' => '因', '' => '殷', '' => '音', '' => '阴', '' => '姻', '' => '吟', '' => '银', '' => '淫', '' => '寅', '' => '饮', '' => '尹', '' => '引', '' => '隐', '@' => '覢', 'A' => '覣', 'B' => '覤', 'C' => '覥', 'D' => '覦', 'E' => '覧', 'F' => '覨', 'G' => '覩', 'H' => '親', 'I' => '覫', 'J' => '覬', 'K' => '覭', 'L' => '覮', 'M' => '覯', 'N' => '覰', 'O' => '覱', 'P' => '覲', 'Q' => '観', 'R' => '覴', 'S' => '覵', 'T' => '覶', 'U' => '覷', 'V' => '覸', 'W' => '覹', 'X' => '覺', 'Y' => '覻', 'Z' => '覼', '[' => '覽', '\\' => '覾', ']' => '覿', '^' => '觀', '_' => '觃', '`' => '觍', 'a' => '觓', 'b' => '觔', 'c' => '觕', 'd' => '觗', 'e' => '觘', 'f' => '觙', 'g' => '觛', 'h' => '觝', 'i' => '觟', 'j' => '觠', 'k' => '觡', 'l' => '觢', 'm' => '觤', 'n' => '觧', 'o' => '觨', 'p' => '觩', 'q' => '觪', 'r' => '觬', 's' => '觭', 't' => '觮', 'u' => '觰', 'v' => '觱', 'w' => '觲', 'x' => '觴', 'y' => '觵', 'z' => '觶', '{' => '觷', '|' => '觸', '}' => '觹', '~' => '觺', 'Ӏ' => '觻', 'Ӂ' => '觼', 'ӂ' => '觽', 'Ӄ' => '觾', 'ӄ' => '觿', 'Ӆ' => '訁', 'ӆ' => '訂', 'Ӈ' => '訃', 'ӈ' => '訄', 'Ӊ' => '訅', 'ӊ' => '訆', 'Ӌ' => '計', 'ӌ' => '訉', 'Ӎ' => '訊', 'ӎ' => '訋', 'ӏ' => '訌', 'Ӑ' => '訍', 'ӑ' => '討', 'Ӓ' => '訏', 'ӓ' => '訐', 'Ӕ' => '訑', 'ӕ' => '訒', 'Ӗ' => '訓', 'ӗ' => '訔', 'Ә' => '訕', 'ә' => '訖', 'Ӛ' => '託', 'ӛ' => '記', 'Ӝ' => '訙', 'ӝ' => '訚', 'Ӟ' => '訛', 'ӟ' => '訜', 'Ӡ' => '訝', 'ӡ' => '印', 'Ӣ' => '英', 'ӣ' => '樱', 'Ӥ' => '婴', 'ӥ' => '鹰', 'Ӧ' => '应', 'ӧ' => '缨', 'Ө' => '莹', 'ө' => '萤', 'Ӫ' => '营', 'ӫ' => '荧', 'Ӭ' => '蝇', 'ӭ' => '迎', 'Ӯ' => '赢', 'ӯ' => '盈', 'Ӱ' => '影', 'ӱ' => '颖', 'Ӳ' => '硬', 'ӳ' => '映', 'Ӵ' => '哟', 'ӵ' => '拥', 'Ӷ' => '佣', 'ӷ' => '臃', 'Ӹ' => '痈', 'ӹ' => '庸', 'Ӻ' => '雍', 'ӻ' => '踊', 'Ӽ' => '蛹', 'ӽ' => '咏', 'Ӿ' => '泳', 'ӿ' => '涌', '' => '永', '' => '恿', '' => '勇', '' => '用', '' => '幽', '' => '优', '' => '悠', '' => '忧', '' => '尤', '' => '由', '' => '邮', '' => '铀', '' => '犹', '' => '油', '' => '游', '' => '酉', '' => '有', '' => '友', '' => '右', '' => '佑', '' => '釉', '' => '诱', '' => '又', '' => '幼', '' => '迂', '' => '淤', '' => '于', '' => '盂', '' => '榆', '' => '虞', '' => '愚', '' => '舆', '' => '余', '' => '俞', '' => '逾', '' => '鱼', '' => '愉', '' => '渝', '' => '渔', '' => '隅', '' => '予', '' => '娱', '' => '雨', '' => '与', '' => '屿', '' => '禹', '' => '宇', '' => '语', '' => '羽', '' => '玉', '' => '域', '' => '芋', '' => '郁', '' => '吁', '' => '遇', '' => '喻', '' => '峪', '' => '御', '' => '愈', '' => '欲', '' => '狱', '' => '育', '' => '誉', '@' => '訞', 'A' => '訟', 'B' => '訠', 'C' => '訡', 'D' => '訢', 'E' => '訣', 'F' => '訤', 'G' => '訥', 'H' => '訦', 'I' => '訧', 'J' => '訨', 'K' => '訩', 'L' => '訪', 'M' => '訫', 'N' => '訬', 'O' => '設', 'P' => '訮', 'Q' => '訯', 'R' => '訰', 'S' => '許', 'T' => '訲', 'U' => '訳', 'V' => '訴', 'W' => '訵', 'X' => '訶', 'Y' => '訷', 'Z' => '訸', '[' => '訹', '\\' => '診', ']' => '註', '^' => '証', '_' => '訽', '`' => '訿', 'a' => '詀', 'b' => '詁', 'c' => '詂', 'd' => '詃', 'e' => '詄', 'f' => '詅', 'g' => '詆', 'h' => '詇', 'i' => '詉', 'j' => '詊', 'k' => '詋', 'l' => '詌', 'm' => '詍', 'n' => '詎', 'o' => '詏', 'p' => '詐', 'q' => '詑', 'r' => '詒', 's' => '詓', 't' => '詔', 'u' => '評', 'v' => '詖', 'w' => '詗', 'x' => '詘', 'y' => '詙', 'z' => '詚', '{' => '詛', '|' => '詜', '}' => '詝', '~' => '詞', 'Ԁ' => '詟', 'ԁ' => '詠', 'Ԃ' => '詡', 'ԃ' => '詢', 'Ԅ' => '詣', 'ԅ' => '詤', 'Ԇ' => '詥', 'ԇ' => '試', 'Ԉ' => '詧', 'ԉ' => '詨', 'Ԋ' => '詩', 'ԋ' => '詪', 'Ԍ' => '詫', 'ԍ' => '詬', 'Ԏ' => '詭', 'ԏ' => '詮', 'Ԑ' => '詯', 'ԑ' => '詰', 'Ԓ' => '話', 'ԓ' => '該', 'Ԕ' => '詳', 'ԕ' => '詴', 'Ԗ' => '詵', 'ԗ' => '詶', 'Ԙ' => '詷', 'ԙ' => '詸', 'Ԛ' => '詺', 'ԛ' => '詻', 'Ԝ' => '詼', 'ԝ' => '詽', 'Ԟ' => '詾', 'ԟ' => '詿', 'Ԡ' => '誀', 'ԡ' => '浴', 'Ԣ' => '寓', 'ԣ' => '裕', 'Ԥ' => '预', 'ԥ' => '豫', 'Ԧ' => '驭', 'ԧ' => '鸳', 'Ԩ' => '渊', 'ԩ' => '冤', 'Ԫ' => '元', 'ԫ' => '垣', 'Ԭ' => '袁', 'ԭ' => '原', 'Ԯ' => '援', 'ԯ' => '辕', '԰' => '园', 'Ա' => '员', 'Բ' => '圆', 'Գ' => '猿', 'Դ' => '源', 'Ե' => '缘', 'Զ' => '远', 'Է' => '苑', 'Ը' => '愿', 'Թ' => '怨', 'Ժ' => '院', 'Ի' => '曰', 'Լ' => '约', 'Խ' => '越', 'Ծ' => '跃', 'Կ' => '钥', '' => '岳', '' => '粤', '' => '月', '' => '悦', '' => '阅', '' => '耘', '' => '云', '' => '郧', '' => '匀', '' => '陨', '' => '允', '' => '运', '' => '蕴', '' => '酝', '' => '晕', '' => '韵', '' => '孕', '' => '匝', '' => '砸', '' => '杂', '' => '栽', '' => '哉', '' => '灾', '' => '宰', '' => '载', '' => '再', '' => '在', '' => '咱', '' => '攒', '' => '暂', '' => '赞', '' => '赃', '' => '脏', '' => '葬', '' => '遭', '' => '糟', '' => '凿', '' => '藻', '' => '枣', '' => '早', '' => '澡', '' => '蚤', '' => '躁', '' => '噪', '' => '造', '' => '皂', '' => '灶', '' => '燥', '' => '责', '' => '择', '' => '则', '' => '泽', '' => '贼', '' => '怎', '' => '增', '' => '憎', '' => '曾', '' => '赠', '' => '扎', '' => '喳', '' => '渣', '' => '札', '' => '轧', '@' => '誁', 'A' => '誂', 'B' => '誃', 'C' => '誄', 'D' => '誅', 'E' => '誆', 'F' => '誇', 'G' => '誈', 'H' => '誋', 'I' => '誌', 'J' => '認', 'K' => '誎', 'L' => '誏', 'M' => '誐', 'N' => '誑', 'O' => '誒', 'P' => '誔', 'Q' => '誕', 'R' => '誖', 'S' => '誗', 'T' => '誘', 'U' => '誙', 'V' => '誚', 'W' => '誛', 'X' => '誜', 'Y' => '誝', 'Z' => '語', '[' => '誟', '\\' => '誠', ']' => '誡', '^' => '誢', '_' => '誣', '`' => '誤', 'a' => '誥', 'b' => '誦', 'c' => '誧', 'd' => '誨', 'e' => '誩', 'f' => '說', 'g' => '誫', 'h' => '説', 'i' => '読', 'j' => '誮', 'k' => '誯', 'l' => '誰', 'm' => '誱', 'n' => '課', 'o' => '誳', 'p' => '誴', 'q' => '誵', 'r' => '誶', 's' => '誷', 't' => '誸', 'u' => '誹', 'v' => '誺', 'w' => '誻', 'x' => '誼', 'y' => '誽', 'z' => '誾', '{' => '調', '|' => '諀', '}' => '諁', '~' => '諂', 'Հ' => '諃', 'Ձ' => '諄', 'Ղ' => '諅', 'Ճ' => '諆', 'Մ' => '談', 'Յ' => '諈', 'Ն' => '諉', 'Շ' => '諊', 'Ո' => '請', 'Չ' => '諌', 'Պ' => '諍', 'Ջ' => '諎', 'Ռ' => '諏', 'Ս' => '諐', 'Վ' => '諑', 'Տ' => '諒', 'Ր' => '諓', 'Ց' => '諔', 'Ւ' => '諕', 'Փ' => '論', 'Ք' => '諗', 'Օ' => '諘', 'Ֆ' => '諙', '՗' => '諚', '՘' => '諛', 'ՙ' => '諜', '՚' => '諝', '՛' => '諞', '՜' => '諟', '՝' => '諠', '՞' => '諡', '՟' => '諢', 'ՠ' => '諣', 'ա' => '铡', 'բ' => '闸', 'գ' => '眨', 'դ' => '栅', 'ե' => '榨', 'զ' => '咋', 'է' => '乍', 'ը' => '炸', 'թ' => '诈', 'ժ' => '摘', 'ի' => '斋', 'լ' => '宅', 'խ' => '窄', 'ծ' => '债', 'կ' => '寨', 'հ' => '瞻', 'ձ' => '毡', 'ղ' => '詹', 'ճ' => '粘', 'մ' => '沾', 'յ' => '盏', 'ն' => '斩', 'շ' => '辗', 'ո' => '崭', 'չ' => '展', 'պ' => '蘸', 'ջ' => '栈', 'ռ' => '占', 'ս' => '战', 'վ' => '站', 'տ' => '湛', '' => '绽', '' => '樟', '' => '章', '' => '彰', '' => '漳', '' => '张', '' => '掌', '' => '涨', '' => '杖', '' => '丈', '' => '帐', '' => '账', '' => '仗', '' => '胀', '' => '瘴', '' => '障', '' => '招', '' => '昭', '' => '找', '' => '沼', '' => '赵', '' => '照', '' => '罩', '' => '兆', '' => '肇', '' => '召', '' => '遮', '' => '折', '' => '哲', '' => '蛰', '' => '辙', '' => '者', '' => '锗', '' => '蔗', '' => '这', '' => '浙', '' => '珍', '' => '斟', '' => '真', '' => '甄', '' => '砧', '' => '臻', '' => '贞', '' => '针', '' => '侦', '' => '枕', '' => '疹', '' => '诊', '' => '震', '' => '振', '' => '镇', '' => '阵', '' => '蒸', '' => '挣', '' => '睁', '' => '征', '' => '狰', '' => '争', '' => '怔', '' => '整', '' => '拯', '' => '正', '' => '政', '@' => '諤', 'A' => '諥', 'B' => '諦', 'C' => '諧', 'D' => '諨', 'E' => '諩', 'F' => '諪', 'G' => '諫', 'H' => '諬', 'I' => '諭', 'J' => '諮', 'K' => '諯', 'L' => '諰', 'M' => '諱', 'N' => '諲', 'O' => '諳', 'P' => '諴', 'Q' => '諵', 'R' => '諶', 'S' => '諷', 'T' => '諸', 'U' => '諹', 'V' => '諺', 'W' => '諻', 'X' => '諼', 'Y' => '諽', 'Z' => '諾', '[' => '諿', '\\' => '謀', ']' => '謁', '^' => '謂', '_' => '謃', '`' => '謄', 'a' => '謅', 'b' => '謆', 'c' => '謈', 'd' => '謉', 'e' => '謊', 'f' => '謋', 'g' => '謌', 'h' => '謍', 'i' => '謎', 'j' => '謏', 'k' => '謐', 'l' => '謑', 'm' => '謒', 'n' => '謓', 'o' => '謔', 'p' => '謕', 'q' => '謖', 'r' => '謗', 's' => '謘', 't' => '謙', 'u' => '謚', 'v' => '講', 'w' => '謜', 'x' => '謝', 'y' => '謞', 'z' => '謟', '{' => '謠', '|' => '謡', '}' => '謢', '~' => '謣', 'ր' => '謤', 'ց' => '謥', 'ւ' => '謧', 'փ' => '謨', 'ք' => '謩', 'օ' => '謪', 'ֆ' => '謫', 'և' => '謬', 'ֈ' => '謭', '։' => '謮', '֊' => '謯', '֋' => '謰', '֌' => '謱', '֍' => '謲', '֎' => '謳', '֏' => '謴', '֐' => '謵', '֑' => '謶', '֒' => '謷', '֓' => '謸', '֔' => '謹', '֕' => '謺', '֖' => '謻', '֗' => '謼', '֘' => '謽', '֙' => '謾', '֚' => '謿', '֛' => '譀', '֜' => '譁', '֝' => '譂', '֞' => '譃', '֟' => '譄', '֠' => '譅', '֡' => '帧', '֢' => '症', '֣' => '郑', '֤' => '证', '֥' => '芝', '֦' => '枝', '֧' => '支', '֨' => '吱', '֩' => '蜘', '֪' => '知', '֫' => '肢', '֬' => '脂', '֭' => '汁', '֮' => '之', '֯' => '织', 'ְ' => '职', 'ֱ' => '直', 'ֲ' => '植', 'ֳ' => '殖', 'ִ' => '执', 'ֵ' => '值', 'ֶ' => '侄', 'ַ' => '址', 'ָ' => '指', 'ֹ' => '止', 'ֺ' => '趾', 'ֻ' => '只', 'ּ' => '旨', 'ֽ' => '纸', '־' => '志', 'ֿ' => '挚', '' => '掷', '' => '至', '' => '致', '' => '置', '' => '帜', '' => '峙', '' => '制', '' => '智', '' => '秩', '' => '稚', '' => '质', '' => '炙', '' => '痔', '' => '滞', '' => '治', '' => '窒', '' => '中', '' => '盅', '' => '忠', '' => '钟', '' => '衷', '' => '终', '' => '种', '' => '肿', '' => '重', '' => '仲', '' => '众', '' => '舟', '' => '周', '' => '州', '' => '洲', '' => '诌', '' => '粥', '' => '轴', '' => '肘', '' => '帚', '' => '咒', '' => '皱', '' => '宙', '' => '昼', '' => '骤', '' => '珠', '' => '株', '' => '蛛', '' => '朱', '' => '猪', '' => '诸', '' => '诛', '' => '逐', '' => '竹', '' => '烛', '' => '煮', '' => '拄', '' => '瞩', '' => '嘱', '' => '主', '' => '著', '' => '柱', '' => '助', '' => '蛀', '' => '贮', '' => '铸', '' => '筑', '@' => '譆', 'A' => '譇', 'B' => '譈', 'C' => '證', 'D' => '譊', 'E' => '譋', 'F' => '譌', 'G' => '譍', 'H' => '譎', 'I' => '譏', 'J' => '譐', 'K' => '譑', 'L' => '譒', 'M' => '譓', 'N' => '譔', 'O' => '譕', 'P' => '譖', 'Q' => '譗', 'R' => '識', 'S' => '譙', 'T' => '譚', 'U' => '譛', 'V' => '譜', 'W' => '譝', 'X' => '譞', 'Y' => '譟', 'Z' => '譠', '[' => '譡', '\\' => '譢', ']' => '譣', '^' => '譤', '_' => '譥', '`' => '譧', 'a' => '譨', 'b' => '譩', 'c' => '譪', 'd' => '譫', 'e' => '譭', 'f' => '譮', 'g' => '譯', 'h' => '議', 'i' => '譱', 'j' => '譲', 'k' => '譳', 'l' => '譴', 'm' => '譵', 'n' => '譶', 'o' => '護', 'p' => '譸', 'q' => '譹', 'r' => '譺', 's' => '譻', 't' => '譼', 'u' => '譽', 'v' => '譾', 'w' => '譿', 'x' => '讀', 'y' => '讁', 'z' => '讂', '{' => '讃', '|' => '讄', '}' => '讅', '~' => '讆', '׀' => '讇', 'ׁ' => '讈', 'ׂ' => '讉', '׃' => '變', 'ׄ' => '讋', 'ׅ' => '讌', '׆' => '讍', 'ׇ' => '讎', '׈' => '讏', '׉' => '讐', '׊' => '讑', '׋' => '讒', '׌' => '讓', '׍' => '讔', '׎' => '讕', '׏' => '讖', 'א' => '讗', 'ב' => '讘', 'ג' => '讙', 'ד' => '讚', 'ה' => '讛', 'ו' => '讜', 'ז' => '讝', 'ח' => '讞', 'ט' => '讟', 'י' => '讬', 'ך' => '讱', 'כ' => '讻', 'ל' => '诇', 'ם' => '诐', 'מ' => '诪', 'ן' => '谉', 'נ' => '谞', 'ס' => '住', 'ע' => '注', 'ף' => '祝', 'פ' => '驻', 'ץ' => '抓', 'צ' => '爪', 'ק' => '拽', 'ר' => '专', 'ש' => '砖', 'ת' => '转', '׫' => '撰', '׬' => '赚', '׭' => '篆', '׮' => '桩', 'ׯ' => '庄', 'װ' => '装', 'ױ' => '妆', 'ײ' => '撞', '׳' => '壮', '״' => '状', '׵' => '椎', '׶' => '锥', '׷' => '追', '׸' => '赘', '׹' => '坠', '׺' => '缀', '׻' => '谆', '׼' => '准', '׽' => '捉', '׾' => '拙', '׿' => '卓', '' => '桌', '' => '琢', '' => '茁', '' => '酌', '' => '啄', '' => '着', '' => '灼', '' => '浊', '' => '兹', '' => '咨', '' => '资', '' => '姿', '' => '滋', '' => '淄', '' => '孜', '' => '紫', '' => '仔', '' => '籽', '' => '滓', '' => '子', '' => '自', '' => '渍', '' => '字', '' => '鬃', '' => '棕', '' => '踪', '' => '宗', '' => '综', '' => '总', '' => '纵', '' => '邹', '' => '走', '' => '奏', '' => '揍', '' => '租', '' => '足', '' => '卒', '' => '族', '' => '祖', '' => '诅', '' => '阻', '' => '组', '' => '钻', '' => '纂', '' => '嘴', '' => '醉', '' => '最', '' => '罪', '' => '尊', '' => '遵', '' => '昨', '' => '左', '' => '佐', '' => '柞', '' => '做', '' => '作', '' => '坐', '' => '座', '@' => '谸', 'A' => '谹', 'B' => '谺', 'C' => '谻', 'D' => '谼', 'E' => '谽', 'F' => '谾', 'G' => '谿', 'H' => '豀', 'I' => '豂', 'J' => '豃', 'K' => '豄', 'L' => '豅', 'M' => '豈', 'N' => '豊', 'O' => '豋', 'P' => '豍', 'Q' => '豎', 'R' => '豏', 'S' => '豐', 'T' => '豑', 'U' => '豒', 'V' => '豓', 'W' => '豔', 'X' => '豖', 'Y' => '豗', 'Z' => '豘', '[' => '豙', '\\' => '豛', ']' => '豜', '^' => '豝', '_' => '豞', '`' => '豟', 'a' => '豠', 'b' => '豣', 'c' => '豤', 'd' => '豥', 'e' => '豦', 'f' => '豧', 'g' => '豨', 'h' => '豩', 'i' => '豬', 'j' => '豭', 'k' => '豮', 'l' => '豯', 'm' => '豰', 'n' => '豱', 'o' => '豲', 'p' => '豴', 'q' => '豵', 'r' => '豶', 's' => '豷', 't' => '豻', 'u' => '豼', 'v' => '豽', 'w' => '豾', 'x' => '豿', 'y' => '貀', 'z' => '貁', '{' => '貃', '|' => '貄', '}' => '貆', '~' => '貇', '؀' => '貈', '؁' => '貋', '؂' => '貍', '؃' => '貎', '؄' => '貏', '؅' => '貐', '؆' => '貑', '؇' => '貒', '؈' => '貓', '؉' => '貕', '؊' => '貖', '؋' => '貗', '،' => '貙', '؍' => '貚', '؎' => '貛', '؏' => '貜', 'ؐ' => '貝', 'ؑ' => '貞', 'ؒ' => '貟', 'ؓ' => '負', 'ؔ' => '財', 'ؕ' => '貢', 'ؖ' => '貣', 'ؗ' => '貤', 'ؘ' => '貥', 'ؙ' => '貦', 'ؚ' => '貧', '؛' => '貨', '؜' => '販', '؝' => '貪', '؞' => '貫', '؟' => '責', 'ؠ' => '貭', 'ء' => '亍', 'آ' => '丌', 'أ' => '兀', 'ؤ' => '丐', 'إ' => '廿', 'ئ' => '卅', 'ا' => '丕', 'ب' => '亘', 'ة' => '丞', 'ت' => '鬲', 'ث' => '孬', 'ج' => '噩', 'ح' => '丨', 'خ' => '禺', 'د' => '丿', 'ذ' => '匕', 'ر' => '乇', 'ز' => '夭', 'س' => '爻', 'ش' => '卮', 'ص' => '氐', 'ض' => '囟', 'ط' => '胤', 'ظ' => '馗', 'ع' => '毓', 'غ' => '睾', 'ػ' => '鼗', 'ؼ' => '丶', 'ؽ' => '亟', 'ؾ' => '鼐', 'ؿ' => '乜', '' => '乩', '' => '亓', '' => '芈', '' => '孛', '' => '啬', '' => '嘏', '' => '仄', '' => '厍', '' => '厝', '' => '厣', '' => '厥', '' => '厮', '' => '靥', '' => '赝', '' => '匚', '' => '叵', '' => '匦', '' => '匮', '' => '匾', '' => '赜', '' => '卦', '' => '卣', '' => '刂', '' => '刈', '' => '刎', '' => '刭', '' => '刳', '' => '刿', '' => '剀', '' => '剌', '' => '剞', '' => '剡', '' => '剜', '' => '蒯', '' => '剽', '' => '劂', '' => '劁', '' => '劐', '' => '劓', '' => '冂', '' => '罔', '' => '亻', '' => '仃', '' => '仉', '' => '仂', '' => '仨', '' => '仡', '' => '仫', '' => '仞', '' => '伛', '' => '仳', '' => '伢', '' => '佤', '' => '仵', '' => '伥', '' => '伧', '' => '伉', '' => '伫', '' => '佞', '' => '佧', '' => '攸', '' => '佚', '' => '佝', '@' => '貮', 'A' => '貯', 'B' => '貰', 'C' => '貱', 'D' => '貲', 'E' => '貳', 'F' => '貴', 'G' => '貵', 'H' => '貶', 'I' => '買', 'J' => '貸', 'K' => '貹', 'L' => '貺', 'M' => '費', 'N' => '貼', 'O' => '貽', 'P' => '貾', 'Q' => '貿', 'R' => '賀', 'S' => '賁', 'T' => '賂', 'U' => '賃', 'V' => '賄', 'W' => '賅', 'X' => '賆', 'Y' => '資', 'Z' => '賈', '[' => '賉', '\\' => '賊', ']' => '賋', '^' => '賌', '_' => '賍', '`' => '賎', 'a' => '賏', 'b' => '賐', 'c' => '賑', 'd' => '賒', 'e' => '賓', 'f' => '賔', 'g' => '賕', 'h' => '賖', 'i' => '賗', 'j' => '賘', 'k' => '賙', 'l' => '賚', 'm' => '賛', 'n' => '賜', 'o' => '賝', 'p' => '賞', 'q' => '賟', 'r' => '賠', 's' => '賡', 't' => '賢', 'u' => '賣', 'v' => '賤', 'w' => '賥', 'x' => '賦', 'y' => '賧', 'z' => '賨', '{' => '賩', '|' => '質', '}' => '賫', '~' => '賬', 'ـ' => '賭', 'ف' => '賮', 'ق' => '賯', 'ك' => '賰', 'ل' => '賱', 'م' => '賲', 'ن' => '賳', 'ه' => '賴', 'و' => '賵', 'ى' => '賶', 'ي' => '賷', 'ً' => '賸', 'ٌ' => '賹', 'ٍ' => '賺', 'َ' => '賻', 'ُ' => '購', 'ِ' => '賽', 'ّ' => '賾', 'ْ' => '賿', 'ٓ' => '贀', 'ٔ' => '贁', 'ٕ' => '贂', 'ٖ' => '贃', 'ٗ' => '贄', '٘' => '贅', 'ٙ' => '贆', 'ٚ' => '贇', 'ٛ' => '贈', 'ٜ' => '贉', 'ٝ' => '贊', 'ٞ' => '贋', 'ٟ' => '贌', '٠' => '贍', '١' => '佟', '٢' => '佗', '٣' => '伲', '٤' => '伽', '٥' => '佶', '٦' => '佴', '٧' => '侑', '٨' => '侉', '٩' => '侃', '٪' => '侏', '٫' => '佾', '٬' => '佻', '٭' => '侪', 'ٮ' => '佼', 'ٯ' => '侬', 'ٰ' => '侔', 'ٱ' => '俦', 'ٲ' => '俨', 'ٳ' => '俪', 'ٴ' => '俅', 'ٵ' => '俚', 'ٶ' => '俣', 'ٷ' => '俜', 'ٸ' => '俑', 'ٹ' => '俟', 'ٺ' => '俸', 'ٻ' => '倩', 'ټ' => '偌', 'ٽ' => '俳', 'پ' => '倬', 'ٿ' => '倏', '' => '倮', '' => '倭', '' => '俾', '' => '倜', '' => '倌', '' => '倥', '' => '倨', '' => '偾', '' => '偃', '' => '偕', '' => '偈', '' => '偎', '' => '偬', '' => '偻', '' => '傥', '' => '傧', '' => '傩', '' => '傺', '' => '僖', '' => '儆', '' => '僭', '' => '僬', '' => '僦', '' => '僮', '' => '儇', '' => '儋', '' => '仝', '' => '氽', '' => '佘', '' => '佥', '' => '俎', '' => '龠', '' => '汆', '' => '籴', '' => '兮', '' => '巽', '' => '黉', '' => '馘', '' => '冁', '' => '夔', '' => '勹', '' => '匍', '' => '訇', '' => '匐', '' => '凫', '' => '夙', '' => '兕', '' => '亠', '' => '兖', '' => '亳', '' => '衮', '' => '袤', '' => '亵', '' => '脔', '' => '裒', '' => '禀', '' => '嬴', '' => '蠃', '' => '羸', '' => '冫', '' => '冱', '' => '冽', '' => '冼', '@' => '贎', 'A' => '贏', 'B' => '贐', 'C' => '贑', 'D' => '贒', 'E' => '贓', 'F' => '贔', 'G' => '贕', 'H' => '贖', 'I' => '贗', 'J' => '贘', 'K' => '贙', 'L' => '贚', 'M' => '贛', 'N' => '贜', 'O' => '贠', 'P' => '赑', 'Q' => '赒', 'R' => '赗', 'S' => '赟', 'T' => '赥', 'U' => '赨', 'V' => '赩', 'W' => '赪', 'X' => '赬', 'Y' => '赮', 'Z' => '赯', '[' => '赱', '\\' => '赲', ']' => '赸', '^' => '赹', '_' => '赺', '`' => '赻', 'a' => '赼', 'b' => '赽', 'c' => '赾', 'd' => '赿', 'e' => '趀', 'f' => '趂', 'g' => '趃', 'h' => '趆', 'i' => '趇', 'j' => '趈', 'k' => '趉', 'l' => '趌', 'm' => '趍', 'n' => '趎', 'o' => '趏', 'p' => '趐', 'q' => '趒', 'r' => '趓', 's' => '趕', 't' => '趖', 'u' => '趗', 'v' => '趘', 'w' => '趙', 'x' => '趚', 'y' => '趛', 'z' => '趜', '{' => '趝', '|' => '趞', '}' => '趠', '~' => '趡', 'ڀ' => '趢', 'ځ' => '趤', 'ڂ' => '趥', 'ڃ' => '趦', 'ڄ' => '趧', 'څ' => '趨', 'چ' => '趩', 'ڇ' => '趪', 'ڈ' => '趫', 'ډ' => '趬', 'ڊ' => '趭', 'ڋ' => '趮', 'ڌ' => '趯', 'ڍ' => '趰', 'ڎ' => '趲', 'ڏ' => '趶', 'ڐ' => '趷', 'ڑ' => '趹', 'ڒ' => '趻', 'ړ' => '趽', 'ڔ' => '跀', 'ڕ' => '跁', 'ږ' => '跂', 'ڗ' => '跅', 'ژ' => '跇', 'ڙ' => '跈', 'ښ' => '跉', 'ڛ' => '跊', 'ڜ' => '跍', 'ڝ' => '跐', 'ڞ' => '跒', 'ڟ' => '跓', 'ڠ' => '跔', 'ڡ' => '凇', 'ڢ' => '冖', 'ڣ' => '冢', 'ڤ' => '冥', 'ڥ' => '讠', 'ڦ' => '讦', 'ڧ' => '讧', 'ڨ' => '讪', 'ک' => '讴', 'ڪ' => '讵', 'ګ' => '讷', 'ڬ' => '诂', 'ڭ' => '诃', 'ڮ' => '诋', 'گ' => '诏', 'ڰ' => '诎', 'ڱ' => '诒', 'ڲ' => '诓', 'ڳ' => '诔', 'ڴ' => '诖', 'ڵ' => '诘', 'ڶ' => '诙', 'ڷ' => '诜', 'ڸ' => '诟', 'ڹ' => '诠', 'ں' => '诤', 'ڻ' => '诨', 'ڼ' => '诩', 'ڽ' => '诮', 'ھ' => '诰', 'ڿ' => '诳', '' => '诶', '' => '诹', '' => '诼', '' => '诿', '' => '谀', '' => '谂', '' => '谄', '' => '谇', '' => '谌', '' => '谏', '' => '谑', '' => '谒', '' => '谔', '' => '谕', '' => '谖', '' => '谙', '' => '谛', '' => '谘', '' => '谝', '' => '谟', '' => '谠', '' => '谡', '' => '谥', '' => '谧', '' => '谪', '' => '谫', '' => '谮', '' => '谯', '' => '谲', '' => '谳', '' => '谵', '' => '谶', '' => '卩', '' => '卺', '' => '阝', '' => '阢', '' => '阡', '' => '阱', '' => '阪', '' => '阽', '' => '阼', '' => '陂', '' => '陉', '' => '陔', '' => '陟', '' => '陧', '' => '陬', '' => '陲', '' => '陴', '' => '隈', '' => '隍', '' => '隗', '' => '隰', '' => '邗', '' => '邛', '' => '邝', '' => '邙', '' => '邬', '' => '邡', '' => '邴', '' => '邳', '' => '邶', '' => '邺', '@' => '跕', 'A' => '跘', 'B' => '跙', 'C' => '跜', 'D' => '跠', 'E' => '跡', 'F' => '跢', 'G' => '跥', 'H' => '跦', 'I' => '跧', 'J' => '跩', 'K' => '跭', 'L' => '跮', 'M' => '跰', 'N' => '跱', 'O' => '跲', 'P' => '跴', 'Q' => '跶', 'R' => '跼', 'S' => '跾', 'T' => '跿', 'U' => '踀', 'V' => '踁', 'W' => '踂', 'X' => '踃', 'Y' => '踄', 'Z' => '踆', '[' => '踇', '\\' => '踈', ']' => '踋', '^' => '踍', '_' => '踎', '`' => '踐', 'a' => '踑', 'b' => '踒', 'c' => '踓', 'd' => '踕', 'e' => '踖', 'f' => '踗', 'g' => '踘', 'h' => '踙', 'i' => '踚', 'j' => '踛', 'k' => '踜', 'l' => '踠', 'm' => '踡', 'n' => '踤', 'o' => '踥', 'p' => '踦', 'q' => '踧', 'r' => '踨', 's' => '踫', 't' => '踭', 'u' => '踰', 'v' => '踲', 'w' => '踳', 'x' => '踴', 'y' => '踶', 'z' => '踷', '{' => '踸', '|' => '踻', '}' => '踼', '~' => '踾', 'ۀ' => '踿', 'ہ' => '蹃', 'ۂ' => '蹅', 'ۃ' => '蹆', 'ۄ' => '蹌', 'ۅ' => '蹍', 'ۆ' => '蹎', 'ۇ' => '蹏', 'ۈ' => '蹐', 'ۉ' => '蹓', 'ۊ' => '蹔', 'ۋ' => '蹕', 'ی' => '蹖', 'ۍ' => '蹗', 'ێ' => '蹘', 'ۏ' => '蹚', 'ې' => '蹛', 'ۑ' => '蹜', 'ے' => '蹝', 'ۓ' => '蹞', '۔' => '蹟', 'ە' => '蹠', 'ۖ' => '蹡', 'ۗ' => '蹢', 'ۘ' => '蹣', 'ۙ' => '蹤', 'ۚ' => '蹥', 'ۛ' => '蹧', 'ۜ' => '蹨', '۝' => '蹪', '۞' => '蹫', '۟' => '蹮', '۠' => '蹱', 'ۡ' => '邸', 'ۢ' => '邰', 'ۣ' => '郏', 'ۤ' => '郅', 'ۥ' => '邾', 'ۦ' => '郐', 'ۧ' => '郄', 'ۨ' => '郇', '۩' => '郓', '۪' => '郦', '۫' => '郢', '۬' => '郜', 'ۭ' => '郗', 'ۮ' => '郛', 'ۯ' => '郫', '۰' => '郯', '۱' => '郾', '۲' => '鄄', '۳' => '鄢', '۴' => '鄞', '۵' => '鄣', '۶' => '鄱', '۷' => '鄯', '۸' => '鄹', '۹' => '酃', 'ۺ' => '酆', 'ۻ' => '刍', 'ۼ' => '奂', '۽' => '劢', '۾' => '劬', 'ۿ' => '劭', '' => '劾', '' => '哿', '' => '勐', '' => '勖', '' => '勰', '' => '叟', '' => '燮', '' => '矍', '' => '廴', '' => '凵', '' => '凼', '' => '鬯', '' => '厶', '' => '弁', '' => '畚', '' => '巯', '' => '坌', '' => '垩', '' => '垡', '' => '塾', '' => '墼', '' => '壅', '' => '壑', '' => '圩', '' => '圬', '' => '圪', '' => '圳', '' => '圹', '' => '圮', '' => '圯', '' => '坜', '' => '圻', '' => '坂', '' => '坩', '' => '垅', '' => '坫', '' => '垆', '' => '坼', '' => '坻', '' => '坨', '' => '坭', '' => '坶', '' => '坳', '' => '垭', '' => '垤', '' => '垌', '' => '垲', '' => '埏', '' => '垧', '' => '垴', '' => '垓', '' => '垠', '' => '埕', '' => '埘', '' => '埚', '' => '埙', '' => '埒', '' => '垸', '' => '埴', '' => '埯', '' => '埸', '' => '埤', '' => '埝', '@' => '蹳', 'A' => '蹵', 'B' => '蹷', 'C' => '蹸', 'D' => '蹹', 'E' => '蹺', 'F' => '蹻', 'G' => '蹽', 'H' => '蹾', 'I' => '躀', 'J' => '躂', 'K' => '躃', 'L' => '躄', 'M' => '躆', 'N' => '躈', 'O' => '躉', 'P' => '躊', 'Q' => '躋', 'R' => '躌', 'S' => '躍', 'T' => '躎', 'U' => '躑', 'V' => '躒', 'W' => '躓', 'X' => '躕', 'Y' => '躖', 'Z' => '躗', '[' => '躘', '\\' => '躙', ']' => '躚', '^' => '躛', '_' => '躝', '`' => '躟', 'a' => '躠', 'b' => '躡', 'c' => '躢', 'd' => '躣', 'e' => '躤', 'f' => '躥', 'g' => '躦', 'h' => '躧', 'i' => '躨', 'j' => '躩', 'k' => '躪', 'l' => '躭', 'm' => '躮', 'n' => '躰', 'o' => '躱', 'p' => '躳', 'q' => '躴', 'r' => '躵', 's' => '躶', 't' => '躷', 'u' => '躸', 'v' => '躹', 'w' => '躻', 'x' => '躼', 'y' => '躽', 'z' => '躾', '{' => '躿', '|' => '軀', '}' => '軁', '~' => '軂', '܀' => '軃', '܁' => '軄', '܂' => '軅', '܃' => '軆', '܄' => '軇', '܅' => '軈', '܆' => '軉', '܇' => '車', '܈' => '軋', '܉' => '軌', '܊' => '軍', '܋' => '軏', '܌' => '軐', '܍' => '軑', '܎' => '軒', '܏' => '軓', 'ܐ' => '軔', 'ܑ' => '軕', 'ܒ' => '軖', 'ܓ' => '軗', 'ܔ' => '軘', 'ܕ' => '軙', 'ܖ' => '軚', 'ܗ' => '軛', 'ܘ' => '軜', 'ܙ' => '軝', 'ܚ' => '軞', 'ܛ' => '軟', 'ܜ' => '軠', 'ܝ' => '軡', 'ܞ' => '転', 'ܟ' => '軣', 'ܠ' => '軤', 'ܡ' => '堋', 'ܢ' => '堍', 'ܣ' => '埽', 'ܤ' => '埭', 'ܥ' => '堀', 'ܦ' => '堞', 'ܧ' => '堙', 'ܨ' => '塄', 'ܩ' => '堠', 'ܪ' => '塥', 'ܫ' => '塬', 'ܬ' => '墁', 'ܭ' => '墉', 'ܮ' => '墚', 'ܯ' => '墀', 'ܰ' => '馨', 'ܱ' => '鼙', 'ܲ' => '懿', 'ܳ' => '艹', 'ܴ' => '艽', 'ܵ' => '艿', 'ܶ' => '芏', 'ܷ' => '芊', 'ܸ' => '芨', 'ܹ' => '芄', 'ܺ' => '芎', 'ܻ' => '芑', 'ܼ' => '芗', 'ܽ' => '芙', 'ܾ' => '芫', 'ܿ' => '芸', '' => '芾', '' => '芰', '' => '苈', '' => '苊', '' => '苣', '' => '芘', '' => '芷', '' => '芮', '' => '苋', '' => '苌', '' => '苁', '' => '芩', '' => '芴', '' => '芡', '' => '芪', '' => '芟', '' => '苄', '' => '苎', '' => '芤', '' => '苡', '' => '茉', '' => '苷', '' => '苤', '' => '茏', '' => '茇', '' => '苜', '' => '苴', '' => '苒', '' => '苘', '' => '茌', '' => '苻', '' => '苓', '' => '茑', '' => '茚', '' => '茆', '' => '茔', '' => '茕', '' => '苠', '' => '苕', '' => '茜', '' => '荑', '' => '荛', '' => '荜', '' => '茈', '' => '莒', '' => '茼', '' => '茴', '' => '茱', '' => '莛', '' => '荞', '' => '茯', '' => '荏', '' => '荇', '' => '荃', '' => '荟', '' => '荀', '' => '茗', '' => '荠', '' => '茭', '' => '茺', '' => '茳', '' => '荦', '' => '荥', '@' => '軥', 'A' => '軦', 'B' => '軧', 'C' => '軨', 'D' => '軩', 'E' => '軪', 'F' => '軫', 'G' => '軬', 'H' => '軭', 'I' => '軮', 'J' => '軯', 'K' => '軰', 'L' => '軱', 'M' => '軲', 'N' => '軳', 'O' => '軴', 'P' => '軵', 'Q' => '軶', 'R' => '軷', 'S' => '軸', 'T' => '軹', 'U' => '軺', 'V' => '軻', 'W' => '軼', 'X' => '軽', 'Y' => '軾', 'Z' => '軿', '[' => '輀', '\\' => '輁', ']' => '輂', '^' => '較', '_' => '輄', '`' => '輅', 'a' => '輆', 'b' => '輇', 'c' => '輈', 'd' => '載', 'e' => '輊', 'f' => '輋', 'g' => '輌', 'h' => '輍', 'i' => '輎', 'j' => '輏', 'k' => '輐', 'l' => '輑', 'm' => '輒', 'n' => '輓', 'o' => '輔', 'p' => '輕', 'q' => '輖', 'r' => '輗', 's' => '輘', 't' => '輙', 'u' => '輚', 'v' => '輛', 'w' => '輜', 'x' => '輝', 'y' => '輞', 'z' => '輟', '{' => '輠', '|' => '輡', '}' => '輢', '~' => '輣', '݀' => '輤', '݁' => '輥', '݂' => '輦', '݃' => '輧', '݄' => '輨', '݅' => '輩', '݆' => '輪', '݇' => '輫', '݈' => '輬', '݉' => '輭', '݊' => '輮', '݋' => '輯', '݌' => '輰', 'ݍ' => '輱', 'ݎ' => '輲', 'ݏ' => '輳', 'ݐ' => '輴', 'ݑ' => '輵', 'ݒ' => '輶', 'ݓ' => '輷', 'ݔ' => '輸', 'ݕ' => '輹', 'ݖ' => '輺', 'ݗ' => '輻', 'ݘ' => '輼', 'ݙ' => '輽', 'ݚ' => '輾', 'ݛ' => '輿', 'ݜ' => '轀', 'ݝ' => '轁', 'ݞ' => '轂', 'ݟ' => '轃', 'ݠ' => '轄', 'ݡ' => '荨', 'ݢ' => '茛', 'ݣ' => '荩', 'ݤ' => '荬', 'ݥ' => '荪', 'ݦ' => '荭', 'ݧ' => '荮', 'ݨ' => '莰', 'ݩ' => '荸', 'ݪ' => '莳', 'ݫ' => '莴', 'ݬ' => '莠', 'ݭ' => '莪', 'ݮ' => '莓', 'ݯ' => '莜', 'ݰ' => '莅', 'ݱ' => '荼', 'ݲ' => '莶', 'ݳ' => '莩', 'ݴ' => '荽', 'ݵ' => '莸', 'ݶ' => '荻', 'ݷ' => '莘', 'ݸ' => '莞', 'ݹ' => '莨', 'ݺ' => '莺', 'ݻ' => '莼', 'ݼ' => '菁', 'ݽ' => '萁', 'ݾ' => '菥', 'ݿ' => '菘', '' => '堇', '' => '萘', '' => '萋', '' => '菝', '' => '菽', '' => '菖', '' => '萜', '' => '萸', '' => '萑', '' => '萆', '' => '菔', '' => '菟', '' => '萏', '' => '萃', '' => '菸', '' => '菹', '' => '菪', '' => '菅', '' => '菀', '' => '萦', '' => '菰', '' => '菡', '' => '葜', '' => '葑', '' => '葚', '' => '葙', '' => '葳', '' => '蒇', '' => '蒈', '' => '葺', '' => '蒉', '' => '葸', '' => '萼', '' => '葆', '' => '葩', '' => '葶', '' => '蒌', '' => '蒎', '' => '萱', '' => '葭', '' => '蓁', '' => '蓍', '' => '蓐', '' => '蓦', '' => '蒽', '' => '蓓', '' => '蓊', '' => '蒿', '' => '蒺', '' => '蓠', '' => '蒡', '' => '蒹', '' => '蒴', '' => '蒗', '' => '蓥', '' => '蓣', '' => '蔌', '' => '甍', '' => '蔸', '' => '蓰', '' => '蔹', '' => '蔟', '' => '蔺', '@' => '轅', 'A' => '轆', 'B' => '轇', 'C' => '轈', 'D' => '轉', 'E' => '轊', 'F' => '轋', 'G' => '轌', 'H' => '轍', 'I' => '轎', 'J' => '轏', 'K' => '轐', 'L' => '轑', 'M' => '轒', 'N' => '轓', 'O' => '轔', 'P' => '轕', 'Q' => '轖', 'R' => '轗', 'S' => '轘', 'T' => '轙', 'U' => '轚', 'V' => '轛', 'W' => '轜', 'X' => '轝', 'Y' => '轞', 'Z' => '轟', '[' => '轠', '\\' => '轡', ']' => '轢', '^' => '轣', '_' => '轤', '`' => '轥', 'a' => '轪', 'b' => '辀', 'c' => '辌', 'd' => '辒', 'e' => '辝', 'f' => '辠', 'g' => '辡', 'h' => '辢', 'i' => '辤', 'j' => '辥', 'k' => '辦', 'l' => '辧', 'm' => '辪', 'n' => '辬', 'o' => '辭', 'p' => '辮', 'q' => '辯', 'r' => '農', 's' => '辳', 't' => '辴', 'u' => '辵', 'v' => '辷', 'w' => '辸', 'x' => '辺', 'y' => '辻', 'z' => '込', '{' => '辿', '|' => '迀', '}' => '迃', '~' => '迆', 'ހ' => '迉', 'ށ' => '迊', 'ނ' => '迋', 'ރ' => '迌', 'ބ' => '迍', 'ޅ' => '迏', 'ކ' => '迒', 'އ' => '迖', 'ވ' => '迗', 'މ' => '迚', 'ފ' => '迠', 'ދ' => '迡', 'ތ' => '迣', 'ލ' => '迧', 'ގ' => '迬', 'ޏ' => '迯', 'ސ' => '迱', 'ޑ' => '迲', 'ޒ' => '迴', 'ޓ' => '迵', 'ޔ' => '迶', 'ޕ' => '迺', 'ޖ' => '迻', 'ޗ' => '迼', 'ޘ' => '迾', 'ޙ' => '迿', 'ޚ' => '逇', 'ޛ' => '逈', 'ޜ' => '逌', 'ޝ' => '逎', 'ޞ' => '逓', 'ޟ' => '逕', 'ޠ' => '逘', 'ޡ' => '蕖', 'ޢ' => '蔻', 'ޣ' => '蓿', 'ޤ' => '蓼', 'ޥ' => '蕙', 'ަ' => '蕈', 'ާ' => '蕨', 'ި' => '蕤', 'ީ' => '蕞', 'ު' => '蕺', 'ޫ' => '瞢', 'ެ' => '蕃', 'ޭ' => '蕲', 'ޮ' => '蕻', 'ޯ' => '薤', 'ް' => '薨', 'ޱ' => '薇', '޲' => '薏', '޳' => '蕹', '޴' => '薮', '޵' => '薜', '޶' => '薅', '޷' => '薹', '޸' => '薷', '޹' => '薰', '޺' => '藓', '޻' => '藁', '޼' => '藜', '޽' => '藿', '޾' => '蘧', '޿' => '蘅', '' => '蘩', '' => '蘖', '' => '蘼', '' => '廾', '' => '弈', '' => '夼', '' => '奁', '' => '耷', '' => '奕', '' => '奚', '' => '奘', '' => '匏', '' => '尢', '' => '尥', '' => '尬', '' => '尴', '' => '扌', '' => '扪', '' => '抟', '' => '抻', '' => '拊', '' => '拚', '' => '拗', '' => '拮', '' => '挢', '' => '拶', '' => '挹', '' => '捋', '' => '捃', '' => '掭', '' => '揶', '' => '捱', '' => '捺', '' => '掎', '' => '掴', '' => '捭', '' => '掬', '' => '掊', '' => '捩', '' => '掮', '' => '掼', '' => '揲', '' => '揸', '' => '揠', '' => '揿', '' => '揄', '' => '揞', '' => '揎', '' => '摒', '' => '揆', '' => '掾', '' => '摅', '' => '摁', '' => '搋', '' => '搛', '' => '搠', '' => '搌', '' => '搦', '' => '搡', '' => '摞', '' => '撄', '' => '摭', '' => '撖', '@' => '這', 'A' => '逜', 'B' => '連', 'C' => '逤', 'D' => '逥', 'E' => '逧', 'F' => '逨', 'G' => '逩', 'H' => '逪', 'I' => '逫', 'J' => '逬', 'K' => '逰', 'L' => '週', 'M' => '進', 'N' => '逳', 'O' => '逴', 'P' => '逷', 'Q' => '逹', 'R' => '逺', 'S' => '逽', 'T' => '逿', 'U' => '遀', 'V' => '遃', 'W' => '遅', 'X' => '遆', 'Y' => '遈', 'Z' => '遉', '[' => '遊', '\\' => '運', ']' => '遌', '^' => '過', '_' => '達', '`' => '違', 'a' => '遖', 'b' => '遙', 'c' => '遚', 'd' => '遜', 'e' => '遝', 'f' => '遞', 'g' => '遟', 'h' => '遠', 'i' => '遡', 'j' => '遤', 'k' => '遦', 'l' => '遧', 'm' => '適', 'n' => '遪', 'o' => '遫', 'p' => '遬', 'q' => '遯', 'r' => '遰', 's' => '遱', 't' => '遲', 'u' => '遳', 'v' => '遶', 'w' => '遷', 'x' => '選', 'y' => '遹', 'z' => '遺', '{' => '遻', '|' => '遼', '}' => '遾', '~' => '邁', '߀' => '還', '߁' => '邅', '߂' => '邆', '߃' => '邇', '߄' => '邉', '߅' => '邊', '߆' => '邌', '߇' => '邍', '߈' => '邎', '߉' => '邏', 'ߊ' => '邐', 'ߋ' => '邒', 'ߌ' => '邔', 'ߍ' => '邖', 'ߎ' => '邘', 'ߏ' => '邚', 'ߐ' => '邜', 'ߑ' => '邞', 'ߒ' => '邟', 'ߓ' => '邠', 'ߔ' => '邤', 'ߕ' => '邥', 'ߖ' => '邧', 'ߗ' => '邨', 'ߘ' => '邩', 'ߙ' => '邫', 'ߚ' => '邭', 'ߛ' => '邲', 'ߜ' => '邷', 'ߝ' => '邼', 'ߞ' => '邽', 'ߟ' => '邿', 'ߠ' => '郀', 'ߡ' => '摺', 'ߢ' => '撷', 'ߣ' => '撸', 'ߤ' => '撙', 'ߥ' => '撺', 'ߦ' => '擀', 'ߧ' => '擐', 'ߨ' => '擗', 'ߩ' => '擤', 'ߪ' => '擢', '߫' => '攉', '߬' => '攥', '߭' => '攮', '߮' => '弋', '߯' => '忒', '߰' => '甙', '߱' => '弑', '߲' => '卟', '߳' => '叱', 'ߴ' => '叽', 'ߵ' => '叩', '߶' => '叨', '߷' => '叻', '߸' => '吒', '߹' => '吖', 'ߺ' => '吆', '߻' => '呋', '߼' => '呒', '߽' => '呓', '߾' => '呔', '߿' => '呖', '' => '呃', '' => '吡', '' => '呗', '' => '呙', '' => '吣', '' => '吲', '' => '咂', '' => '咔', '' => '呷', '' => '呱', '' => '呤', '' => '咚', '' => '咛', '' => '咄', '' => '呶', '' => '呦', '' => '咝', '' => '哐', '' => '咭', '' => '哂', '' => '咴', '' => '哒', '' => '咧', '' => '咦', '' => '哓', '' => '哔', '' => '呲', '' => '咣', '' => '哕', '' => '咻', '' => '咿', '' => '哌', '' => '哙', '' => '哚', '' => '哜', '' => '咩', '' => '咪', '' => '咤', '' => '哝', '' => '哏', '' => '哞', '' => '唛', '' => '哧', '' => '唠', '' => '哽', '' => '唔', '' => '哳', '' => '唢', '' => '唣', '' => '唏', '' => '唑', '' => '唧', '' => '唪', '' => '啧', '' => '喏', '' => '喵', '' => '啉', '' => '啭', '' => '啁', '' => '啕', '' => '唿', '' => '啐', '' => '唼', '@' => '郂', 'A' => '郃', 'B' => '郆', 'C' => '郈', 'D' => '郉', 'E' => '郋', 'F' => '郌', 'G' => '郍', 'H' => '郒', 'I' => '郔', 'J' => '郕', 'K' => '郖', 'L' => '郘', 'M' => '郙', 'N' => '郚', 'O' => '郞', 'P' => '郟', 'Q' => '郠', 'R' => '郣', 'S' => '郤', 'T' => '郥', 'U' => '郩', 'V' => '郪', 'W' => '郬', 'X' => '郮', 'Y' => '郰', 'Z' => '郱', '[' => '郲', '\\' => '郳', ']' => '郵', '^' => '郶', '_' => '郷', '`' => '郹', 'a' => '郺', 'b' => '郻', 'c' => '郼', 'd' => '郿', 'e' => '鄀', 'f' => '鄁', 'g' => '鄃', 'h' => '鄅', 'i' => '鄆', 'j' => '鄇', 'k' => '鄈', 'l' => '鄉', 'm' => '鄊', 'n' => '鄋', 'o' => '鄌', 'p' => '鄍', 'q' => '鄎', 'r' => '鄏', 's' => '鄐', 't' => '鄑', 'u' => '鄒', 'v' => '鄓', 'w' => '鄔', 'x' => '鄕', 'y' => '鄖', 'z' => '鄗', '{' => '鄘', '|' => '鄚', '}' => '鄛', '~' => '鄜', '' => '鄝', '' => '鄟', '' => '鄠', '' => '鄡', '' => '鄤', '' => '鄥', '' => '鄦', '' => '鄧', '' => '鄨', '' => '鄩', '' => '鄪', '' => '鄫', '' => '鄬', '' => '鄭', '' => '鄮', '' => '鄰', '' => '鄲', '' => '鄳', '' => '鄴', '' => '鄵', '' => '鄶', '' => '鄷', '' => '鄸', '' => '鄺', '' => '鄻', '' => '鄼', '' => '鄽', '' => '鄾', '' => '鄿', '' => '酀', '' => '酁', '' => '酂', '' => '酄', '' => '唷', '' => '啖', '' => '啵', '' => '啶', '' => '啷', '' => '唳', '' => '唰', '' => '啜', '' => '喋', '' => '嗒', '' => '喃', '' => '喱', '' => '喹', '' => '喈', '' => '喁', '' => '喟', '' => '啾', '' => '嗖', '' => '喑', '' => '啻', '' => '嗟', '' => '喽', '' => '喾', '' => '喔', '' => '喙', '' => '嗪', '' => '嗷', '' => '嗉', '' => '嘟', '' => '嗑', '' => '嗫', '' => '嗬', '' => '嗔', '' => '嗦', '' => '嗝', '' => '嗄', '' => '嗯', '' => '嗥', '' => '嗲', '' => '嗳', '' => '嗌', '' => '嗍', '' => '嗨', '' => '嗵', '' => '嗤', '' => '辔', '' => '嘞', '' => '嘈', '' => '嘌', '' => '嘁', '' => '嘤', '' => '嘣', '' => '嗾', '' => '嘀', '' => '嘧', '' => '嘭', '' => '噘', '' => '嘹', '' => '噗', '' => '嘬', '' => '噍', '' => '噢', '' => '噙', '' => '噜', '' => '噌', '' => '噔', '' => '嚆', '' => '噤', '' => '噱', '' => '噫', '' => '噻', '' => '噼', '' => '嚅', '' => '嚓', '' => '嚯', '' => '囔', '' => '囗', '' => '囝', '' => '囡', '' => '囵', '' => '囫', '' => '囹', '' => '囿', '' => '圄', '' => '圊', '' => '圉', '' => '圜', '' => '帏', '' => '帙', '' => '帔', '' => '帑', '' => '帱', '' => '帻', '' => '帼', '@' => '酅', 'A' => '酇', 'B' => '酈', 'C' => '酑', 'D' => '酓', 'E' => '酔', 'F' => '酕', 'G' => '酖', 'H' => '酘', 'I' => '酙', 'J' => '酛', 'K' => '酜', 'L' => '酟', 'M' => '酠', 'N' => '酦', 'O' => '酧', 'P' => '酨', 'Q' => '酫', 'R' => '酭', 'S' => '酳', 'T' => '酺', 'U' => '酻', 'V' => '酼', 'W' => '醀', 'X' => '醁', 'Y' => '醂', 'Z' => '醃', '[' => '醄', '\\' => '醆', ']' => '醈', '^' => '醊', '_' => '醎', '`' => '醏', 'a' => '醓', 'b' => '醔', 'c' => '醕', 'd' => '醖', 'e' => '醗', 'f' => '醘', 'g' => '醙', 'h' => '醜', 'i' => '醝', 'j' => '醞', 'k' => '醟', 'l' => '醠', 'm' => '醡', 'n' => '醤', 'o' => '醥', 'p' => '醦', 'q' => '醧', 'r' => '醨', 's' => '醩', 't' => '醫', 'u' => '醬', 'v' => '醰', 'w' => '醱', 'x' => '醲', 'y' => '醳', 'z' => '醶', '{' => '醷', '|' => '醸', '}' => '醹', '~' => '醻', '' => '醼', '' => '醽', '' => '醾', '' => '醿', '' => '釀', '' => '釁', '' => '釂', '' => '釃', '' => '釄', '' => '釅', '' => '釆', '' => '釈', '' => '釋', '' => '釐', '' => '釒', '' => '釓', '' => '釔', '' => '釕', '' => '釖', '' => '釗', '' => '釘', '' => '釙', '' => '釚', '' => '釛', '' => '針', '' => '釞', '' => '釟', '' => '釠', '' => '釡', '' => '釢', '' => '釣', '' => '釤', '' => '釥', '' => '帷', '' => '幄', '' => '幔', '' => '幛', '' => '幞', '' => '幡', '' => '岌', '' => '屺', '' => '岍', '' => '岐', '' => '岖', '' => '岈', '' => '岘', '' => '岙', '' => '岑', '' => '岚', '' => '岜', '' => '岵', '' => '岢', '' => '岽', '' => '岬', '' => '岫', '' => '岱', '' => '岣', '' => '峁', '' => '岷', '' => '峄', '' => '峒', '' => '峤', '' => '峋', '' => '峥', '' => '崂', '' => '崃', '' => '崧', '' => '崦', '' => '崮', '' => '崤', '' => '崞', '' => '崆', '' => '崛', '' => '嵘', '' => '崾', '' => '崴', '' => '崽', '' => '嵬', '' => '嵛', '' => '嵯', '' => '嵝', '' => '嵫', '' => '嵋', '' => '嵊', '' => '嵩', '' => '嵴', '' => '嶂', '' => '嶙', '' => '嶝', '' => '豳', '' => '嶷', '' => '巅', '' => '彳', '' => '彷', '' => '徂', '' => '徇', '' => '徉', '' => '後', '' => '徕', '' => '徙', '' => '徜', '' => '徨', '' => '徭', '' => '徵', '' => '徼', '' => '衢', '' => '彡', '' => '犭', '' => '犰', '' => '犴', '' => '犷', '' => '犸', '' => '狃', '' => '狁', '' => '狎', '' => '狍', '' => '狒', '' => '狨', '' => '狯', '' => '狩', '' => '狲', '' => '狴', '' => '狷', '' => '猁', '' => '狳', '' => '猃', '' => '狺', '@' => '釦', 'A' => '釧', 'B' => '釨', 'C' => '釩', 'D' => '釪', 'E' => '釫', 'F' => '釬', 'G' => '釭', 'H' => '釮', 'I' => '釯', 'J' => '釰', 'K' => '釱', 'L' => '釲', 'M' => '釳', 'N' => '釴', 'O' => '釵', 'P' => '釶', 'Q' => '釷', 'R' => '釸', 'S' => '釹', 'T' => '釺', 'U' => '釻', 'V' => '釼', 'W' => '釽', 'X' => '釾', 'Y' => '釿', 'Z' => '鈀', '[' => '鈁', '\\' => '鈂', ']' => '鈃', '^' => '鈄', '_' => '鈅', '`' => '鈆', 'a' => '鈇', 'b' => '鈈', 'c' => '鈉', 'd' => '鈊', 'e' => '鈋', 'f' => '鈌', 'g' => '鈍', 'h' => '鈎', 'i' => '鈏', 'j' => '鈐', 'k' => '鈑', 'l' => '鈒', 'm' => '鈓', 'n' => '鈔', 'o' => '鈕', 'p' => '鈖', 'q' => '鈗', 'r' => '鈘', 's' => '鈙', 't' => '鈚', 'u' => '鈛', 'v' => '鈜', 'w' => '鈝', 'x' => '鈞', 'y' => '鈟', 'z' => '鈠', '{' => '鈡', '|' => '鈢', '}' => '鈣', '~' => '鈤', '' => '鈥', '' => '鈦', '' => '鈧', '' => '鈨', '' => '鈩', '' => '鈪', '' => '鈫', '' => '鈬', '' => '鈭', '' => '鈮', '' => '鈯', '' => '鈰', '' => '鈱', '' => '鈲', '' => '鈳', '' => '鈴', '' => '鈵', '' => '鈶', '' => '鈷', '' => '鈸', '' => '鈹', '' => '鈺', '' => '鈻', '' => '鈼', '' => '鈽', '' => '鈾', '' => '鈿', '' => '鉀', '' => '鉁', '' => '鉂', '' => '鉃', '' => '鉄', '' => '鉅', '' => '狻', '' => '猗', '' => '猓', '' => '猡', '' => '猊', '' => '猞', '' => '猝', '' => '猕', '' => '猢', '' => '猹', '' => '猥', '' => '猬', '' => '猸', '' => '猱', '' => '獐', '' => '獍', '' => '獗', '' => '獠', '' => '獬', '' => '獯', '' => '獾', '' => '舛', '' => '夥', '' => '飧', '' => '夤', '' => '夂', '' => '饣', '' => '饧', '' => '饨', '' => '饩', '' => '饪', '' => '饫', '' => '饬', '' => '饴', '' => '饷', '' => '饽', '' => '馀', '' => '馄', '' => '馇', '' => '馊', '' => '馍', '' => '馐', '' => '馑', '' => '馓', '' => '馔', '' => '馕', '' => '庀', '' => '庑', '' => '庋', '' => '庖', '' => '庥', '' => '庠', '' => '庹', '' => '庵', '' => '庾', '' => '庳', '' => '赓', '' => '廒', '' => '廑', '' => '廛', '' => '廨', '' => '廪', '' => '膺', '' => '忄', '' => '忉', '' => '忖', '' => '忏', '' => '怃', '' => '忮', '' => '怄', '' => '忡', '' => '忤', '' => '忾', '' => '怅', '' => '怆', '' => '忪', '' => '忭', '' => '忸', '' => '怙', '' => '怵', '' => '怦', '' => '怛', '' => '怏', '' => '怍', '' => '怩', '' => '怫', '' => '怊', '' => '怿', '' => '怡', '' => '恸', '' => '恹', '' => '恻', '' => '恺', '' => '恂', '@' => '鉆', 'A' => '鉇', 'B' => '鉈', 'C' => '鉉', 'D' => '鉊', 'E' => '鉋', 'F' => '鉌', 'G' => '鉍', 'H' => '鉎', 'I' => '鉏', 'J' => '鉐', 'K' => '鉑', 'L' => '鉒', 'M' => '鉓', 'N' => '鉔', 'O' => '鉕', 'P' => '鉖', 'Q' => '鉗', 'R' => '鉘', 'S' => '鉙', 'T' => '鉚', 'U' => '鉛', 'V' => '鉜', 'W' => '鉝', 'X' => '鉞', 'Y' => '鉟', 'Z' => '鉠', '[' => '鉡', '\\' => '鉢', ']' => '鉣', '^' => '鉤', '_' => '鉥', '`' => '鉦', 'a' => '鉧', 'b' => '鉨', 'c' => '鉩', 'd' => '鉪', 'e' => '鉫', 'f' => '鉬', 'g' => '鉭', 'h' => '鉮', 'i' => '鉯', 'j' => '鉰', 'k' => '鉱', 'l' => '鉲', 'm' => '鉳', 'n' => '鉵', 'o' => '鉶', 'p' => '鉷', 'q' => '鉸', 'r' => '鉹', 's' => '鉺', 't' => '鉻', 'u' => '鉼', 'v' => '鉽', 'w' => '鉾', 'x' => '鉿', 'y' => '銀', 'z' => '銁', '{' => '銂', '|' => '銃', '}' => '銄', '~' => '銅', '' => '銆', '' => '銇', '' => '銈', '' => '銉', '' => '銊', '' => '銋', '' => '銌', '' => '銍', '' => '銏', '' => '銐', '' => '銑', '' => '銒', '' => '銓', '' => '銔', '' => '銕', '' => '銖', '' => '銗', '' => '銘', '' => '銙', '' => '銚', '' => '銛', '' => '銜', '' => '銝', '' => '銞', '' => '銟', '' => '銠', '' => '銡', '' => '銢', '' => '銣', '' => '銤', '' => '銥', '' => '銦', '' => '銧', '' => '恪', '' => '恽', '' => '悖', '' => '悚', '' => '悭', '' => '悝', '' => '悃', '' => '悒', '' => '悌', '' => '悛', '' => '惬', '' => '悻', '' => '悱', '' => '惝', '' => '惘', '' => '惆', '' => '惚', '' => '悴', '' => '愠', '' => '愦', '' => '愕', '' => '愣', '' => '惴', '' => '愀', '' => '愎', '' => '愫', '' => '慊', '' => '慵', '' => '憬', '' => '憔', '' => '憧', '' => '憷', '' => '懔', '' => '懵', '' => '忝', '' => '隳', '' => '闩', '' => '闫', '' => '闱', '' => '闳', '' => '闵', '' => '闶', '' => '闼', '' => '闾', '' => '阃', '' => '阄', '' => '阆', '' => '阈', '' => '阊', '' => '阋', '' => '阌', '' => '阍', '' => '阏', '' => '阒', '' => '阕', '' => '阖', '' => '阗', '' => '阙', '' => '阚', '' => '丬', '' => '爿', '' => '戕', '' => '氵', '' => '汔', '' => '汜', '' => '汊', '' => '沣', '' => '沅', '' => '沐', '' => '沔', '' => '沌', '' => '汨', '' => '汩', '' => '汴', '' => '汶', '' => '沆', '' => '沩', '' => '泐', '' => '泔', '' => '沭', '' => '泷', '' => '泸', '' => '泱', '' => '泗', '' => '沲', '' => '泠', '' => '泖', '' => '泺', '' => '泫', '' => '泮', '' => '沱', '' => '泓', '' => '泯', '' => '泾', '@' => '銨', 'A' => '銩', 'B' => '銪', 'C' => '銫', 'D' => '銬', 'E' => '銭', 'F' => '銯', 'G' => '銰', 'H' => '銱', 'I' => '銲', 'J' => '銳', 'K' => '銴', 'L' => '銵', 'M' => '銶', 'N' => '銷', 'O' => '銸', 'P' => '銹', 'Q' => '銺', 'R' => '銻', 'S' => '銼', 'T' => '銽', 'U' => '銾', 'V' => '銿', 'W' => '鋀', 'X' => '鋁', 'Y' => '鋂', 'Z' => '鋃', '[' => '鋄', '\\' => '鋅', ']' => '鋆', '^' => '鋇', '_' => '鋉', '`' => '鋊', 'a' => '鋋', 'b' => '鋌', 'c' => '鋍', 'd' => '鋎', 'e' => '鋏', 'f' => '鋐', 'g' => '鋑', 'h' => '鋒', 'i' => '鋓', 'j' => '鋔', 'k' => '鋕', 'l' => '鋖', 'm' => '鋗', 'n' => '鋘', 'o' => '鋙', 'p' => '鋚', 'q' => '鋛', 'r' => '鋜', 's' => '鋝', 't' => '鋞', 'u' => '鋟', 'v' => '鋠', 'w' => '鋡', 'x' => '鋢', 'y' => '鋣', 'z' => '鋤', '{' => '鋥', '|' => '鋦', '}' => '鋧', '~' => '鋨', '' => '鋩', '' => '鋪', '' => '鋫', '' => '鋬', '' => '鋭', '' => '鋮', '' => '鋯', '' => '鋰', '' => '鋱', '' => '鋲', '' => '鋳', '' => '鋴', '' => '鋵', '' => '鋶', '' => '鋷', '' => '鋸', '' => '鋹', '' => '鋺', '' => '鋻', '' => '鋼', '' => '鋽', '' => '鋾', '' => '鋿', '' => '錀', '' => '錁', '' => '錂', '' => '錃', '' => '錄', '' => '錅', '' => '錆', '' => '錇', '' => '錈', '' => '錉', '' => '洹', '' => '洧', '' => '洌', '' => '浃', '' => '浈', '' => '洇', '' => '洄', '' => '洙', '' => '洎', '' => '洫', '' => '浍', '' => '洮', '' => '洵', '' => '洚', '' => '浏', '' => '浒', '' => '浔', '' => '洳', '' => '涑', '' => '浯', '' => '涞', '' => '涠', '' => '浞', '' => '涓', '' => '涔', '' => '浜', '' => '浠', '' => '浼', '' => '浣', '' => '渚', '' => '淇', '' => '淅', '' => '淞', '' => '渎', '' => '涿', '' => '淠', '' => '渑', '' => '淦', '' => '淝', '' => '淙', '' => '渖', '' => '涫', '' => '渌', '' => '涮', '' => '渫', '' => '湮', '' => '湎', '' => '湫', '' => '溲', '' => '湟', '' => '溆', '' => '湓', '' => '湔', '' => '渲', '' => '渥', '' => '湄', '' => '滟', '' => '溱', '' => '溘', '' => '滠', '' => '漭', '' => '滢', '' => '溥', '' => '溧', '' => '溽', '' => '溻', '' => '溷', '' => '滗', '' => '溴', '' => '滏', '' => '溏', '' => '滂', '' => '溟', '' => '潢', '' => '潆', '' => '潇', '' => '漤', '' => '漕', '' => '滹', '' => '漯', '' => '漶', '' => '潋', '' => '潴', '' => '漪', '' => '漉', '' => '漩', '' => '澉', '' => '澍', '' => '澌', '' => '潸', '' => '潲', '' => '潼', '' => '潺', '' => '濑', '@' => '錊', 'A' => '錋', 'B' => '錌', 'C' => '錍', 'D' => '錎', 'E' => '錏', 'F' => '錐', 'G' => '錑', 'H' => '錒', 'I' => '錓', 'J' => '錔', 'K' => '錕', 'L' => '錖', 'M' => '錗', 'N' => '錘', 'O' => '錙', 'P' => '錚', 'Q' => '錛', 'R' => '錜', 'S' => '錝', 'T' => '錞', 'U' => '錟', 'V' => '錠', 'W' => '錡', 'X' => '錢', 'Y' => '錣', 'Z' => '錤', '[' => '錥', '\\' => '錦', ']' => '錧', '^' => '錨', '_' => '錩', '`' => '錪', 'a' => '錫', 'b' => '錬', 'c' => '錭', 'd' => '錮', 'e' => '錯', 'f' => '錰', 'g' => '錱', 'h' => '録', 'i' => '錳', 'j' => '錴', 'k' => '錵', 'l' => '錶', 'm' => '錷', 'n' => '錸', 'o' => '錹', 'p' => '錺', 'q' => '錻', 'r' => '錼', 's' => '錽', 't' => '錿', 'u' => '鍀', 'v' => '鍁', 'w' => '鍂', 'x' => '鍃', 'y' => '鍄', 'z' => '鍅', '{' => '鍆', '|' => '鍇', '}' => '鍈', '~' => '鍉', '' => '鍊', '' => '鍋', '' => '鍌', '' => '鍍', '' => '鍎', '' => '鍏', '' => '鍐', '' => '鍑', '' => '鍒', '' => '鍓', '' => '鍔', '' => '鍕', '' => '鍖', '' => '鍗', '' => '鍘', '' => '鍙', '' => '鍚', '' => '鍛', '' => '鍜', '' => '鍝', '' => '鍞', '' => '鍟', '' => '鍠', '' => '鍡', '' => '鍢', '' => '鍣', '' => '鍤', '' => '鍥', '' => '鍦', '' => '鍧', '' => '鍨', '' => '鍩', '' => '鍫', '' => '濉', '' => '澧', '' => '澹', '' => '澶', '' => '濂', '' => '濡', '' => '濮', '' => '濞', '' => '濠', '' => '濯', '' => '瀚', '' => '瀣', '' => '瀛', '' => '瀹', '' => '瀵', '' => '灏', '' => '灞', '' => '宀', '' => '宄', '' => '宕', '' => '宓', '' => '宥', '' => '宸', '' => '甯', '' => '骞', '' => '搴', '' => '寤', '' => '寮', '' => '褰', '' => '寰', '' => '蹇', '' => '謇', '' => '辶', '' => '迓', '' => '迕', '' => '迥', '' => '迮', '' => '迤', '' => '迩', '' => '迦', '' => '迳', '' => '迨', '' => '逅', '' => '逄', '' => '逋', '' => '逦', '' => '逑', '' => '逍', '' => '逖', '' => '逡', '' => '逵', '' => '逶', '' => '逭', '' => '逯', '' => '遄', '' => '遑', '' => '遒', '' => '遐', '' => '遨', '' => '遘', '' => '遢', '' => '遛', '' => '暹', '' => '遴', '' => '遽', '' => '邂', '' => '邈', '' => '邃', '' => '邋', '' => '彐', '' => '彗', '' => '彖', '' => '彘', '' => '尻', '' => '咫', '' => '屐', '' => '屙', '' => '孱', '' => '屣', '' => '屦', '' => '羼', '' => '弪', '' => '弩', '' => '弭', '' => '艴', '' => '弼', '' => '鬻', '' => '屮', '' => '妁', '' => '妃', '' => '妍', '' => '妩', '' => '妪', '' => '妣', '@' => '鍬', 'A' => '鍭', 'B' => '鍮', 'C' => '鍯', 'D' => '鍰', 'E' => '鍱', 'F' => '鍲', 'G' => '鍳', 'H' => '鍴', 'I' => '鍵', 'J' => '鍶', 'K' => '鍷', 'L' => '鍸', 'M' => '鍹', 'N' => '鍺', 'O' => '鍻', 'P' => '鍼', 'Q' => '鍽', 'R' => '鍾', 'S' => '鍿', 'T' => '鎀', 'U' => '鎁', 'V' => '鎂', 'W' => '鎃', 'X' => '鎄', 'Y' => '鎅', 'Z' => '鎆', '[' => '鎇', '\\' => '鎈', ']' => '鎉', '^' => '鎊', '_' => '鎋', '`' => '鎌', 'a' => '鎍', 'b' => '鎎', 'c' => '鎐', 'd' => '鎑', 'e' => '鎒', 'f' => '鎓', 'g' => '鎔', 'h' => '鎕', 'i' => '鎖', 'j' => '鎗', 'k' => '鎘', 'l' => '鎙', 'm' => '鎚', 'n' => '鎛', 'o' => '鎜', 'p' => '鎝', 'q' => '鎞', 'r' => '鎟', 's' => '鎠', 't' => '鎡', 'u' => '鎢', 'v' => '鎣', 'w' => '鎤', 'x' => '鎥', 'y' => '鎦', 'z' => '鎧', '{' => '鎨', '|' => '鎩', '}' => '鎪', '~' => '鎫', '' => '鎬', '' => '鎭', '' => '鎮', '' => '鎯', '' => '鎰', '' => '鎱', '' => '鎲', '' => '鎳', '' => '鎴', '' => '鎵', '' => '鎶', '' => '鎷', '' => '鎸', '' => '鎹', '' => '鎺', '' => '鎻', '' => '鎼', '' => '鎽', '' => '鎾', '' => '鎿', '' => '鏀', '' => '鏁', '' => '鏂', '' => '鏃', '' => '鏄', '' => '鏅', '' => '鏆', '' => '鏇', '' => '鏈', '' => '鏉', '' => '鏋', '' => '鏌', '' => '鏍', '' => '妗', '' => '姊', '' => '妫', '' => '妞', '' => '妤', '' => '姒', '' => '妲', '' => '妯', '' => '姗', '' => '妾', '' => '娅', '' => '娆', '' => '姝', '' => '娈', '' => '姣', '' => '姘', '' => '姹', '' => '娌', '' => '娉', '' => '娲', '' => '娴', '' => '娑', '' => '娣', '' => '娓', '' => '婀', '' => '婧', '' => '婊', '' => '婕', '' => '娼', '' => '婢', '' => '婵', '' => '胬', '' => '媪', '' => '媛', '' => '婷', '' => '婺', '' => '媾', '' => '嫫', '' => '媲', '' => '嫒', '' => '嫔', '' => '媸', '' => '嫠', '' => '嫣', '' => '嫱', '' => '嫖', '' => '嫦', '' => '嫘', '' => '嫜', '' => '嬉', '' => '嬗', '' => '嬖', '' => '嬲', '' => '嬷', '' => '孀', '' => '尕', '' => '尜', '' => '孚', '' => '孥', '' => '孳', '' => '孑', '' => '孓', '' => '孢', '' => '驵', '' => '驷', '' => '驸', '' => '驺', '' => '驿', '' => '驽', '' => '骀', '' => '骁', '' => '骅', '' => '骈', '' => '骊', '' => '骐', '' => '骒', '' => '骓', '' => '骖', '' => '骘', '' => '骛', '' => '骜', '' => '骝', '' => '骟', '' => '骠', '' => '骢', '' => '骣', '' => '骥', '' => '骧', '' => '纟', '' => '纡', '' => '纣', '' => '纥', '' => '纨', '' => '纩', '@' => '鏎', 'A' => '鏏', 'B' => '鏐', 'C' => '鏑', 'D' => '鏒', 'E' => '鏓', 'F' => '鏔', 'G' => '鏕', 'H' => '鏗', 'I' => '鏘', 'J' => '鏙', 'K' => '鏚', 'L' => '鏛', 'M' => '鏜', 'N' => '鏝', 'O' => '鏞', 'P' => '鏟', 'Q' => '鏠', 'R' => '鏡', 'S' => '鏢', 'T' => '鏣', 'U' => '鏤', 'V' => '鏥', 'W' => '鏦', 'X' => '鏧', 'Y' => '鏨', 'Z' => '鏩', '[' => '鏪', '\\' => '鏫', ']' => '鏬', '^' => '鏭', '_' => '鏮', '`' => '鏯', 'a' => '鏰', 'b' => '鏱', 'c' => '鏲', 'd' => '鏳', 'e' => '鏴', 'f' => '鏵', 'g' => '鏶', 'h' => '鏷', 'i' => '鏸', 'j' => '鏹', 'k' => '鏺', 'l' => '鏻', 'm' => '鏼', 'n' => '鏽', 'o' => '鏾', 'p' => '鏿', 'q' => '鐀', 'r' => '鐁', 's' => '鐂', 't' => '鐃', 'u' => '鐄', 'v' => '鐅', 'w' => '鐆', 'x' => '鐇', 'y' => '鐈', 'z' => '鐉', '{' => '鐊', '|' => '鐋', '}' => '鐌', '~' => '鐍', '' => '鐎', '' => '鐏', '' => '鐐', '' => '鐑', '' => '鐒', '' => '鐓', '' => '鐔', '' => '鐕', '' => '鐖', '' => '鐗', '' => '鐘', '' => '鐙', '' => '鐚', '' => '鐛', '' => '鐜', '' => '鐝', '' => '鐞', '' => '鐟', '' => '鐠', '' => '鐡', '' => '鐢', '' => '鐣', '' => '鐤', '' => '鐥', '' => '鐦', '' => '鐧', '' => '鐨', '' => '鐩', '' => '鐪', '' => '鐫', '' => '鐬', '' => '鐭', '' => '鐮', '' => '纭', '' => '纰', '' => '纾', '' => '绀', '' => '绁', '' => '绂', '' => '绉', '' => '绋', '' => '绌', '' => '绐', '' => '绔', '' => '绗', '' => '绛', '' => '绠', '' => '绡', '' => '绨', '' => '绫', '' => '绮', '' => '绯', '' => '绱', '' => '绲', '' => '缍', '' => '绶', '' => '绺', '' => '绻', '' => '绾', '' => '缁', '' => '缂', '' => '缃', '' => '缇', '' => '缈', '' => '缋', '' => '缌', '' => '缏', '' => '缑', '' => '缒', '' => '缗', '' => '缙', '' => '缜', '' => '缛', '' => '缟', '' => '缡', '' => '缢', '' => '缣', '' => '缤', '' => '缥', '' => '缦', '' => '缧', '' => '缪', '' => '缫', '' => '缬', '' => '缭', '' => '缯', '' => '缰', '' => '缱', '' => '缲', '' => '缳', '' => '缵', '' => '幺', '' => '畿', '' => '巛', '' => '甾', '' => '邕', '' => '玎', '' => '玑', '' => '玮', '' => '玢', '' => '玟', '' => '珏', '' => '珂', '' => '珑', '' => '玷', '' => '玳', '' => '珀', '' => '珉', '' => '珈', '' => '珥', '' => '珙', '' => '顼', '' => '琊', '' => '珩', '' => '珧', '' => '珞', '' => '玺', '' => '珲', '' => '琏', '' => '琪', '' => '瑛', '' => '琦', '' => '琥', '' => '琨', '' => '琰', '' => '琮', '' => '琬', '@' => '鐯', 'A' => '鐰', 'B' => '鐱', 'C' => '鐲', 'D' => '鐳', 'E' => '鐴', 'F' => '鐵', 'G' => '鐶', 'H' => '鐷', 'I' => '鐸', 'J' => '鐹', 'K' => '鐺', 'L' => '鐻', 'M' => '鐼', 'N' => '鐽', 'O' => '鐿', 'P' => '鑀', 'Q' => '鑁', 'R' => '鑂', 'S' => '鑃', 'T' => '鑄', 'U' => '鑅', 'V' => '鑆', 'W' => '鑇', 'X' => '鑈', 'Y' => '鑉', 'Z' => '鑊', '[' => '鑋', '\\' => '鑌', ']' => '鑍', '^' => '鑎', '_' => '鑏', '`' => '鑐', 'a' => '鑑', 'b' => '鑒', 'c' => '鑓', 'd' => '鑔', 'e' => '鑕', 'f' => '鑖', 'g' => '鑗', 'h' => '鑘', 'i' => '鑙', 'j' => '鑚', 'k' => '鑛', 'l' => '鑜', 'm' => '鑝', 'n' => '鑞', 'o' => '鑟', 'p' => '鑠', 'q' => '鑡', 'r' => '鑢', 's' => '鑣', 't' => '鑤', 'u' => '鑥', 'v' => '鑦', 'w' => '鑧', 'x' => '鑨', 'y' => '鑩', 'z' => '鑪', '{' => '鑬', '|' => '鑭', '}' => '鑮', '~' => '鑯', '' => '鑰', '' => '鑱', '' => '鑲', '' => '鑳', '' => '鑴', '' => '鑵', '' => '鑶', '' => '鑷', '' => '鑸', '' => '鑹', '' => '鑺', '' => '鑻', '' => '鑼', '' => '鑽', '' => '鑾', '' => '鑿', '' => '钀', '' => '钁', '' => '钂', '' => '钃', '' => '钄', '' => '钑', '' => '钖', '' => '钘', '' => '铇', '' => '铏', '' => '铓', '' => '铔', '' => '铚', '' => '铦', '' => '铻', '' => '锜', '' => '锠', '' => '琛', '' => '琚', '' => '瑁', '' => '瑜', '' => '瑗', '' => '瑕', '' => '瑙', '' => '瑷', '' => '瑭', '' => '瑾', '' => '璜', '' => '璎', '' => '璀', '' => '璁', '' => '璇', '' => '璋', '' => '璞', '' => '璨', '' => '璩', '' => '璐', '' => '璧', '' => '瓒', '' => '璺', '' => '韪', '' => '韫', '' => '韬', '' => '杌', '' => '杓', '' => '杞', '' => '杈', '' => '杩', '' => '枥', '' => '枇', '' => '杪', '' => '杳', '' => '枘', '' => '枧', '' => '杵', '' => '枨', '' => '枞', '' => '枭', '' => '枋', '' => '杷', '' => '杼', '' => '柰', '' => '栉', '' => '柘', '' => '栊', '' => '柩', '' => '枰', '' => '栌', '' => '柙', '' => '枵', '' => '柚', '' => '枳', '' => '柝', '' => '栀', '' => '柃', '' => '枸', '' => '柢', '' => '栎', '' => '柁', '' => '柽', '' => '栲', '' => '栳', '' => '桠', '' => '桡', '' => '桎', '' => '桢', '' => '桄', '' => '桤', '' => '梃', '' => '栝', '' => '桕', '' => '桦', '' => '桁', '' => '桧', '' => '桀', '' => '栾', '' => '桊', '' => '桉', '' => '栩', '' => '梵', '' => '梏', '' => '桴', '' => '桷', '' => '梓', '' => '桫', '' => '棂', '' => '楮', '' => '棼', '' => '椟', '' => '椠', '' => '棹', '@' => '锧', 'A' => '锳', 'B' => '锽', 'C' => '镃', 'D' => '镈', 'E' => '镋', 'F' => '镕', 'G' => '镚', 'H' => '镠', 'I' => '镮', 'J' => '镴', 'K' => '镵', 'L' => '長', 'M' => '镸', 'N' => '镹', 'O' => '镺', 'P' => '镻', 'Q' => '镼', 'R' => '镽', 'S' => '镾', 'T' => '門', 'U' => '閁', 'V' => '閂', 'W' => '閃', 'X' => '閄', 'Y' => '閅', 'Z' => '閆', '[' => '閇', '\\' => '閈', ']' => '閉', '^' => '閊', '_' => '開', '`' => '閌', 'a' => '閍', 'b' => '閎', 'c' => '閏', 'd' => '閐', 'e' => '閑', 'f' => '閒', 'g' => '間', 'h' => '閔', 'i' => '閕', 'j' => '閖', 'k' => '閗', 'l' => '閘', 'm' => '閙', 'n' => '閚', 'o' => '閛', 'p' => '閜', 'q' => '閝', 'r' => '閞', 's' => '閟', 't' => '閠', 'u' => '閡', 'v' => '関', 'w' => '閣', 'x' => '閤', 'y' => '閥', 'z' => '閦', '{' => '閧', '|' => '閨', '}' => '閩', '~' => '閪', '' => '閫', '' => '閬', '' => '閭', '' => '閮', '' => '閯', '' => '閰', '' => '閱', '' => '閲', '' => '閳', '' => '閴', '' => '閵', '' => '閶', '' => '閷', '' => '閸', '' => '閹', '' => '閺', '' => '閻', '' => '閼', '' => '閽', '' => '閾', '' => '閿', '' => '闀', '' => '闁', '' => '闂', '' => '闃', '' => '闄', '' => '闅', '' => '闆', '' => '闇', '' => '闈', '' => '闉', '' => '闊', '' => '闋', '' => '椤', '' => '棰', '' => '椋', '' => '椁', '' => '楗', '' => '棣', '' => '椐', '' => '楱', '' => '椹', '' => '楠', '' => '楂', '' => '楝', '' => '榄', '' => '楫', '' => '榀', '' => '榘', '' => '楸', '' => '椴', '' => '槌', '' => '榇', '' => '榈', '' => '槎', '' => '榉', '' => '楦', '' => '楣', '' => '楹', '' => '榛', '' => '榧', '' => '榻', '' => '榫', '' => '榭', '' => '槔', '' => '榱', '' => '槁', '' => '槊', '' => '槟', '' => '榕', '' => '槠', '' => '榍', '' => '槿', '' => '樯', '' => '槭', '' => '樗', '' => '樘', '' => '橥', '' => '槲', '' => '橄', '' => '樾', '' => '檠', '' => '橐', '' => '橛', '' => '樵', '' => '檎', '' => '橹', '' => '樽', '' => '樨', '' => '橘', '' => '橼', '' => '檑', '' => '檐', '' => '檩', '' => '檗', '' => '檫', '' => '猷', '' => '獒', '' => '殁', '' => '殂', '' => '殇', '' => '殄', '' => '殒', '' => '殓', '' => '殍', '' => '殚', '' => '殛', '' => '殡', '' => '殪', '' => '轫', '' => '轭', '' => '轱', '' => '轲', '' => '轳', '' => '轵', '' => '轶', '' => '轸', '' => '轷', '' => '轹', '' => '轺', '' => '轼', '' => '轾', '' => '辁', '' => '辂', '' => '辄', '' => '辇', '' => '辋', '@' => '闌', 'A' => '闍', 'B' => '闎', 'C' => '闏', 'D' => '闐', 'E' => '闑', 'F' => '闒', 'G' => '闓', 'H' => '闔', 'I' => '闕', 'J' => '闖', 'K' => '闗', 'L' => '闘', 'M' => '闙', 'N' => '闚', 'O' => '闛', 'P' => '關', 'Q' => '闝', 'R' => '闞', 'S' => '闟', 'T' => '闠', 'U' => '闡', 'V' => '闢', 'W' => '闣', 'X' => '闤', 'Y' => '闥', 'Z' => '闦', '[' => '闧', '\\' => '闬', ']' => '闿', '^' => '阇', '_' => '阓', '`' => '阘', 'a' => '阛', 'b' => '阞', 'c' => '阠', 'd' => '阣', 'e' => '阤', 'f' => '阥', 'g' => '阦', 'h' => '阧', 'i' => '阨', 'j' => '阩', 'k' => '阫', 'l' => '阬', 'm' => '阭', 'n' => '阯', 'o' => '阰', 'p' => '阷', 'q' => '阸', 'r' => '阹', 's' => '阺', 't' => '阾', 'u' => '陁', 'v' => '陃', 'w' => '陊', 'x' => '陎', 'y' => '陏', 'z' => '陑', '{' => '陒', '|' => '陓', '}' => '陖', '~' => '陗', '' => '陘', '' => '陙', '' => '陚', '' => '陜', '' => '陝', '' => '陞', '' => '陠', '' => '陣', '' => '陥', '' => '陦', '' => '陫', '' => '陭', '' => '陮', '' => '陯', '' => '陰', '' => '陱', '' => '陳', '' => '陸', '' => '陹', '' => '険', '' => '陻', '' => '陼', '' => '陽', '' => '陾', '' => '陿', '' => '隀', '' => '隁', '' => '隂', '' => '隃', '' => '隄', '' => '隇', '' => '隉', '' => '隊', '' => '辍', '' => '辎', '' => '辏', '' => '辘', '' => '辚', '' => '軎', '' => '戋', '' => '戗', '' => '戛', '' => '戟', '' => '戢', '' => '戡', '' => '戥', '' => '戤', '' => '戬', '' => '臧', '' => '瓯', '' => '瓴', '' => '瓿', '' => '甏', '' => '甑', '' => '甓', '' => '攴', '' => '旮', '' => '旯', '' => '旰', '' => '昊', '' => '昙', '' => '杲', '' => '昃', '' => '昕', '' => '昀', '' => '炅', '' => '曷', '' => '昝', '' => '昴', '' => '昱', '' => '昶', '' => '昵', '' => '耆', '' => '晟', '' => '晔', '' => '晁', '' => '晏', '' => '晖', '' => '晡', '' => '晗', '' => '晷', '' => '暄', '' => '暌', '' => '暧', '' => '暝', '' => '暾', '' => '曛', '' => '曜', '' => '曦', '' => '曩', '' => '贲', '' => '贳', '' => '贶', '' => '贻', '' => '贽', '' => '赀', '' => '赅', '' => '赆', '' => '赈', '' => '赉', '' => '赇', '' => '赍', '' => '赕', '' => '赙', '' => '觇', '' => '觊', '' => '觋', '' => '觌', '' => '觎', '' => '觏', '' => '觐', '' => '觑', '' => '牮', '' => '犟', '' => '牝', '' => '牦', '' => '牯', '' => '牾', '' => '牿', '' => '犄', '' => '犋', '' => '犍', '' => '犏', '' => '犒', '' => '挈', '' => '挲', '' => '掰', '@' => '隌', 'A' => '階', 'B' => '隑', 'C' => '隒', 'D' => '隓', 'E' => '隕', 'F' => '隖', 'G' => '隚', 'H' => '際', 'I' => '隝', 'J' => '隞', 'K' => '隟', 'L' => '隠', 'M' => '隡', 'N' => '隢', 'O' => '隣', 'P' => '隤', 'Q' => '隥', 'R' => '隦', 'S' => '隨', 'T' => '隩', 'U' => '險', 'V' => '隫', 'W' => '隬', 'X' => '隭', 'Y' => '隮', 'Z' => '隯', '[' => '隱', '\\' => '隲', ']' => '隴', '^' => '隵', '_' => '隷', '`' => '隸', 'a' => '隺', 'b' => '隻', 'c' => '隿', 'd' => '雂', 'e' => '雃', 'f' => '雈', 'g' => '雊', 'h' => '雋', 'i' => '雐', 'j' => '雑', 'k' => '雓', 'l' => '雔', 'm' => '雖', 'n' => '雗', 'o' => '雘', 'p' => '雙', 'q' => '雚', 'r' => '雛', 's' => '雜', 't' => '雝', 'u' => '雞', 'v' => '雟', 'w' => '雡', 'x' => '離', 'y' => '難', 'z' => '雤', '{' => '雥', '|' => '雦', '}' => '雧', '~' => '雫', '' => '雬', '' => '雭', '' => '雮', '' => '雰', '' => '雱', '' => '雲', '' => '雴', '' => '雵', '' => '雸', '' => '雺', '' => '電', '' => '雼', '' => '雽', '' => '雿', '' => '霂', '' => '霃', '' => '霅', '' => '霊', '' => '霋', '' => '霌', '' => '霐', '' => '霑', '' => '霒', '' => '霔', '' => '霕', '' => '霗', '' => '霘', '' => '霙', '' => '霚', '' => '霛', '' => '霝', '' => '霟', '' => '霠', '' => '搿', '' => '擘', '' => '耄', '' => '毪', '' => '毳', '' => '毽', '' => '毵', '' => '毹', '' => '氅', '' => '氇', '' => '氆', '' => '氍', '' => '氕', '' => '氘', '' => '氙', '' => '氚', '' => '氡', '' => '氩', '' => '氤', '' => '氪', '' => '氲', '' => '攵', '' => '敕', '' => '敫', '' => '牍', '' => '牒', '' => '牖', '' => '爰', '' => '虢', '' => '刖', '' => '肟', '' => '肜', '' => '肓', '' => '肼', '' => '朊', '' => '肽', '' => '肱', '' => '肫', '' => '肭', '' => '肴', '' => '肷', '' => '胧', '' => '胨', '' => '胩', '' => '胪', '' => '胛', '' => '胂', '' => '胄', '' => '胙', '' => '胍', '' => '胗', '' => '朐', '' => '胝', '' => '胫', '' => '胱', '' => '胴', '' => '胭', '' => '脍', '' => '脎', '' => '胲', '' => '胼', '' => '朕', '' => '脒', '' => '豚', '' => '脶', '' => '脞', '' => '脬', '' => '脘', '' => '脲', '' => '腈', '' => '腌', '' => '腓', '' => '腴', '' => '腙', '' => '腚', '' => '腱', '' => '腠', '' => '腩', '' => '腼', '' => '腽', '' => '腭', '' => '腧', '' => '塍', '' => '媵', '' => '膈', '' => '膂', '' => '膑', '' => '滕', '' => '膣', '' => '膪', '' => '臌', '' => '朦', '' => '臊', '' => '膻', '@' => '霡', 'A' => '霢', 'B' => '霣', 'C' => '霤', 'D' => '霥', 'E' => '霦', 'F' => '霧', 'G' => '霨', 'H' => '霩', 'I' => '霫', 'J' => '霬', 'K' => '霮', 'L' => '霯', 'M' => '霱', 'N' => '霳', 'O' => '霴', 'P' => '霵', 'Q' => '霶', 'R' => '霷', 'S' => '霺', 'T' => '霻', 'U' => '霼', 'V' => '霽', 'W' => '霿', 'X' => '靀', 'Y' => '靁', 'Z' => '靂', '[' => '靃', '\\' => '靄', ']' => '靅', '^' => '靆', '_' => '靇', '`' => '靈', 'a' => '靉', 'b' => '靊', 'c' => '靋', 'd' => '靌', 'e' => '靍', 'f' => '靎', 'g' => '靏', 'h' => '靐', 'i' => '靑', 'j' => '靔', 'k' => '靕', 'l' => '靗', 'm' => '靘', 'n' => '靚', 'o' => '靜', 'p' => '靝', 'q' => '靟', 'r' => '靣', 's' => '靤', 't' => '靦', 'u' => '靧', 'v' => '靨', 'w' => '靪', 'x' => '靫', 'y' => '靬', 'z' => '靭', '{' => '靮', '|' => '靯', '}' => '靰', '~' => '靱', '' => '靲', '' => '靵', '' => '靷', '' => '靸', '' => '靹', '' => '靺', '' => '靻', '' => '靽', '' => '靾', '' => '靿', '' => '鞀', '' => '鞁', '' => '鞂', '' => '鞃', '' => '鞄', '' => '鞆', '' => '鞇', '' => '鞈', '' => '鞉', '' => '鞊', '' => '鞌', '' => '鞎', '' => '鞏', '' => '鞐', '' => '鞓', '' => '鞕', '' => '鞖', '' => '鞗', '' => '鞙', '' => '鞚', '' => '鞛', '' => '鞜', '' => '鞝', '' => '臁', '' => '膦', '' => '欤', '' => '欷', '' => '欹', '' => '歃', '' => '歆', '' => '歙', '' => '飑', '' => '飒', '' => '飓', '' => '飕', '' => '飙', '' => '飚', '' => '殳', '' => '彀', '' => '毂', '' => '觳', '' => '斐', '' => '齑', '' => '斓', '' => '於', '' => '旆', '' => '旄', '' => '旃', '' => '旌', '' => '旎', '' => '旒', '' => '旖', '' => '炀', '' => '炜', '' => '炖', '' => '炝', '' => '炻', '' => '烀', '' => '炷', '' => '炫', '' => '炱', '' => '烨', '' => '烊', '' => '焐', '' => '焓', '' => '焖', '' => '焯', '' => '焱', '' => '煳', '' => '煜', '' => '煨', '' => '煅', '' => '煲', '' => '煊', '' => '煸', '' => '煺', '' => '熘', '' => '熳', '' => '熵', '' => '熨', '' => '熠', '' => '燠', '' => '燔', '' => '燧', '' => '燹', '' => '爝', '' => '爨', '' => '灬', '' => '焘', '' => '煦', '' => '熹', '' => '戾', '' => '戽', '' => '扃', '' => '扈', '' => '扉', '' => '礻', '' => '祀', '' => '祆', '' => '祉', '' => '祛', '' => '祜', '' => '祓', '' => '祚', '' => '祢', '' => '祗', '' => '祠', '' => '祯', '' => '祧', '' => '祺', '' => '禅', '' => '禊', '' => '禚', '' => '禧', '' => '禳', '' => '忑', '' => '忐', '@' => '鞞', 'A' => '鞟', 'B' => '鞡', 'C' => '鞢', 'D' => '鞤', 'E' => '鞥', 'F' => '鞦', 'G' => '鞧', 'H' => '鞨', 'I' => '鞩', 'J' => '鞪', 'K' => '鞬', 'L' => '鞮', 'M' => '鞰', 'N' => '鞱', 'O' => '鞳', 'P' => '鞵', 'Q' => '鞶', 'R' => '鞷', 'S' => '鞸', 'T' => '鞹', 'U' => '鞺', 'V' => '鞻', 'W' => '鞼', 'X' => '鞽', 'Y' => '鞾', 'Z' => '鞿', '[' => '韀', '\\' => '韁', ']' => '韂', '^' => '韃', '_' => '韄', '`' => '韅', 'a' => '韆', 'b' => '韇', 'c' => '韈', 'd' => '韉', 'e' => '韊', 'f' => '韋', 'g' => '韌', 'h' => '韍', 'i' => '韎', 'j' => '韏', 'k' => '韐', 'l' => '韑', 'm' => '韒', 'n' => '韓', 'o' => '韔', 'p' => '韕', 'q' => '韖', 'r' => '韗', 's' => '韘', 't' => '韙', 'u' => '韚', 'v' => '韛', 'w' => '韜', 'x' => '韝', 'y' => '韞', 'z' => '韟', '{' => '韠', '|' => '韡', '}' => '韢', '~' => '韣', '' => '韤', '' => '韥', '' => '韨', '' => '韮', '' => '韯', '' => '韰', '' => '韱', '' => '韲', '' => '韴', '' => '韷', '' => '韸', '' => '韹', '' => '韺', '' => '韻', '' => '韼', '' => '韽', '' => '韾', '' => '響', '' => '頀', '' => '頁', '' => '頂', '' => '頃', '' => '頄', '' => '項', '' => '順', '' => '頇', '' => '須', '' => '頉', '' => '頊', '' => '頋', '' => '頌', '' => '頍', '' => '頎', '' => '怼', '' => '恝', '' => '恚', '' => '恧', '' => '恁', '' => '恙', '' => '恣', '' => '悫', '' => '愆', '' => '愍', '' => '慝', '' => '憩', '' => '憝', '' => '懋', '' => '懑', '' => '戆', '' => '肀', '' => '聿', '' => '沓', '' => '泶', '' => '淼', '' => '矶', '' => '矸', '' => '砀', '' => '砉', '' => '砗', '' => '砘', '' => '砑', '' => '斫', '' => '砭', '' => '砜', '' => '砝', '' => '砹', '' => '砺', '' => '砻', '' => '砟', '' => '砼', '' => '砥', '' => '砬', '' => '砣', '' => '砩', '' => '硎', '' => '硭', '' => '硖', '' => '硗', '' => '砦', '' => '硐', '' => '硇', '' => '硌', '' => '硪', '' => '碛', '' => '碓', '' => '碚', '' => '碇', '' => '碜', '' => '碡', '' => '碣', '' => '碲', '' => '碹', '' => '碥', '' => '磔', '' => '磙', '' => '磉', '' => '磬', '' => '磲', '' => '礅', '' => '磴', '' => '礓', '' => '礤', '' => '礞', '' => '礴', '' => '龛', '' => '黹', '' => '黻', '' => '黼', '' => '盱', '' => '眄', '' => '眍', '' => '盹', '' => '眇', '' => '眈', '' => '眚', '' => '眢', '' => '眙', '' => '眭', '' => '眦', '' => '眵', '' => '眸', '' => '睐', '' => '睑', '' => '睇', '' => '睃', '' => '睚', '' => '睨', '@' => '頏', 'A' => '預', 'B' => '頑', 'C' => '頒', 'D' => '頓', 'E' => '頔', 'F' => '頕', 'G' => '頖', 'H' => '頗', 'I' => '領', 'J' => '頙', 'K' => '頚', 'L' => '頛', 'M' => '頜', 'N' => '頝', 'O' => '頞', 'P' => '頟', 'Q' => '頠', 'R' => '頡', 'S' => '頢', 'T' => '頣', 'U' => '頤', 'V' => '頥', 'W' => '頦', 'X' => '頧', 'Y' => '頨', 'Z' => '頩', '[' => '頪', '\\' => '頫', ']' => '頬', '^' => '頭', '_' => '頮', '`' => '頯', 'a' => '頰', 'b' => '頱', 'c' => '頲', 'd' => '頳', 'e' => '頴', 'f' => '頵', 'g' => '頶', 'h' => '頷', 'i' => '頸', 'j' => '頹', 'k' => '頺', 'l' => '頻', 'm' => '頼', 'n' => '頽', 'o' => '頾', 'p' => '頿', 'q' => '顀', 'r' => '顁', 's' => '顂', 't' => '顃', 'u' => '顄', 'v' => '顅', 'w' => '顆', 'x' => '顇', 'y' => '顈', 'z' => '顉', '{' => '顊', '|' => '顋', '}' => '題', '~' => '額', '' => '顎', '' => '顏', '' => '顐', '' => '顑', '' => '顒', '' => '顓', '' => '顔', '' => '顕', '' => '顖', '' => '顗', '' => '願', '' => '顙', '' => '顚', '' => '顛', '' => '顜', '' => '顝', '' => '類', '' => '顟', '' => '顠', '' => '顡', '' => '顢', '' => '顣', '' => '顤', '' => '顥', '' => '顦', '' => '顧', '' => '顨', '' => '顩', '' => '顪', '' => '顫', '' => '顬', '' => '顭', '' => '顮', '' => '睢', '' => '睥', '' => '睿', '' => '瞍', '' => '睽', '' => '瞀', '' => '瞌', '' => '瞑', '' => '瞟', '' => '瞠', '' => '瞰', '' => '瞵', '' => '瞽', '' => '町', '' => '畀', '' => '畎', '' => '畋', '' => '畈', '' => '畛', '' => '畲', '' => '畹', '' => '疃', '' => '罘', '' => '罡', '' => '罟', '' => '詈', '' => '罨', '' => '罴', '' => '罱', '' => '罹', '' => '羁', '' => '罾', '' => '盍', '' => '盥', '' => '蠲', '' => '钅', '' => '钆', '' => '钇', '' => '钋', '' => '钊', '' => '钌', '' => '钍', '' => '钏', '' => '钐', '' => '钔', '' => '钗', '' => '钕', '' => '钚', '' => '钛', '' => '钜', '' => '钣', '' => '钤', '' => '钫', '' => '钪', '' => '钭', '' => '钬', '' => '钯', '' => '钰', '' => '钲', '' => '钴', '' => '钶', '' => '钷', '' => '钸', '' => '钹', '' => '钺', '' => '钼', '' => '钽', '' => '钿', '' => '铄', '' => '铈', '' => '铉', '' => '铊', '' => '铋', '' => '铌', '' => '铍', '' => '铎', '' => '铐', '' => '铑', '' => '铒', '' => '铕', '' => '铖', '' => '铗', '' => '铙', '' => '铘', '' => '铛', '' => '铞', '' => '铟', '' => '铠', '' => '铢', '' => '铤', '' => '铥', '' => '铧', '' => '铨', '' => '铪', '@' => '顯', 'A' => '顰', 'B' => '顱', 'C' => '顲', 'D' => '顳', 'E' => '顴', 'F' => '颋', 'G' => '颎', 'H' => '颒', 'I' => '颕', 'J' => '颙', 'K' => '颣', 'L' => '風', 'M' => '颩', 'N' => '颪', 'O' => '颫', 'P' => '颬', 'Q' => '颭', 'R' => '颮', 'S' => '颯', 'T' => '颰', 'U' => '颱', 'V' => '颲', 'W' => '颳', 'X' => '颴', 'Y' => '颵', 'Z' => '颶', '[' => '颷', '\\' => '颸', ']' => '颹', '^' => '颺', '_' => '颻', '`' => '颼', 'a' => '颽', 'b' => '颾', 'c' => '颿', 'd' => '飀', 'e' => '飁', 'f' => '飂', 'g' => '飃', 'h' => '飄', 'i' => '飅', 'j' => '飆', 'k' => '飇', 'l' => '飈', 'm' => '飉', 'n' => '飊', 'o' => '飋', 'p' => '飌', 'q' => '飍', 'r' => '飏', 's' => '飐', 't' => '飔', 'u' => '飖', 'v' => '飗', 'w' => '飛', 'x' => '飜', 'y' => '飝', 'z' => '飠', '{' => '飡', '|' => '飢', '}' => '飣', '~' => '飤', '' => '飥', '' => '飦', '' => '飩', '' => '飪', '' => '飫', '' => '飬', '' => '飭', '' => '飮', '' => '飯', '' => '飰', '' => '飱', '' => '飲', '' => '飳', '' => '飴', '' => '飵', '' => '飶', '' => '飷', '' => '飸', '' => '飹', '' => '飺', '' => '飻', '' => '飼', '' => '飽', '' => '飾', '' => '飿', '' => '餀', '' => '餁', '' => '餂', '' => '餃', '' => '餄', '' => '餅', '' => '餆', '' => '餇', '' => '铩', '' => '铫', '' => '铮', '' => '铯', '' => '铳', '' => '铴', '' => '铵', '' => '铷', '' => '铹', '' => '铼', '' => '铽', '' => '铿', '' => '锃', '' => '锂', '' => '锆', '' => '锇', '' => '锉', '' => '锊', '' => '锍', '' => '锎', '' => '锏', '' => '锒', '' => '锓', '' => '锔', '' => '锕', '' => '锖', '' => '锘', '' => '锛', '' => '锝', '' => '锞', '' => '锟', '' => '锢', '' => '锪', '' => '锫', '' => '锩', '' => '锬', '' => '锱', '' => '锲', '' => '锴', '' => '锶', '' => '锷', '' => '锸', '' => '锼', '' => '锾', '' => '锿', '' => '镂', '' => '锵', '' => '镄', '' => '镅', '' => '镆', '' => '镉', '' => '镌', '' => '镎', '' => '镏', '' => '镒', '' => '镓', '' => '镔', '' => '镖', '' => '镗', '' => '镘', '' => '镙', '' => '镛', '' => '镞', '' => '镟', '' => '镝', '' => '镡', '' => '镢', '' => '镤', '' => '镥', '' => '镦', '' => '镧', '' => '镨', '' => '镩', '' => '镪', '' => '镫', '' => '镬', '' => '镯', '' => '镱', '' => '镲', '' => '镳', '' => '锺', '' => '矧', '' => '矬', '' => '雉', '' => '秕', '' => '秭', '' => '秣', '' => '秫', '' => '稆', '' => '嵇', '' => '稃', '' => '稂', '' => '稞', '' => '稔', '@' => '餈', 'A' => '餉', 'B' => '養', 'C' => '餋', 'D' => '餌', 'E' => '餎', 'F' => '餏', 'G' => '餑', 'H' => '餒', 'I' => '餓', 'J' => '餔', 'K' => '餕', 'L' => '餖', 'M' => '餗', 'N' => '餘', 'O' => '餙', 'P' => '餚', 'Q' => '餛', 'R' => '餜', 'S' => '餝', 'T' => '餞', 'U' => '餟', 'V' => '餠', 'W' => '餡', 'X' => '餢', 'Y' => '餣', 'Z' => '餤', '[' => '餥', '\\' => '餦', ']' => '餧', '^' => '館', '_' => '餩', '`' => '餪', 'a' => '餫', 'b' => '餬', 'c' => '餭', 'd' => '餯', 'e' => '餰', 'f' => '餱', 'g' => '餲', 'h' => '餳', 'i' => '餴', 'j' => '餵', 'k' => '餶', 'l' => '餷', 'm' => '餸', 'n' => '餹', 'o' => '餺', 'p' => '餻', 'q' => '餼', 'r' => '餽', 's' => '餾', 't' => '餿', 'u' => '饀', 'v' => '饁', 'w' => '饂', 'x' => '饃', 'y' => '饄', 'z' => '饅', '{' => '饆', '|' => '饇', '}' => '饈', '~' => '饉', '' => '饊', '' => '饋', '' => '饌', '' => '饍', '' => '饎', '' => '饏', '' => '饐', '' => '饑', '' => '饒', '' => '饓', '' => '饖', '' => '饗', '' => '饘', '' => '饙', '' => '饚', '' => '饛', '' => '饜', '' => '饝', '' => '饞', '' => '饟', '' => '饠', '' => '饡', '' => '饢', '' => '饤', '' => '饦', '' => '饳', '' => '饸', '' => '饹', '' => '饻', '' => '饾', '' => '馂', '' => '馃', '' => '馉', '' => '稹', '' => '稷', '' => '穑', '' => '黏', '' => '馥', '' => '穰', '' => '皈', '' => '皎', '' => '皓', '' => '皙', '' => '皤', '' => '瓞', '' => '瓠', '' => '甬', '' => '鸠', '' => '鸢', '' => '鸨', '' => '鸩', '' => '鸪', '' => '鸫', '' => '鸬', '' => '鸲', '' => '鸱', '' => '鸶', '' => '鸸', '' => '鸷', '' => '鸹', '' => '鸺', '' => '鸾', '' => '鹁', '' => '鹂', '' => '鹄', '' => '鹆', '' => '鹇', '' => '鹈', '' => '鹉', '' => '鹋', '' => '鹌', '' => '鹎', '' => '鹑', '' => '鹕', '' => '鹗', '' => '鹚', '' => '鹛', '' => '鹜', '' => '鹞', '' => '鹣', '' => '鹦', '' => '鹧', '' => '鹨', '' => '鹩', '' => '鹪', '' => '鹫', '' => '鹬', '' => '鹱', '' => '鹭', '' => '鹳', '' => '疒', '' => '疔', '' => '疖', '' => '疠', '' => '疝', '' => '疬', '' => '疣', '' => '疳', '' => '疴', '' => '疸', '' => '痄', '' => '疱', '' => '疰', '' => '痃', '' => '痂', '' => '痖', '' => '痍', '' => '痣', '' => '痨', '' => '痦', '' => '痤', '' => '痫', '' => '痧', '' => '瘃', '' => '痱', '' => '痼', '' => '痿', '' => '瘐', '' => '瘀', '' => '瘅', '' => '瘌', '' => '瘗', '' => '瘊', '' => '瘥', '' => '瘘', '' => '瘕', '' => '瘙', '@' => '馌', 'A' => '馎', 'B' => '馚', 'C' => '馛', 'D' => '馜', 'E' => '馝', 'F' => '馞', 'G' => '馟', 'H' => '馠', 'I' => '馡', 'J' => '馢', 'K' => '馣', 'L' => '馤', 'M' => '馦', 'N' => '馧', 'O' => '馩', 'P' => '馪', 'Q' => '馫', 'R' => '馬', 'S' => '馭', 'T' => '馮', 'U' => '馯', 'V' => '馰', 'W' => '馱', 'X' => '馲', 'Y' => '馳', 'Z' => '馴', '[' => '馵', '\\' => '馶', ']' => '馷', '^' => '馸', '_' => '馹', '`' => '馺', 'a' => '馻', 'b' => '馼', 'c' => '馽', 'd' => '馾', 'e' => '馿', 'f' => '駀', 'g' => '駁', 'h' => '駂', 'i' => '駃', 'j' => '駄', 'k' => '駅', 'l' => '駆', 'm' => '駇', 'n' => '駈', 'o' => '駉', 'p' => '駊', 'q' => '駋', 'r' => '駌', 's' => '駍', 't' => '駎', 'u' => '駏', 'v' => '駐', 'w' => '駑', 'x' => '駒', 'y' => '駓', 'z' => '駔', '{' => '駕', '|' => '駖', '}' => '駗', '~' => '駘', '' => '駙', '' => '駚', '' => '駛', '' => '駜', '' => '駝', '' => '駞', '' => '駟', '' => '駠', '' => '駡', '' => '駢', '' => '駣', '' => '駤', '' => '駥', '' => '駦', '' => '駧', '' => '駨', '' => '駩', '' => '駪', '' => '駫', '' => '駬', '' => '駭', '' => '駮', '' => '駯', '' => '駰', '' => '駱', '' => '駲', '' => '駳', '' => '駴', '' => '駵', '' => '駶', '' => '駷', '' => '駸', '' => '駹', '' => '瘛', '' => '瘼', '' => '瘢', '' => '瘠', '' => '癀', '' => '瘭', '' => '瘰', '' => '瘿', '' => '瘵', '' => '癃', '' => '瘾', '' => '瘳', '' => '癍', '' => '癞', '' => '癔', '' => '癜', '' => '癖', '' => '癫', '' => '癯', '' => '翊', '' => '竦', '' => '穸', '' => '穹', '' => '窀', '' => '窆', '' => '窈', '' => '窕', '' => '窦', '' => '窠', '' => '窬', '' => '窨', '' => '窭', '' => '窳', '' => '衤', '' => '衩', '' => '衲', '' => '衽', '' => '衿', '' => '袂', '' => '袢', '' => '裆', '' => '袷', '' => '袼', '' => '裉', '' => '裢', '' => '裎', '' => '裣', '' => '裥', '' => '裱', '' => '褚', '' => '裼', '' => '裨', '' => '裾', '' => '裰', '' => '褡', '' => '褙', '' => '褓', '' => '褛', '' => '褊', '' => '褴', '' => '褫', '' => '褶', '' => '襁', '' => '襦', '' => '襻', '' => '疋', '' => '胥', '' => '皲', '' => '皴', '' => '矜', '' => '耒', '' => '耔', '' => '耖', '' => '耜', '' => '耠', '' => '耢', '' => '耥', '' => '耦', '' => '耧', '' => '耩', '' => '耨', '' => '耱', '' => '耋', '' => '耵', '' => '聃', '' => '聆', '' => '聍', '' => '聒', '' => '聩', '' => '聱', '' => '覃', '' => '顸', '' => '颀', '' => '颃', '@' => '駺', 'A' => '駻', 'B' => '駼', 'C' => '駽', 'D' => '駾', 'E' => '駿', 'F' => '騀', 'G' => '騁', 'H' => '騂', 'I' => '騃', 'J' => '騄', 'K' => '騅', 'L' => '騆', 'M' => '騇', 'N' => '騈', 'O' => '騉', 'P' => '騊', 'Q' => '騋', 'R' => '騌', 'S' => '騍', 'T' => '騎', 'U' => '騏', 'V' => '騐', 'W' => '騑', 'X' => '騒', 'Y' => '験', 'Z' => '騔', '[' => '騕', '\\' => '騖', ']' => '騗', '^' => '騘', '_' => '騙', '`' => '騚', 'a' => '騛', 'b' => '騜', 'c' => '騝', 'd' => '騞', 'e' => '騟', 'f' => '騠', 'g' => '騡', 'h' => '騢', 'i' => '騣', 'j' => '騤', 'k' => '騥', 'l' => '騦', 'm' => '騧', 'n' => '騨', 'o' => '騩', 'p' => '騪', 'q' => '騫', 'r' => '騬', 's' => '騭', 't' => '騮', 'u' => '騯', 'v' => '騰', 'w' => '騱', 'x' => '騲', 'y' => '騳', 'z' => '騴', '{' => '騵', '|' => '騶', '}' => '騷', '~' => '騸', '' => '騹', '' => '騺', '' => '騻', '' => '騼', '' => '騽', '' => '騾', '' => '騿', '' => '驀', '' => '驁', '' => '驂', '' => '驃', '' => '驄', '' => '驅', '' => '驆', '' => '驇', '' => '驈', '' => '驉', '' => '驊', '' => '驋', '' => '驌', '' => '驍', '' => '驎', '' => '驏', '' => '驐', '' => '驑', '' => '驒', '' => '驓', '' => '驔', '' => '驕', '' => '驖', '' => '驗', '' => '驘', '' => '驙', '' => '颉', '' => '颌', '' => '颍', '' => '颏', '' => '颔', '' => '颚', '' => '颛', '' => '颞', '' => '颟', '' => '颡', '' => '颢', '' => '颥', '' => '颦', '' => '虍', '' => '虔', '' => '虬', '' => '虮', '' => '虿', '' => '虺', '' => '虼', '' => '虻', '' => '蚨', '' => '蚍', '' => '蚋', '' => '蚬', '' => '蚝', '' => '蚧', '' => '蚣', '' => '蚪', '' => '蚓', '' => '蚩', '' => '蚶', '' => '蛄', '' => '蚵', '' => '蛎', '' => '蚰', '' => '蚺', '' => '蚱', '' => '蚯', '' => '蛉', '' => '蛏', '' => '蚴', '' => '蛩', '' => '蛱', '' => '蛲', '' => '蛭', '' => '蛳', '' => '蛐', '' => '蜓', '' => '蛞', '' => '蛴', '' => '蛟', '' => '蛘', '' => '蛑', '' => '蜃', '' => '蜇', '' => '蛸', '' => '蜈', '' => '蜊', '' => '蜍', '' => '蜉', '' => '蜣', '' => '蜻', '' => '蜞', '' => '蜥', '' => '蜮', '' => '蜚', '' => '蜾', '' => '蝈', '' => '蜴', '' => '蜱', '' => '蜩', '' => '蜷', '' => '蜿', '' => '螂', '' => '蜢', '' => '蝽', '' => '蝾', '' => '蝻', '' => '蝠', '' => '蝰', '' => '蝌', '' => '蝮', '' => '螋', '' => '蝓', '' => '蝣', '' => '蝼', '' => '蝤', '' => '蝙', '' => '蝥', '' => '螓', '' => '螯', '' => '螨', '' => '蟒', '@' => '驚', 'A' => '驛', 'B' => '驜', 'C' => '驝', 'D' => '驞', 'E' => '驟', 'F' => '驠', 'G' => '驡', 'H' => '驢', 'I' => '驣', 'J' => '驤', 'K' => '驥', 'L' => '驦', 'M' => '驧', 'N' => '驨', 'O' => '驩', 'P' => '驪', 'Q' => '驫', 'R' => '驲', 'S' => '骃', 'T' => '骉', 'U' => '骍', 'V' => '骎', 'W' => '骔', 'X' => '骕', 'Y' => '骙', 'Z' => '骦', '[' => '骩', '\\' => '骪', ']' => '骫', '^' => '骬', '_' => '骭', '`' => '骮', 'a' => '骯', 'b' => '骲', 'c' => '骳', 'd' => '骴', 'e' => '骵', 'f' => '骹', 'g' => '骻', 'h' => '骽', 'i' => '骾', 'j' => '骿', 'k' => '髃', 'l' => '髄', 'm' => '髆', 'n' => '髇', 'o' => '髈', 'p' => '髉', 'q' => '髊', 'r' => '髍', 's' => '髎', 't' => '髏', 'u' => '髐', 'v' => '髒', 'w' => '體', 'x' => '髕', 'y' => '髖', 'z' => '髗', '{' => '髙', '|' => '髚', '}' => '髛', '~' => '髜', '' => '髝', '' => '髞', '' => '髠', '' => '髢', '' => '髣', '' => '髤', '' => '髥', '' => '髧', '' => '髨', '' => '髩', '' => '髪', '' => '髬', '' => '髮', '' => '髰', '' => '髱', '' => '髲', '' => '髳', '' => '髴', '' => '髵', '' => '髶', '' => '髷', '' => '髸', '' => '髺', '' => '髼', '' => '髽', '' => '髾', '' => '髿', '' => '鬀', '' => '鬁', '' => '鬂', '' => '鬄', '' => '鬅', '' => '鬆', '' => '蟆', '' => '螈', '' => '螅', '' => '螭', '' => '螗', '' => '螃', '' => '螫', '' => '蟥', '' => '螬', '' => '螵', '' => '螳', '' => '蟋', '' => '蟓', '' => '螽', '' => '蟑', '' => '蟀', '' => '蟊', '' => '蟛', '' => '蟪', '' => '蟠', '' => '蟮', '' => '蠖', '' => '蠓', '' => '蟾', '' => '蠊', '' => '蠛', '' => '蠡', '' => '蠹', '' => '蠼', '' => '缶', '' => '罂', '' => '罄', '' => '罅', '' => '舐', '' => '竺', '' => '竽', '' => '笈', '' => '笃', '' => '笄', '' => '笕', '' => '笊', '' => '笫', '' => '笏', '' => '筇', '' => '笸', '' => '笪', '' => '笙', '' => '笮', '' => '笱', '' => '笠', '' => '笥', '' => '笤', '' => '笳', '' => '笾', '' => '笞', '' => '筘', '' => '筚', '' => '筅', '' => '筵', '' => '筌', '' => '筝', '' => '筠', '' => '筮', '' => '筻', '' => '筢', '' => '筲', '' => '筱', '' => '箐', '' => '箦', '' => '箧', '' => '箸', '' => '箬', '' => '箝', '' => '箨', '' => '箅', '' => '箪', '' => '箜', '' => '箢', '' => '箫', '' => '箴', '' => '篑', '' => '篁', '' => '篌', '' => '篝', '' => '篚', '' => '篥', '' => '篦', '' => '篪', '' => '簌', '' => '篾', '' => '篼', '' => '簏', '' => '簖', '' => '簋', '@' => '鬇', 'A' => '鬉', 'B' => '鬊', 'C' => '鬋', 'D' => '鬌', 'E' => '鬍', 'F' => '鬎', 'G' => '鬐', 'H' => '鬑', 'I' => '鬒', 'J' => '鬔', 'K' => '鬕', 'L' => '鬖', 'M' => '鬗', 'N' => '鬘', 'O' => '鬙', 'P' => '鬚', 'Q' => '鬛', 'R' => '鬜', 'S' => '鬝', 'T' => '鬞', 'U' => '鬠', 'V' => '鬡', 'W' => '鬢', 'X' => '鬤', 'Y' => '鬥', 'Z' => '鬦', '[' => '鬧', '\\' => '鬨', ']' => '鬩', '^' => '鬪', '_' => '鬫', '`' => '鬬', 'a' => '鬭', 'b' => '鬮', 'c' => '鬰', 'd' => '鬱', 'e' => '鬳', 'f' => '鬴', 'g' => '鬵', 'h' => '鬶', 'i' => '鬷', 'j' => '鬸', 'k' => '鬹', 'l' => '鬺', 'm' => '鬽', 'n' => '鬾', 'o' => '鬿', 'p' => '魀', 'q' => '魆', 'r' => '魊', 's' => '魋', 't' => '魌', 'u' => '魎', 'v' => '魐', 'w' => '魒', 'x' => '魓', 'y' => '魕', 'z' => '魖', '{' => '魗', '|' => '魘', '}' => '魙', '~' => '魚', '' => '魛', '' => '魜', '' => '魝', '' => '魞', '' => '魟', '' => '魠', '' => '魡', '' => '魢', '' => '魣', '' => '魤', '' => '魥', '' => '魦', '' => '魧', '' => '魨', '' => '魩', '' => '魪', '' => '魫', '' => '魬', '' => '魭', '' => '魮', '' => '魯', '' => '魰', '' => '魱', '' => '魲', '' => '魳', '' => '魴', '' => '魵', '' => '魶', '' => '魷', '' => '魸', '' => '魹', '' => '魺', '' => '魻', '' => '簟', '' => '簪', '' => '簦', '' => '簸', '' => '籁', '' => '籀', '' => '臾', '' => '舁', '' => '舂', '' => '舄', '' => '臬', '' => '衄', '' => '舡', '' => '舢', '' => '舣', '' => '舭', '' => '舯', '' => '舨', '' => '舫', '' => '舸', '' => '舻', '' => '舳', '' => '舴', '' => '舾', '' => '艄', '' => '艉', '' => '艋', '' => '艏', '' => '艚', '' => '艟', '' => '艨', '' => '衾', '' => '袅', '' => '袈', '' => '裘', '' => '裟', '' => '襞', '' => '羝', '' => '羟', '' => '羧', '' => '羯', '' => '羰', '' => '羲', '' => '籼', '' => '敉', '' => '粑', '' => '粝', '' => '粜', '' => '粞', '' => '粢', '' => '粲', '' => '粼', '' => '粽', '' => '糁', '' => '糇', '' => '糌', '' => '糍', '' => '糈', '' => '糅', '' => '糗', '' => '糨', '' => '艮', '' => '暨', '' => '羿', '' => '翎', '' => '翕', '' => '翥', '' => '翡', '' => '翦', '' => '翩', '' => '翮', '' => '翳', '' => '糸', '' => '絷', '' => '綦', '' => '綮', '' => '繇', '' => '纛', '' => '麸', '' => '麴', '' => '赳', '' => '趄', '' => '趔', '' => '趑', '' => '趱', '' => '赧', '' => '赭', '' => '豇', '' => '豉', '' => '酊', '' => '酐', '' => '酎', '' => '酏', '' => '酤', '@' => '魼', 'A' => '魽', 'B' => '魾', 'C' => '魿', 'D' => '鮀', 'E' => '鮁', 'F' => '鮂', 'G' => '鮃', 'H' => '鮄', 'I' => '鮅', 'J' => '鮆', 'K' => '鮇', 'L' => '鮈', 'M' => '鮉', 'N' => '鮊', 'O' => '鮋', 'P' => '鮌', 'Q' => '鮍', 'R' => '鮎', 'S' => '鮏', 'T' => '鮐', 'U' => '鮑', 'V' => '鮒', 'W' => '鮓', 'X' => '鮔', 'Y' => '鮕', 'Z' => '鮖', '[' => '鮗', '\\' => '鮘', ']' => '鮙', '^' => '鮚', '_' => '鮛', '`' => '鮜', 'a' => '鮝', 'b' => '鮞', 'c' => '鮟', 'd' => '鮠', 'e' => '鮡', 'f' => '鮢', 'g' => '鮣', 'h' => '鮤', 'i' => '鮥', 'j' => '鮦', 'k' => '鮧', 'l' => '鮨', 'm' => '鮩', 'n' => '鮪', 'o' => '鮫', 'p' => '鮬', 'q' => '鮭', 'r' => '鮮', 's' => '鮯', 't' => '鮰', 'u' => '鮱', 'v' => '鮲', 'w' => '鮳', 'x' => '鮴', 'y' => '鮵', 'z' => '鮶', '{' => '鮷', '|' => '鮸', '}' => '鮹', '~' => '鮺', '' => '鮻', '' => '鮼', '' => '鮽', '' => '鮾', '' => '鮿', '' => '鯀', '' => '鯁', '' => '鯂', '' => '鯃', '' => '鯄', '' => '鯅', '' => '鯆', '' => '鯇', '' => '鯈', '' => '鯉', '' => '鯊', '' => '鯋', '' => '鯌', '' => '鯍', '' => '鯎', '' => '鯏', '' => '鯐', '' => '鯑', '' => '鯒', '' => '鯓', '' => '鯔', '' => '鯕', '' => '鯖', '' => '鯗', '' => '鯘', '' => '鯙', '' => '鯚', '' => '鯛', '' => '酢', '' => '酡', '' => '酰', '' => '酩', '' => '酯', '' => '酽', '' => '酾', '' => '酲', '' => '酴', '' => '酹', '' => '醌', '' => '醅', '' => '醐', '' => '醍', '' => '醑', '' => '醢', '' => '醣', '' => '醪', '' => '醭', '' => '醮', '' => '醯', '' => '醵', '' => '醴', '' => '醺', '' => '豕', '' => '鹾', '' => '趸', '' => '跫', '' => '踅', '' => '蹙', '' => '蹩', '' => '趵', '' => '趿', '' => '趼', '' => '趺', '' => '跄', '' => '跖', '' => '跗', '' => '跚', '' => '跞', '' => '跎', '' => '跏', '' => '跛', '' => '跆', '' => '跬', '' => '跷', '' => '跸', '' => '跣', '' => '跹', '' => '跻', '' => '跤', '' => '踉', '' => '跽', '' => '踔', '' => '踝', '' => '踟', '' => '踬', '' => '踮', '' => '踣', '' => '踯', '' => '踺', '' => '蹀', '' => '踹', '' => '踵', '' => '踽', '' => '踱', '' => '蹉', '' => '蹁', '' => '蹂', '' => '蹑', '' => '蹒', '' => '蹊', '' => '蹰', '' => '蹶', '' => '蹼', '' => '蹯', '' => '蹴', '' => '躅', '' => '躏', '' => '躔', '' => '躐', '' => '躜', '' => '躞', '' => '豸', '' => '貂', '' => '貊', '' => '貅', '' => '貘', '' => '貔', '' => '斛', '' => '觖', '' => '觞', '' => '觚', '' => '觜', '@' => '鯜', 'A' => '鯝', 'B' => '鯞', 'C' => '鯟', 'D' => '鯠', 'E' => '鯡', 'F' => '鯢', 'G' => '鯣', 'H' => '鯤', 'I' => '鯥', 'J' => '鯦', 'K' => '鯧', 'L' => '鯨', 'M' => '鯩', 'N' => '鯪', 'O' => '鯫', 'P' => '鯬', 'Q' => '鯭', 'R' => '鯮', 'S' => '鯯', 'T' => '鯰', 'U' => '鯱', 'V' => '鯲', 'W' => '鯳', 'X' => '鯴', 'Y' => '鯵', 'Z' => '鯶', '[' => '鯷', '\\' => '鯸', ']' => '鯹', '^' => '鯺', '_' => '鯻', '`' => '鯼', 'a' => '鯽', 'b' => '鯾', 'c' => '鯿', 'd' => '鰀', 'e' => '鰁', 'f' => '鰂', 'g' => '鰃', 'h' => '鰄', 'i' => '鰅', 'j' => '鰆', 'k' => '鰇', 'l' => '鰈', 'm' => '鰉', 'n' => '鰊', 'o' => '鰋', 'p' => '鰌', 'q' => '鰍', 'r' => '鰎', 's' => '鰏', 't' => '鰐', 'u' => '鰑', 'v' => '鰒', 'w' => '鰓', 'x' => '鰔', 'y' => '鰕', 'z' => '鰖', '{' => '鰗', '|' => '鰘', '}' => '鰙', '~' => '鰚', '' => '鰛', '' => '鰜', '' => '鰝', '' => '鰞', '' => '鰟', '' => '鰠', '' => '鰡', '' => '鰢', '' => '鰣', '' => '鰤', '' => '鰥', '' => '鰦', '' => '鰧', '' => '鰨', '' => '鰩', '' => '鰪', '' => '鰫', '' => '鰬', '' => '鰭', '' => '鰮', '' => '鰯', '' => '鰰', '' => '鰱', '' => '鰲', '' => '鰳', '' => '鰴', '' => '鰵', '' => '鰶', '' => '鰷', '' => '鰸', '' => '鰹', '' => '鰺', '' => '鰻', '' => '觥', '' => '觫', '' => '觯', '' => '訾', '' => '謦', '' => '靓', '' => '雩', '' => '雳', '' => '雯', '' => '霆', '' => '霁', '' => '霈', '' => '霏', '' => '霎', '' => '霪', '' => '霭', '' => '霰', '' => '霾', '' => '龀', '' => '龃', '' => '龅', '' => '龆', '' => '龇', '' => '龈', '' => '龉', '' => '龊', '' => '龌', '' => '黾', '' => '鼋', '' => '鼍', '' => '隹', '' => '隼', '' => '隽', '' => '雎', '' => '雒', '' => '瞿', '' => '雠', '' => '銎', '' => '銮', '' => '鋈', '' => '錾', '' => '鍪', '' => '鏊', '' => '鎏', '' => '鐾', '' => '鑫', '' => '鱿', '' => '鲂', '' => '鲅', '' => '鲆', '' => '鲇', '' => '鲈', '' => '稣', '' => '鲋', '' => '鲎', '' => '鲐', '' => '鲑', '' => '鲒', '' => '鲔', '' => '鲕', '' => '鲚', '' => '鲛', '' => '鲞', '' => '鲟', '' => '鲠', '' => '鲡', '' => '鲢', '' => '鲣', '' => '鲥', '' => '鲦', '' => '鲧', '' => '鲨', '' => '鲩', '' => '鲫', '' => '鲭', '' => '鲮', '' => '鲰', '' => '鲱', '' => '鲲', '' => '鲳', '' => '鲴', '' => '鲵', '' => '鲶', '' => '鲷', '' => '鲺', '' => '鲻', '' => '鲼', '' => '鲽', '' => '鳄', '' => '鳅', '' => '鳆', '' => '鳇', '' => '鳊', '' => '鳋', '@' => '鰼', 'A' => '鰽', 'B' => '鰾', 'C' => '鰿', 'D' => '鱀', 'E' => '鱁', 'F' => '鱂', 'G' => '鱃', 'H' => '鱄', 'I' => '鱅', 'J' => '鱆', 'K' => '鱇', 'L' => '鱈', 'M' => '鱉', 'N' => '鱊', 'O' => '鱋', 'P' => '鱌', 'Q' => '鱍', 'R' => '鱎', 'S' => '鱏', 'T' => '鱐', 'U' => '鱑', 'V' => '鱒', 'W' => '鱓', 'X' => '鱔', 'Y' => '鱕', 'Z' => '鱖', '[' => '鱗', '\\' => '鱘', ']' => '鱙', '^' => '鱚', '_' => '鱛', '`' => '鱜', 'a' => '鱝', 'b' => '鱞', 'c' => '鱟', 'd' => '鱠', 'e' => '鱡', 'f' => '鱢', 'g' => '鱣', 'h' => '鱤', 'i' => '鱥', 'j' => '鱦', 'k' => '鱧', 'l' => '鱨', 'm' => '鱩', 'n' => '鱪', 'o' => '鱫', 'p' => '鱬', 'q' => '鱭', 'r' => '鱮', 's' => '鱯', 't' => '鱰', 'u' => '鱱', 'v' => '鱲', 'w' => '鱳', 'x' => '鱴', 'y' => '鱵', 'z' => '鱶', '{' => '鱷', '|' => '鱸', '}' => '鱹', '~' => '鱺', '' => '鱻', '' => '鱽', '' => '鱾', '' => '鲀', '' => '鲃', '' => '鲄', '' => '鲉', '' => '鲊', '' => '鲌', '' => '鲏', '' => '鲓', '' => '鲖', '' => '鲗', '' => '鲘', '' => '鲙', '' => '鲝', '' => '鲪', '' => '鲬', '' => '鲯', '' => '鲹', '' => '鲾', '' => '鲿', '' => '鳀', '' => '鳁', '' => '鳂', '' => '鳈', '' => '鳉', '' => '鳑', '' => '鳒', '' => '鳚', '' => '鳛', '' => '鳠', '' => '鳡', '' => '鳌', '' => '鳍', '' => '鳎', '' => '鳏', '' => '鳐', '' => '鳓', '' => '鳔', '' => '鳕', '' => '鳗', '' => '鳘', '' => '鳙', '' => '鳜', '' => '鳝', '' => '鳟', '' => '鳢', '' => '靼', '' => '鞅', '' => '鞑', '' => '鞒', '' => '鞔', '' => '鞯', '' => '鞫', '' => '鞣', '' => '鞲', '' => '鞴', '' => '骱', '' => '骰', '' => '骷', '' => '鹘', '' => '骶', '' => '骺', '' => '骼', '' => '髁', '' => '髀', '' => '髅', '' => '髂', '' => '髋', '' => '髌', '' => '髑', '' => '魅', '' => '魃', '' => '魇', '' => '魉', '' => '魈', '' => '魍', '' => '魑', '' => '飨', '' => '餍', '' => '餮', '' => '饕', '' => '饔', '' => '髟', '' => '髡', '' => '髦', '' => '髯', '' => '髫', '' => '髻', '' => '髭', '' => '髹', '' => '鬈', '' => '鬏', '' => '鬓', '' => '鬟', '' => '鬣', '' => '麽', '' => '麾', '' => '縻', '' => '麂', '' => '麇', '' => '麈', '' => '麋', '' => '麒', '' => '鏖', '' => '麝', '' => '麟', '' => '黛', '' => '黜', '' => '黝', '' => '黠', '' => '黟', '' => '黢', '' => '黩', '' => '黧', '' => '黥', '' => '黪', '' => '黯', '' => '鼢', '' => '鼬', '' => '鼯', '' => '鼹', '' => '鼷', '' => '鼽', '' => '鼾', '' => '齄', '@' => '鳣', 'A' => '鳤', 'B' => '鳥', 'C' => '鳦', 'D' => '鳧', 'E' => '鳨', 'F' => '鳩', 'G' => '鳪', 'H' => '鳫', 'I' => '鳬', 'J' => '鳭', 'K' => '鳮', 'L' => '鳯', 'M' => '鳰', 'N' => '鳱', 'O' => '鳲', 'P' => '鳳', 'Q' => '鳴', 'R' => '鳵', 'S' => '鳶', 'T' => '鳷', 'U' => '鳸', 'V' => '鳹', 'W' => '鳺', 'X' => '鳻', 'Y' => '鳼', 'Z' => '鳽', '[' => '鳾', '\\' => '鳿', ']' => '鴀', '^' => '鴁', '_' => '鴂', '`' => '鴃', 'a' => '鴄', 'b' => '鴅', 'c' => '鴆', 'd' => '鴇', 'e' => '鴈', 'f' => '鴉', 'g' => '鴊', 'h' => '鴋', 'i' => '鴌', 'j' => '鴍', 'k' => '鴎', 'l' => '鴏', 'm' => '鴐', 'n' => '鴑', 'o' => '鴒', 'p' => '鴓', 'q' => '鴔', 'r' => '鴕', 's' => '鴖', 't' => '鴗', 'u' => '鴘', 'v' => '鴙', 'w' => '鴚', 'x' => '鴛', 'y' => '鴜', 'z' => '鴝', '{' => '鴞', '|' => '鴟', '}' => '鴠', '~' => '鴡', '' => '鴢', '' => '鴣', '' => '鴤', '' => '鴥', '' => '鴦', '' => '鴧', '' => '鴨', '' => '鴩', '' => '鴪', '' => '鴫', '' => '鴬', '' => '鴭', '' => '鴮', '' => '鴯', '' => '鴰', '' => '鴱', '' => '鴲', '' => '鴳', '' => '鴴', '' => '鴵', '' => '鴶', '' => '鴷', '' => '鴸', '' => '鴹', '' => '鴺', '' => '鴻', '' => '鴼', '' => '鴽', '' => '鴾', '' => '鴿', '' => '鵀', '' => '鵁', '' => '鵂', '@' => '鵃', 'A' => '鵄', 'B' => '鵅', 'C' => '鵆', 'D' => '鵇', 'E' => '鵈', 'F' => '鵉', 'G' => '鵊', 'H' => '鵋', 'I' => '鵌', 'J' => '鵍', 'K' => '鵎', 'L' => '鵏', 'M' => '鵐', 'N' => '鵑', 'O' => '鵒', 'P' => '鵓', 'Q' => '鵔', 'R' => '鵕', 'S' => '鵖', 'T' => '鵗', 'U' => '鵘', 'V' => '鵙', 'W' => '鵚', 'X' => '鵛', 'Y' => '鵜', 'Z' => '鵝', '[' => '鵞', '\\' => '鵟', ']' => '鵠', '^' => '鵡', '_' => '鵢', '`' => '鵣', 'a' => '鵤', 'b' => '鵥', 'c' => '鵦', 'd' => '鵧', 'e' => '鵨', 'f' => '鵩', 'g' => '鵪', 'h' => '鵫', 'i' => '鵬', 'j' => '鵭', 'k' => '鵮', 'l' => '鵯', 'm' => '鵰', 'n' => '鵱', 'o' => '鵲', 'p' => '鵳', 'q' => '鵴', 'r' => '鵵', 's' => '鵶', 't' => '鵷', 'u' => '鵸', 'v' => '鵹', 'w' => '鵺', 'x' => '鵻', 'y' => '鵼', 'z' => '鵽', '{' => '鵾', '|' => '鵿', '}' => '鶀', '~' => '鶁', '' => '鶂', '' => '鶃', '' => '鶄', '' => '鶅', '' => '鶆', '' => '鶇', '' => '鶈', '' => '鶉', '' => '鶊', '' => '鶋', '' => '鶌', '' => '鶍', '' => '鶎', '' => '鶏', '' => '鶐', '' => '鶑', '' => '鶒', '' => '鶓', '' => '鶔', '' => '鶕', '' => '鶖', '' => '鶗', '' => '鶘', '' => '鶙', '' => '鶚', '' => '鶛', '' => '鶜', '' => '鶝', '' => '鶞', '' => '鶟', '' => '鶠', '' => '鶡', '' => '鶢', '@' => '鶣', 'A' => '鶤', 'B' => '鶥', 'C' => '鶦', 'D' => '鶧', 'E' => '鶨', 'F' => '鶩', 'G' => '鶪', 'H' => '鶫', 'I' => '鶬', 'J' => '鶭', 'K' => '鶮', 'L' => '鶯', 'M' => '鶰', 'N' => '鶱', 'O' => '鶲', 'P' => '鶳', 'Q' => '鶴', 'R' => '鶵', 'S' => '鶶', 'T' => '鶷', 'U' => '鶸', 'V' => '鶹', 'W' => '鶺', 'X' => '鶻', 'Y' => '鶼', 'Z' => '鶽', '[' => '鶾', '\\' => '鶿', ']' => '鷀', '^' => '鷁', '_' => '鷂', '`' => '鷃', 'a' => '鷄', 'b' => '鷅', 'c' => '鷆', 'd' => '鷇', 'e' => '鷈', 'f' => '鷉', 'g' => '鷊', 'h' => '鷋', 'i' => '鷌', 'j' => '鷍', 'k' => '鷎', 'l' => '鷏', 'm' => '鷐', 'n' => '鷑', 'o' => '鷒', 'p' => '鷓', 'q' => '鷔', 'r' => '鷕', 's' => '鷖', 't' => '鷗', 'u' => '鷘', 'v' => '鷙', 'w' => '鷚', 'x' => '鷛', 'y' => '鷜', 'z' => '鷝', '{' => '鷞', '|' => '鷟', '}' => '鷠', '~' => '鷡', '' => '鷢', '' => '鷣', '' => '鷤', '' => '鷥', '' => '鷦', '' => '鷧', '' => '鷨', '' => '鷩', '' => '鷪', '' => '鷫', '' => '鷬', '' => '鷭', '' => '鷮', '' => '鷯', '' => '鷰', '' => '鷱', '' => '鷲', '' => '鷳', '' => '鷴', '' => '鷵', '' => '鷶', '' => '鷷', '' => '鷸', '' => '鷹', '' => '鷺', '' => '鷻', '' => '鷼', '' => '鷽', '' => '鷾', '' => '鷿', '' => '鸀', '' => '鸁', '' => '鸂', '@' => '鸃', 'A' => '鸄', 'B' => '鸅', 'C' => '鸆', 'D' => '鸇', 'E' => '鸈', 'F' => '鸉', 'G' => '鸊', 'H' => '鸋', 'I' => '鸌', 'J' => '鸍', 'K' => '鸎', 'L' => '鸏', 'M' => '鸐', 'N' => '鸑', 'O' => '鸒', 'P' => '鸓', 'Q' => '鸔', 'R' => '鸕', 'S' => '鸖', 'T' => '鸗', 'U' => '鸘', 'V' => '鸙', 'W' => '鸚', 'X' => '鸛', 'Y' => '鸜', 'Z' => '鸝', '[' => '鸞', '\\' => '鸤', ']' => '鸧', '^' => '鸮', '_' => '鸰', '`' => '鸴', 'a' => '鸻', 'b' => '鸼', 'c' => '鹀', 'd' => '鹍', 'e' => '鹐', 'f' => '鹒', 'g' => '鹓', 'h' => '鹔', 'i' => '鹖', 'j' => '鹙', 'k' => '鹝', 'l' => '鹟', 'm' => '鹠', 'n' => '鹡', 'o' => '鹢', 'p' => '鹥', 'q' => '鹮', 'r' => '鹯', 's' => '鹲', 't' => '鹴', 'u' => '鹵', 'v' => '鹶', 'w' => '鹷', 'x' => '鹸', 'y' => '鹹', 'z' => '鹺', '{' => '鹻', '|' => '鹼', '}' => '鹽', '~' => '麀', '' => '麁', '' => '麃', '' => '麄', '' => '麅', '' => '麆', '' => '麉', '' => '麊', '' => '麌', '' => '麍', '' => '麎', '' => '麏', '' => '麐', '' => '麑', '' => '麔', '' => '麕', '' => '麖', '' => '麗', '' => '麘', '' => '麙', '' => '麚', '' => '麛', '' => '麜', '' => '麞', '' => '麠', '' => '麡', '' => '麢', '' => '麣', '' => '麤', '' => '麥', '' => '麧', '' => '麨', '' => '麩', '' => '麪', '@' => '麫', 'A' => '麬', 'B' => '麭', 'C' => '麮', 'D' => '麯', 'E' => '麰', 'F' => '麱', 'G' => '麲', 'H' => '麳', 'I' => '麵', 'J' => '麶', 'K' => '麷', 'L' => '麹', 'M' => '麺', 'N' => '麼', 'O' => '麿', 'P' => '黀', 'Q' => '黁', 'R' => '黂', 'S' => '黃', 'T' => '黅', 'U' => '黆', 'V' => '黇', 'W' => '黈', 'X' => '黊', 'Y' => '黋', 'Z' => '黌', '[' => '黐', '\\' => '黒', ']' => '黓', '^' => '黕', '_' => '黖', '`' => '黗', 'a' => '黙', 'b' => '黚', 'c' => '點', 'd' => '黡', 'e' => '黣', 'f' => '黤', 'g' => '黦', 'h' => '黨', 'i' => '黫', 'j' => '黬', 'k' => '黭', 'l' => '黮', 'm' => '黰', 'n' => '黱', 'o' => '黲', 'p' => '黳', 'q' => '黴', 'r' => '黵', 's' => '黶', 't' => '黷', 'u' => '黸', 'v' => '黺', 'w' => '黽', 'x' => '黿', 'y' => '鼀', 'z' => '鼁', '{' => '鼂', '|' => '鼃', '}' => '鼄', '~' => '鼅', '' => '鼆', '' => '鼇', '' => '鼈', '' => '鼉', '' => '鼊', '' => '鼌', '' => '鼏', '' => '鼑', '' => '鼒', '' => '鼔', '' => '鼕', '' => '鼖', '' => '鼘', '' => '鼚', '' => '鼛', '' => '鼜', '' => '鼝', '' => '鼞', '' => '鼟', '' => '鼡', '' => '鼣', '' => '鼤', '' => '鼥', '' => '鼦', '' => '鼧', '' => '鼨', '' => '鼩', '' => '鼪', '' => '鼫', '' => '鼭', '' => '鼮', '' => '鼰', '' => '鼱', '@' => '鼲', 'A' => '鼳', 'B' => '鼴', 'C' => '鼵', 'D' => '鼶', 'E' => '鼸', 'F' => '鼺', 'G' => '鼼', 'H' => '鼿', 'I' => '齀', 'J' => '齁', 'K' => '齂', 'L' => '齃', 'M' => '齅', 'N' => '齆', 'O' => '齇', 'P' => '齈', 'Q' => '齉', 'R' => '齊', 'S' => '齋', 'T' => '齌', 'U' => '齍', 'V' => '齎', 'W' => '齏', 'X' => '齒', 'Y' => '齓', 'Z' => '齔', '[' => '齕', '\\' => '齖', ']' => '齗', '^' => '齘', '_' => '齙', '`' => '齚', 'a' => '齛', 'b' => '齜', 'c' => '齝', 'd' => '齞', 'e' => '齟', 'f' => '齠', 'g' => '齡', 'h' => '齢', 'i' => '齣', 'j' => '齤', 'k' => '齥', 'l' => '齦', 'm' => '齧', 'n' => '齨', 'o' => '齩', 'p' => '齪', 'q' => '齫', '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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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' => '즮', '' => '즯', '' => '즰', '' => '즱', '' => '즲', '' => '즳', '' => '즴', '' => '즵', '' => '즶', '' => '즷', '' => '즸', '' => '즹', '' => '즺', '' => '즻', '' => '즼', '' => '즽', '' => '즾', '' => '즿', '' => '짂', '' => '짃', '' => '짅', '' => '짆', '' => '짉', '' => '짋', '' => '짌', '' => '짍', '' => '짎', '' => '짏', '' => '짒', '' => '짔', '' => '짗', '' => '짘', '' => '짛', '' => '!', '' => '"', '' => '#', '' => '$', '' => '%', '' => '&', '' => ''', '' => '(', '' => ')', '' => '*', '' => '+', '' => ',', '' => '-', '' => '.', '' => '/', '' => '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' => '쩱', 'h' => '쩲', 'i' => '쩳', 'j' => '쩴', 'k' => '쩵', 'l' => '쩶', 'm' => '쩷', 'n' => '쩸', 'o' => '쩹', 'p' => '쩺', 'q' => '쩻', 'r' => '쩼', 's' => '쩾', 't' => '쩿', 'u' => '쪀', 'v' => '쪁', 'w' => '쪂', 'x' => '쪃', 'y' => '쪅', 'z' => '쪆', '' => '쪇', '' => '쪈', '' => '쪉', '' => '쪊', '' => '쪋', '' => '쪌', '' => '쪍', '' => '쪎', '' => '쪏', '' => '쪐', '' => '쪑', '' => '쪒', '' => '쪓', '' => '쪔', '' => '쪕', '' => '쪖', '' => '쪗', '' => '쪙', '' => '쪚', '' => '쪛', '' => '쪜', '' => '쪝', '' => '쪞', '' => '쪟', '' => '쪠', '' => '쪡', '' => '쪢', '' => '쪣', '' => '쪤', '' => '쪥', '' => '쪦', '' => '쪧', '' => 'ⅰ', '' => 'ⅱ', '' => 'ⅲ', '' => 'ⅳ', '' => 'ⅴ', '' => 'ⅵ', '' => 'ⅶ', '' => 'ⅷ', '' => 'ⅸ', '' => 'ⅹ', '' => 'Ⅰ', '' => 'Ⅱ', '' => 'Ⅲ', '' => 'Ⅳ', '' => 'Ⅴ', '' => 'Ⅵ', '' => 'Ⅶ', '' => 'Ⅷ', '' => 'Ⅸ', '' => 'Ⅹ', '' => 'Α', '' => 'Β', '' => 'Γ', '' => 'Δ', '' => 'Ε', '' => 'Ζ', '' => 'Η', '' => 'Θ', '' => 'Ι', '' => 'Κ', '' => 'Λ', '' => 'Μ', '' => 'Ν', '' => 'Ξ', '' => 'Ο', '' => 'Π', '' => 'Ρ', '' => 'Σ', '' => 'Τ', '' => 'Υ', '' => 'Φ', '' => 'Χ', '' => 'Ψ', '' => 'Ω', '' => 'α', '' => 'β', '' => 'γ', '' => 'δ', '' => 'ε', '' => 'ζ', '' => 'η', '' => 'θ', '' => 'ι', '' => 'κ', '' => 'λ', '' => 'μ', '' => 'ν', '' => 'ξ', '' => 'ο', '' => 'π', '' => 'ρ', '' => 'σ', '' => 'τ', '' => 'υ', '' => 'φ', '' => 'χ', '' => 'ψ', '' => 'ω', 'A' => '쪨', 'B' => '쪩', 'C' => '쪪', 'D' => '쪫', 'E' => '쪬', 'F' => '쪭', 'G' => '쪮', 'H' => '쪯', 'I' => '쪰', 'J' => '쪱', 'K' => '쪲', 'L' => '쪳', 'M' => '쪴', 'N' => '쪵', 'O' => '쪶', 'P' => '쪷', 'Q' => '쪸', 'R' => '쪹', 'S' => '쪺', 'T' => '쪻', 'U' => '쪾', 'V' => '쪿', 'W' => '쫁', 'X' => '쫂', 'Y' => '쫃', 'Z' => '쫅', 'a' => '쫆', 'b' => '쫇', 'c' => '쫈', 'd' => '쫉', 'e' => '쫊', 'f' => '쫋', 'g' => '쫎', 'h' => '쫐', 'i' => '쫒', 'j' => '쫔', 'k' => '쫕', 'l' => '쫖', 'm' => '쫗', 'n' => '쫚', 'o' => '쫛', 'p' => '쫜', 'q' => '쫝', 'r' => '쫞', 's' => '쫟', 't' => '쫡', 'u' => '쫢', 'v' => '쫣', 'w' => '쫤', 'x' => '쫥', 'y' => '쫦', 'z' => '쫧', '' => '쫨', '' => '쫩', '' => '쫪', '' => '쫫', '' => '쫭', '' => '쫮', '' => '쫯', '' => '쫰', '' => '쫱', '' => '쫲', '' => '쫳', '' => '쫵', '' => '쫶', '' => '쫷', '' => '쫸', '' => '쫹', '' => '쫺', '' => '쫻', '' => '쫼', '' => '쫽', '' => '쫾', '' => '쫿', '' => '쬀', '' => '쬁', '' => '쬂', '' => '쬃', '' => '쬄', '' => '쬅', '' => '쬆', '' => '쬇', '' => '쬉', '' => '쬊', '' => '─', '' => '│', '' => '┌', '' => '┐', '' => '┘', '' => '└', '' => '├', '' => '┬', '' => '┤', '' => '┴', '' => '┼', '' => '━', '' => '┃', '' => '┏', '' => '┓', '' => '┛', '' => '┗', '' => '┣', '' => '┳', '' => '┫', '' => '┻', '' => '╋', '' => '┠', '' => '┯', '' => '┨', '' => '┷', '' => '┿', '' => '┝', '' => '┰', '' => '┥', '' => '┸', '' => '╂', '' => '┒', '' => '┑', '' => '┚', '' => '┙', '' => '┖', '' => '┕', '' => '┎', '' => '┍', '' => '┞', '' => '┟', '' => '┡', '' => '┢', '' => '┦', '' => '┧', '' => '┩', '' => '┪', '' => '┭', '' => '┮', '' => '┱', '' => '┲', '' => '┵', '' => '┶', '' => '┹', '' => '┺', '' => '┽', '' => '┾', '' => '╀', '' => '╁', '' => '╃', '' => '╄', '' => '╅', '' => '╆', '' => '╇', '' => '╈', '' => '╉', '' => '╊', 'A' => '쬋', 'B' => '쬌', 'C' => '쬍', 'D' => '쬎', 'E' => '쬏', 'F' => '쬑', 'G' => '쬒', 'H' => '쬓', 'I' => '쬕', 'J' => '쬖', 'K' => '쬗', 'L' => '쬙', 'M' => '쬚', 'N' => '쬛', 'O' => '쬜', 'P' => '쬝', 'Q' => '쬞', 'R' => '쬟', 'S' => '쬢', 'T' => '쬣', 'U' => '쬤', 'V' => '쬥', 'W' => '쬦', 'X' => '쬧', 'Y' => '쬨', 'Z' => '쬩', 'a' => '쬪', 'b' => '쬫', 'c' => '쬬', 'd' => '쬭', 'e' => '쬮', 'f' => '쬯', 'g' => '쬰', 'h' => '쬱', 'i' => '쬲', 'j' => '쬳', 'k' => '쬴', 'l' => '쬵', 'm' => '쬶', 'n' => '쬷', 'o' => '쬸', 'p' => '쬹', 'q' => '쬺', 'r' => '쬻', 's' => '쬼', 't' => '쬽', 'u' => '쬾', 'v' => '쬿', 'w' => '쭀', 'x' => '쭂', 'y' => '쭃', 'z' => '쭄', '' => '쭅', '' => '쭆', '' => '쭇', '' => '쭊', '' => '쭋', '' => '쭍', '' => '쭎', '' => '쭏', '' => '쭑', '' => '쭒', '' => '쭓', '' => '쭔', '' => '쭕', '' => '쭖', '' => '쭗', '' => '쭚', '' => '쭛', '' => '쭜', '' => '쭞', '' => '쭟', '' => '쭠', '' => '쭡', '' => '쭢', '' => '쭣', '' => '쭥', '' => '쭦', '' => '쭧', '' => '쭨', '' => '쭩', '' => '쭪', '' => '쭫', '' => '쭬', '' => '㎕', '' => '㎖', '' => '㎗', '' => 'ℓ', '' => '㎘', '' => '㏄', '' => '㎣', '' => '㎤', '' => '㎥', '' => '㎦', '' => '㎙', '' => '㎚', '' => '㎛', '' => '㎜', '' => '㎝', '' => '㎞', '' => '㎟', '' => '㎠', '' => '㎡', '' => '㎢', '' => '㏊', '' => '㎍', '' => '㎎', '' => '㎏', '' => '㏏', '' => '㎈', '' => '㎉', '' => '㏈', '' => '㎧', '' => '㎨', '' => '㎰', '' => '㎱', '' => '㎲', '' => '㎳', '' => '㎴', '' => '㎵', '' => '㎶', '' => '㎷', '' => '㎸', '' => '㎹', '' => '㎀', '' => '㎁', '' => '㎂', '' => '㎃', '' => '㎄', '' => '㎺', '' => '㎻', '' => '㎼', '' => '㎽', '' => '㎾', '' => '㎿', '' => '㎐', '' => '㎑', '' => '㎒', '' => '㎓', '' => '㎔', '' => 'Ω', '' => '㏀', '' => '㏁', '' => '㎊', '' => '㎋', '' => '㎌', '' => '㏖', '' => '㏅', '' => '㎭', '' => '㎮', '' => '㎯', '' => '㏛', '' => '㎩', '' => '㎪', '' => '㎫', '' => '㎬', '' => '㏝', '' => '㏐', '' => '㏓', '' => '㏃', '' => '㏉', '' => '㏜', '' => '㏆', 'A' => '쭭', 'B' => '쭮', 'C' => '쭯', 'D' => '쭰', 'E' => '쭱', 'F' => '쭲', 'G' => '쭳', 'H' => '쭴', 'I' => '쭵', 'J' => '쭶', 'K' => '쭷', 'L' => '쭺', 'M' => '쭻', 'N' => '쭼', 'O' => '쭽', 'P' => '쭾', 'Q' => '쭿', 'R' => '쮀', 'S' => '쮁', 'T' => '쮂', 'U' => '쮃', 'V' => '쮄', 'W' => '쮅', 'X' => '쮆', 'Y' => '쮇', 'Z' => '쮈', 'a' => '쮉', 'b' => '쮊', 'c' => '쮋', 'd' => '쮌', 'e' => '쮍', 'f' => '쮎', 'g' => '쮏', 'h' => '쮐', 'i' => '쮑', 'j' => '쮒', 'k' => '쮓', 'l' => '쮔', 'm' => '쮕', 'n' => '쮖', 'o' => '쮗', 'p' => '쮘', 'q' => '쮙', 'r' => '쮚', 's' => '쮛', 't' => '쮝', 'u' => '쮞', 'v' => '쮟', 'w' => '쮠', 'x' => '쮡', 'y' => '쮢', 'z' => '쮣', '' => '쮤', '' => '쮥', '' => '쮦', '' => '쮧', '' => '쮨', '' => '쮩', '' => '쮪', '' => '쮫', '' => '쮬', '' => '쮭', '' => '쮮', '' => '쮯', '' => '쮰', '' => '쮱', '' => '쮲', '' => '쮳', '' => '쮴', '' => '쮵', '' => '쮶', '' => '쮷', '' => '쮹', '' => '쮺', '' => '쮻', '' => '쮼', '' => '쮽', '' => '쮾', '' => '쮿', '' => '쯀', '' => '쯁', '' => '쯂', '' => '쯃', '' => '쯄', '' => 'Æ', '' => 'Ð', '' => 'ª', '' => 'Ħ', '' => 'IJ', '' => 'Ŀ', '' => 'Ł', '' => 'Ø', '' => 'Œ', '' => 'º', '' => 'Þ', '' => 'Ŧ', '' => 'Ŋ', '' => '㉠', '' => '㉡', '' => '㉢', '' => '㉣', '' => '㉤', '' => '㉥', '' => '㉦', '' => '㉧', '' => '㉨', '' => '㉩', '' => '㉪', '' => '㉫', '' => '㉬', '' => '㉭', '' => '㉮', '' => '㉯', '' => '㉰', '' => '㉱', '' => '㉲', '' => '㉳', '' => '㉴', '' => '㉵', '' => '㉶', '' => '㉷', '' => '㉸', '' => '㉹', '' => '㉺', '' => '㉻', '' => 'ⓐ', '' => 'ⓑ', '' => 'ⓒ', '' => 'ⓓ', '' => 'ⓔ', '' => 'ⓕ', '' => 'ⓖ', '' => 'ⓗ', '' => 'ⓘ', '' => 'ⓙ', '' => 'ⓚ', '' => 'ⓛ', '' => 'ⓜ', '' => 'ⓝ', '' => 'ⓞ', '' => 'ⓟ', '' => 'ⓠ', '' => 'ⓡ', '' => 'ⓢ', '' => 'ⓣ', '' => 'ⓤ', '' => 'ⓥ', '' => 'ⓦ', '' => 'ⓧ', '' => 'ⓨ', '' => 'ⓩ', '' => '①', '' => '②', '' => '③', '' => '④', '' => '⑤', '' => '⑥', '' => '⑦', '' => '⑧', '' => '⑨', '' => '⑩', '' => '⑪', '' => '⑫', '' => '⑬', '' => '⑭', '' => '⑮', '' => '½', '' => '⅓', '' => '⅔', '' => '¼', '' => '¾', '' => '⅛', '' => '⅜', '' => '⅝', '' => '⅞', 'A' => '쯅', 'B' => '쯆', 'C' => '쯇', 'D' => '쯈', 'E' => '쯉', 'F' => '쯊', 'G' => '쯋', 'H' => '쯌', 'I' => '쯍', 'J' => '쯎', 'K' => '쯏', 'L' => '쯐', 'M' => '쯑', 'N' => '쯒', 'O' => '쯓', 'P' => '쯕', 'Q' => '쯖', 'R' => '쯗', 'S' => '쯘', 'T' => '쯙', 'U' => '쯚', 'V' => '쯛', 'W' => '쯜', 'X' => '쯝', 'Y' => '쯞', 'Z' => '쯟', 'a' => '쯠', 'b' => '쯡', 'c' => '쯢', 'd' => '쯣', 'e' => '쯥', 'f' => '쯦', 'g' => '쯨', 'h' => '쯪', 'i' => '쯫', 'j' => '쯬', 'k' => '쯭', 'l' => '쯮', 'm' => '쯯', 'n' => '쯰', 'o' => '쯱', 'p' => '쯲', 'q' => '쯳', 'r' => '쯴', 's' => '쯵', 't' => '쯶', 'u' => '쯷', 'v' => '쯸', 'w' => '쯹', 'x' => '쯺', 'y' => '쯻', 'z' => '쯼', '' => '쯽', '' => '쯾', '' => '쯿', '' => '찀', '' => '찁', '' => '찂', '' => '찃', '' => '찄', '' => '찅', '' => '찆', '' => '찇', '' => '찈', '' => '찉', '' => '찊', '' => '찋', '' => '찎', '' => '찏', '' => '찑', '' => '찒', '' => '찓', '' => '찕', '' => '찖', '' => '찗', '' => '찘', '' => '찙', '' => '찚', '' => '찛', '' => '찞', '' => '찟', '' => '찠', '' => '찣', '' => '찤', '' => 'æ', '' => 'đ', '' => 'ð', '' => 'ħ', '' => 'ı', '' => 'ij', '' => 'ĸ', '' => 'ŀ', '' => 'ł', '' => 'ø', '' => 'œ', '' => 'ß', '' => 'þ', '' => 'ŧ', '' => 'ŋ', '' => 'ʼn', '' => '㈀', '' => '㈁', '' => '㈂', '' => '㈃', '' => '㈄', '' => '㈅', '' => '㈆', '' => '㈇', '' => '㈈', '' => '㈉', '' => '㈊', '' => '㈋', '' => '㈌', '' => '㈍', '' => '㈎', '' => '㈏', '' => '㈐', '' => '㈑', '' => '㈒', '' => '㈓', '' => '㈔', '' => '㈕', '' => '㈖', '' => '㈗', '' => '㈘', '' => '㈙', '' => '㈚', '' => '㈛', '' => '⒜', '' => '⒝', '' => '⒞', '' => '⒟', '' => '⒠', '' => '⒡', '' => '⒢', '' => '⒣', '' => '⒤', '' => '⒥', '' => '⒦', '' => '⒧', '' => '⒨', '' => '⒩', '' => '⒪', '' => '⒫', '' => '⒬', '' => '⒭', '' => '⒮', '' => '⒯', '' => '⒰', '' => '⒱', '' => '⒲', '' => '⒳', '' => '⒴', '' => '⒵', '' => '⑴', '' => '⑵', '' => '⑶', '' => '⑷', '' => '⑸', '' => '⑹', '' => '⑺', '' => '⑻', '' => '⑼', '' => '⑽', '' => '⑾', '' => '⑿', '' => '⒀', '' => '⒁', '' => '⒂', '' => '¹', '' => '²', '' => '³', '' => '⁴', '' => 'ⁿ', '' => '₁', '' => '₂', '' => '₃', '' => '₄', 'A' => '찥', 'B' => '찦', 'C' => '찪', 'D' => '찫', 'E' => '찭', 'F' => '찯', 'G' => '찱', 'H' => '찲', 'I' => '찳', 'J' => '찴', 'K' => '찵', 'L' => '찶', 'M' => '찷', 'N' => '찺', 'O' => '찿', 'P' => '챀', 'Q' => '챁', 'R' => '챂', 'S' => '챃', 'T' => '챆', 'U' => '챇', 'V' => '챉', 'W' => '챊', 'X' => '챋', 'Y' => '챍', 'Z' => '챎', 'a' => '챏', 'b' => '챐', 'c' => '챑', 'd' => '챒', 'e' => '챓', 'f' => '챖', 'g' => '챚', 'h' => '챛', 'i' => '챜', 'j' => '챝', 'k' => '챞', 'l' => '챟', 'm' => '챡', 'n' => '챢', 'o' => '챣', 'p' => '챥', 'q' => '챧', 'r' => '챩', 's' => '챪', 't' => '챫', 'u' => '챬', 'v' => '챭', 'w' => '챮', 'x' => '챯', 'y' => '챱', 'z' => '챲', '' => '챳', '' => '챴', '' => '챶', '' => '챷', '' => '챸', '' => '챹', '' => '챺', '' => '챻', '' => '챼', '' => '챽', '' => '챾', '' => '챿', '' => '첀', '' => '첁', '' => '첂', '' => '첃', '' => '첄', '' => '첅', '' => '첆', '' => '첇', '' => '첈', '' => '첉', '' => '첊', '' => '첋', '' => '첌', '' => '첍', '' => '첎', '' => '첏', '' => '첐', '' => '첑', '' => '첒', '' => '첓', '' => 'ぁ', '' => 'あ', '' => 'ぃ', '' => 'い', '' => 'ぅ', '' => 'う', '' => 'ぇ', '' => 'え', '' => 'ぉ', '' => 'お', '' => 'か', '' => 'が', '' => 'き', '' => 'ぎ', '' => 'く', '' => 'ぐ', '' => 'け', '' => 'げ', '' => 'こ', '' => 'ご', '' => 'さ', '' => 'ざ', '' => 'し', '' => 'じ', '' => 'す', '' => 'ず', '' => 'せ', '' => 'ぜ', '' => 'そ', '' => 'ぞ', '' => 'た', '' => 'だ', '' => 'ち', '' => 'ぢ', '' => 'っ', '' => 'つ', '' => 'づ', '' => 'て', '' => 'で', '' => 'と', '' => 'ど', '' => 'な', '' => 'に', '' => 'ぬ', '' => 'ね', '' => 'の', '' => 'は', '' => 'ば', '' => 'ぱ', '' => 'ひ', '' => 'び', '' => 'ぴ', '' => 'ふ', '' => 'ぶ', '' => 'ぷ', '' => 'へ', '' => 'べ', '' => 'ぺ', '' => 'ほ', '' => 'ぼ', '' => 'ぽ', '' => 'ま', '' => 'み', '' => 'む', '' => 'め', '' => 'も', '' => 'ゃ', '' => 'や', '' => 'ゅ', '' => 'ゆ', '' => 'ょ', '' => 'よ', '' => 'ら', '' => 'り', '' => 'る', '' => 'れ', '' => 'ろ', '' => 'ゎ', '' => 'わ', '' => 'ゐ', '' => 'ゑ', '' => 'を', '' => 'ん', 'A' => '첔', 'B' => '첕', 'C' => '첖', 'D' => '첗', 'E' => '첚', 'F' => '첛', 'G' => '첝', 'H' => '첞', 'I' => '첟', 'J' => '첡', 'K' => '첢', 'L' => '첣', 'M' => '첤', 'N' => '첥', 'O' => '첦', 'P' => '첧', 'Q' => '첪', 'R' => '첮', 'S' => '첯', 'T' => '첰', 'U' => '첱', 'V' => '첲', 'W' => '첳', 'X' => '첶', 'Y' => '첷', 'Z' => '첹', 'a' => '첺', 'b' => '첻', 'c' => '첽', 'd' => '첾', 'e' => '첿', 'f' => '쳀', 'g' => '쳁', 'h' => '쳂', 'i' => '쳃', 'j' => '쳆', 'k' => '쳈', 'l' => '쳊', 'm' => '쳋', 'n' => '쳌', 'o' => '쳍', 'p' => '쳎', 'q' => '쳏', 'r' => '쳑', 's' => '쳒', 't' => '쳓', 'u' => '쳕', 'v' => '쳖', 'w' => '쳗', 'x' => '쳘', 'y' => '쳙', 'z' => '쳚', '' => '쳛', '' => '쳜', '' => '쳝', '' => '쳞', '' => '쳟', '' => '쳠', '' => '쳡', '' => '쳢', '' => '쳣', '' => '쳥', '' => '쳦', '' => '쳧', '' => '쳨', '' => '쳩', '' => '쳪', '' => '쳫', '' => '쳭', '' => '쳮', '' => '쳯', '' => '쳱', '' => '쳲', '' => '쳳', '' => '쳴', '' => '쳵', '' => '쳶', '' => '쳷', '' => '쳸', '' => '쳹', '' => '쳺', '' => '쳻', '' => '쳼', '' => '쳽', '' => 'ァ', '' => 'ア', '' => 'ィ', '' => 'イ', '' => 'ゥ', '' => 'ウ', '' => 'ェ', '' => 'エ', '' => 'ォ', '' => 'オ', '' => 'カ', '' => 'ガ', '' => 'キ', '' => 'ギ', '' => 'ク', '' => 'グ', '' => 'ケ', '' => 'ゲ', '' => 'コ', '' => 'ゴ', '' => 'サ', '' => 'ザ', '' => 'シ', '' => 'ジ', '' => 'ス', '' => 'ズ', '' => 'セ', '' => 'ゼ', '' => 'ソ', '' => 'ゾ', '' => 'タ', '' => 'ダ', '' => 'チ', '' => 'ヂ', '' => 'ッ', '' => 'ツ', '' => 'ヅ', '' => 'テ', '' => 'デ', '' => 'ト', '' => 'ド', '' => 'ナ', '' => 'ニ', '' => 'ヌ', '' => 'ネ', '' => 'ノ', '' => 'ハ', '' => 'バ', '' => 'パ', '' => 'ヒ', '' => 'ビ', '' => 'ピ', '' => 'フ', '' => 'ブ', '' => 'プ', '' => 'ヘ', '' => 'ベ', '' => 'ペ', '' => 'ホ', '' => 'ボ', '' => 'ポ', '' => 'マ', '' => 'ミ', '' => 'ム', '' => 'メ', '' => 'モ', '' => 'ャ', '' => 'ヤ', '' => 'ュ', '' => 'ユ', '' => 'ョ', '' => 'ヨ', '' => 'ラ', '' => 'リ', '' => 'ル', '' => 'レ', '' => 'ロ', '' => 'ヮ', '' => 'ワ', '' => 'ヰ', '' => 'ヱ', '' => 'ヲ', '' => 'ン', '' => 'ヴ', '' => 'ヵ', '' => 'ヶ', 'A' => '쳾', 'B' => '쳿', 'C' => '촀', 'D' => '촂', 'E' => '촃', 'F' => '촄', 'G' => '촅', 'H' => '촆', 'I' => '촇', 'J' => '촊', 'K' => '촋', 'L' => '촍', 'M' => '촎', 'N' => '촏', 'O' => '촑', 'P' => '촒', 'Q' => '촓', 'R' => '촔', 'S' => '촕', 'T' => '촖', 'U' => '촗', 'V' => '촚', 'W' => '촜', 'X' => '촞', 'Y' => '촟', 'Z' => '촠', 'a' => '촡', 'b' => '촢', 'c' => '촣', 'd' => '촥', 'e' => '촦', 'f' => '촧', 'g' => '촩', 'h' => '촪', 'i' => '촫', 'j' => '촭', 'k' => '촮', 'l' => '촯', 'm' => '촰', 'n' => '촱', 'o' => '촲', 'p' => '촳', 'q' => '촴', 'r' => '촵', 's' => '촶', 't' => '촷', 'u' => '촸', 'v' => '촺', 'w' => '촻', 'x' => '촼', 'y' => '촽', 'z' => '촾', '' => '촿', '' => '쵀', '' => '쵁', '' => '쵂', '' => '쵃', '' => '쵄', '' => '쵅', '' => '쵆', '' => '쵇', '' => '쵈', '' => '쵉', '' => '쵊', '' => '쵋', '' => '쵌', '' => '쵍', '' => '쵎', '' => '쵏', '' => '쵐', '' => '쵑', '' => '쵒', '' => '쵓', '' => '쵔', '' => '쵕', '' => '쵖', '' => '쵗', '' => '쵘', '' => '쵙', '' => '쵚', '' => '쵛', '' => '쵝', '' => '쵞', '' => '쵟', '' => 'А', '' => 'Б', '' => 'В', '' => 'Г', '' => 'Д', '' => 'Е', '' => 'Ё', '' => 'Ж', '' => 'З', '' => 'И', '' => 'Й', '' => 'К', '' => 'Л', '' => 'М', '' => 'Н', '' => 'О', '' => 'П', '' => 'Р', '' => 'С', '' => 'Т', '' => 'У', '' => 'Ф', '' => 'Х', '' => 'Ц', '' => 'Ч', '' => 'Ш', '' => 'Щ', '' => 'Ъ', '' => 'Ы', '' => 'Ь', '' => 'Э', '' => 'Ю', '' => 'Я', '' => 'а', '' => 'б', '' => 'в', '' => 'г', '' => 'д', '' => 'е', '' => 'ё', '' => 'ж', '' => 'з', '' => 'и', '' => 'й', '' => 'к', '' => 'л', '' => 'м', '' => 'н', '' => 'о', '' => 'п', '' => 'р', '' => 'с', '' => 'т', '' => 'у', '' => 'ф', '' => 'х', '' => 'ц', '' => 'ч', '' => 'ш', '' => 'щ', '' => 'ъ', '' => 'ы', '' => 'ь', '' => 'э', '' => 'ю', '' => 'я', 'A' => '쵡', 'B' => '쵢', 'C' => '쵣', 'D' => '쵥', 'E' => '쵦', 'F' => '쵧', 'G' => '쵨', 'H' => '쵩', 'I' => '쵪', 'J' => '쵫', 'K' => '쵮', 'L' => '쵰', 'M' => '쵲', 'N' => '쵳', 'O' => '쵴', 'P' => '쵵', 'Q' => '쵶', 'R' => '쵷', 'S' => '쵹', 'T' => '쵺', 'U' => '쵻', 'V' => '쵼', 'W' => '쵽', 'X' => '쵾', 'Y' => '쵿', 'Z' => '춀', 'a' => '춁', 'b' => '춂', 'c' => '춃', 'd' => '춄', 'e' => '춅', 'f' => '춆', 'g' => '춇', 'h' => '춉', 'i' => '춊', 'j' => '춋', 'k' => '춌', 'l' => '춍', 'm' => '춎', 'n' => '춏', 'o' => '춐', 'p' => '춑', 'q' => '춒', 'r' => '춓', 's' => '춖', 't' => '춗', 'u' => '춙', 'v' => '춚', 'w' => '춛', 'x' => '춝', 'y' => '춞', 'z' => '춟', '' => '춠', '' => '춡', '' => '춢', '' => '춣', '' => '춦', '' => '춨', '' => '춪', '' => '춫', '' => '춬', '' => '춭', '' => '춮', '' => '춯', '' => '춱', '' => '춲', '' => '춳', '' => '춴', '' => '춵', '' => '춶', '' => '춷', '' => '춸', '' => '춹', '' => '춺', '' => '춻', '' => '춼', '' => '춽', '' => '춾', '' => '춿', '' => '췀', '' => '췁', '' => '췂', '' => '췃', '' => '췅', 'A' => '췆', 'B' => '췇', 'C' => '췈', 'D' => '췉', 'E' => '췊', 'F' => '췋', 'G' => '췍', 'H' => '췎', 'I' => '췏', 'J' => '췑', 'K' => '췒', 'L' => '췓', 'M' => '췔', 'N' => '췕', 'O' => '췖', 'P' => '췗', 'Q' => '췘', 'R' => '췙', 'S' => '췚', 'T' => '췛', 'U' => '췜', 'V' => '췝', 'W' => '췞', 'X' => '췟', 'Y' => '췠', 'Z' => '췡', 'a' => '췢', 'b' => '췣', 'c' => '췤', 'd' => '췥', 'e' => '췦', 'f' => '췧', 'g' => '췩', 'h' => '췪', 'i' => '췫', 'j' => '췭', 'k' => '췮', 'l' => '췯', 'm' => '췱', 'n' => '췲', 'o' => '췳', 'p' => '췴', 'q' => '췵', 'r' => '췶', 's' => '췷', 't' => '췺', 'u' => '췼', 'v' => '췾', 'w' => '췿', 'x' => '츀', 'y' => '츁', 'z' => '츂', '' => '츃', '' => '츅', '' => '츆', '' => '츇', '' => '츉', '' => '츊', '' => '츋', '' => '츍', '' => '츎', '' => '츏', '' => '츐', '' => '츑', '' => '츒', '' => '츓', '' => '츕', '' => '츖', '' => '츗', '' => '츘', '' => '츚', '' => '츛', '' => '츜', '' => '츝', '' => '츞', '' => '츟', '' => '츢', '' => '츣', '' => '츥', '' => '츦', '' => '츧', '' => '츩', '' => '츪', '' => '츫', 'A' => '츬', 'B' => '츭', 'C' => '츮', 'D' => '츯', 'E' => '츲', 'F' => '츴', 'G' => '츶', 'H' => '츷', 'I' => '츸', 'J' => '츹', 'K' => '츺', 'L' => '츻', 'M' => '츼', 'N' => '츽', 'O' => '츾', 'P' => '츿', 'Q' => '칀', 'R' => '칁', 'S' => '칂', 'T' => '칃', 'U' => '칄', 'V' => '칅', 'W' => '칆', 'X' => '칇', 'Y' => '칈', 'Z' => '칉', 'a' => '칊', 'b' => '칋', 'c' => '칌', 'd' => '칍', 'e' => '칎', 'f' => '칏', 'g' => '칐', 'h' => '칑', 'i' => '칒', 'j' => '칓', 'k' => '칔', 'l' => '칕', 'm' => '칖', 'n' => '칗', 'o' => '칚', 'p' => '칛', 'q' => '칝', 'r' => '칞', 's' => '칢', 't' => '칣', 'u' => '칤', 'v' => '칥', 'w' => '칦', 'x' => '칧', 'y' => '칪', 'z' => '칬', '' => '칮', '' => '칯', '' => '칰', '' => '칱', '' => '칲', '' => '칳', '' => '칶', '' => '칷', '' => '칹', '' => '칺', '' => '칻', '' => '칽', '' => '칾', '' => '칿', '' => '캀', '' => '캁', '' => '캂', '' => '캃', '' => '캆', '' => '캈', '' => '캊', '' => '캋', '' => '캌', '' => '캍', '' => '캎', '' => '캏', '' => '캒', '' => '캓', '' => '캕', '' => '캖', '' => '캗', '' => '캙', 'A' => '캚', 'B' => '캛', 'C' => '캜', 'D' => '캝', 'E' => '캞', 'F' => '캟', 'G' => '캢', 'H' => '캦', 'I' => '캧', 'J' => '캨', 'K' => '캩', 'L' => '캪', 'M' => '캫', 'N' => '캮', 'O' => '캯', 'P' => '캰', 'Q' => '캱', 'R' => '캲', 'S' => '캳', 'T' => '캴', 'U' => '캵', 'V' => '캶', 'W' => '캷', 'X' => '캸', 'Y' => '캹', 'Z' => '캺', 'a' => '캻', 'b' => '캼', 'c' => '캽', 'd' => '캾', 'e' => '캿', 'f' => '컀', 'g' => '컂', 'h' => '컃', 'i' => '컄', 'j' => '컅', 'k' => '컆', 'l' => '컇', 'm' => '컈', 'n' => '컉', 'o' => '컊', 'p' => '컋', 'q' => '컌', 'r' => '컍', 's' => '컎', 't' => '컏', 'u' => '컐', 'v' => '컑', 'w' => '컒', 'x' => '컓', 'y' => '컔', 'z' => '컕', '' => '컖', '' => '컗', '' => '컘', '' => '컙', '' => '컚', '' => '컛', '' => '컜', '' => '컝', '' => '컞', '' => '컟', '' => '컠', '' => '컡', '' => '컢', '' => '컣', '' => '컦', '' => '컧', '' => '컩', '' => '컪', '' => '컭', '' => '컮', '' => '컯', '' => '컰', '' => '컱', '' => '컲', '' => '컳', '' => '컶', '' => '컺', '' => '컻', '' => '컼', '' => '컽', '' => '컾', '' => '컿', '' => '가', '' => '각', '' => '간', '' => '갇', '' => '갈', '' => '갉', '' => '갊', '' => '감', '' => '갑', '' => '값', '' => '갓', '' => '갔', '' => '강', '' => '갖', '' => '갗', '' => '같', '' => '갚', '' => '갛', '' => '개', '' => '객', '' => '갠', '' => '갤', '' => '갬', '' => '갭', '' => '갯', '' => '갰', '' => '갱', '' => '갸', '' => '갹', '' => '갼', '' => '걀', '' => '걋', '' => '걍', '' => '걔', '' => '걘', '' => '걜', '' => '거', '' => '걱', '' => '건', '' => '걷', '' => '걸', '' => '걺', '' => '검', '' => '겁', '' => '것', '' => '겄', '' => '겅', '' => '겆', '' => '겉', '' => '겊', '' => '겋', '' => '게', '' => '겐', '' => '겔', '' => '겜', '' => '겝', '' => '겟', '' => '겠', '' => '겡', '' => '겨', '' => '격', '' => '겪', '' => '견', '' => '겯', '' => '결', '' => '겸', '' => '겹', '' => '겻', '' => '겼', '' => '경', '' => '곁', '' => '계', '' => '곈', '' => '곌', '' => '곕', '' => '곗', '' => '고', '' => '곡', '' => '곤', '' => '곧', '' => '골', '' => '곪', '' => '곬', '' => '곯', '' => '곰', '' => '곱', '' => '곳', '' => '공', '' => '곶', '' => '과', '' => '곽', '' => '관', '' => '괄', '' => '괆', 'A' => '켂', 'B' => '켃', 'C' => '켅', 'D' => '켆', 'E' => '켇', 'F' => '켉', 'G' => '켊', 'H' => '켋', 'I' => '켌', 'J' => '켍', 'K' => '켎', 'L' => '켏', 'M' => '켒', 'N' => '켔', 'O' => '켖', 'P' => '켗', 'Q' => '켘', 'R' => '켙', 'S' => '켚', 'T' => '켛', 'U' => '켝', 'V' => '켞', 'W' => '켟', 'X' => '켡', 'Y' => '켢', 'Z' => '켣', 'a' => '켥', 'b' => '켦', 'c' => '켧', 'd' => '켨', 'e' => '켩', 'f' => '켪', 'g' => '켫', 'h' => '켮', 'i' => '켲', 'j' => '켳', 'k' => '켴', 'l' => '켵', 'm' => '켶', 'n' => '켷', 'o' => '켹', 'p' => '켺', 'q' => '켻', 'r' => '켼', 's' => '켽', 't' => '켾', 'u' => '켿', 'v' => '콀', 'w' => '콁', 'x' => '콂', 'y' => '콃', 'z' => '콄', '' => '콅', '' => '콆', '' => '콇', '' => '콈', '' => '콉', '' => '콊', '' => '콋', '' => '콌', '' => '콍', '' => '콎', '' => '콏', '' => '콐', '' => '콑', '' => '콒', '' => '콓', '' => '콖', '' => '콗', '' => '콙', '' => '콚', '' => '콛', '' => '콝', '' => '콞', '' => '콟', '' => '콠', '' => '콡', '' => '콢', '' => '콣', '' => '콦', '' => '콨', '' => '콪', '' => '콫', '' => '콬', '' => '괌', '' => '괍', '' => '괏', '' => '광', '' => '괘', '' => '괜', '' => '괠', '' => '괩', '' => '괬', '' => '괭', '' => '괴', '' => '괵', '' => '괸', '' => '괼', '' => '굄', '' => '굅', '' => '굇', '' => '굉', '' => '교', '' => '굔', '' => '굘', '' => '굡', '' => '굣', '' => '구', '' => '국', '' => '군', '' => '굳', '' => '굴', '' => '굵', '' => '굶', '' => '굻', '' => '굼', '' => '굽', '' => '굿', '' => '궁', '' => '궂', '' => '궈', '' => '궉', '' => '권', '' => '궐', '' => '궜', '' => '궝', '' => '궤', '' => '궷', '' => '귀', '' => '귁', '' => '귄', '' => '귈', '' => '귐', '' => '귑', '' => '귓', '' => '규', '' => '균', '' => '귤', '' => '그', '' => '극', '' => '근', '' => '귿', '' => '글', '' => '긁', '' => '금', '' => '급', '' => '긋', '' => '긍', '' => '긔', '' => '기', '' => '긱', '' => '긴', '' => '긷', '' => '길', '' => '긺', '' => '김', '' => '깁', '' => '깃', '' => '깅', '' => '깆', '' => '깊', '' => '까', '' => '깍', '' => '깎', '' => '깐', '' => '깔', '' => '깖', '' => '깜', '' => '깝', '' => '깟', '' => '깠', '' => '깡', '' => '깥', '' => '깨', '' => '깩', '' => '깬', '' => '깰', '' => '깸', 'A' => '콭', 'B' => '콮', 'C' => '콯', 'D' => '콲', 'E' => '콳', 'F' => '콵', 'G' => '콶', 'H' => '콷', 'I' => '콹', 'J' => '콺', 'K' => '콻', 'L' => '콼', 'M' => '콽', 'N' => '콾', 'O' => '콿', 'P' => '쾁', 'Q' => '쾂', 'R' => '쾃', 'S' => '쾄', 'T' => '쾆', 'U' => '쾇', 'V' => '쾈', 'W' => '쾉', 'X' => '쾊', 'Y' => '쾋', 'Z' => '쾍', 'a' => '쾎', 'b' => '쾏', 'c' => '쾐', 'd' => '쾑', 'e' => '쾒', 'f' => '쾓', 'g' => '쾔', 'h' => '쾕', 'i' => '쾖', 'j' => '쾗', 'k' => '쾘', 'l' => '쾙', 'm' => '쾚', 'n' => '쾛', 'o' => '쾜', 'p' => '쾝', 'q' => '쾞', 'r' => '쾟', 's' => '쾠', 't' => '쾢', 'u' => '쾣', 'v' => '쾤', 'w' => '쾥', 'x' => '쾦', 'y' => '쾧', 'z' => '쾩', '' => '쾪', '' => '쾫', '' => '쾬', '' => '쾭', '' => '쾮', '' => '쾯', '' => '쾱', '' => '쾲', '' => '쾳', '' => '쾴', '' => '쾵', '' => '쾶', '' => '쾷', '' => '쾸', '' => '쾹', '' => '쾺', '' => '쾻', '' => '쾼', '' => '쾽', '' => '쾾', '' => '쾿', '' => '쿀', '' => '쿁', '' => '쿂', '' => '쿃', '' => '쿅', '' => '쿆', '' => '쿇', '' => '쿈', '' => '쿉', '' => '쿊', '' => '쿋', '' => '깹', '' => '깻', '' => '깼', '' => '깽', '' => '꺄', '' => '꺅', '' => '꺌', '' => '꺼', '' => '꺽', '' => '꺾', '' => '껀', '' => '껄', '' => '껌', '' => '껍', '' => '껏', '' => '껐', '' => '껑', '' => '께', '' => '껙', '' => '껜', '' => '껨', '' => '껫', '' => '껭', '' => '껴', '' => '껸', '' => '껼', '' => '꼇', '' => '꼈', '' => '꼍', '' => '꼐', '' => '꼬', '' => '꼭', '' => '꼰', '' => '꼲', '' => '꼴', '' => '꼼', '' => '꼽', '' => '꼿', '' => '꽁', '' => '꽂', '' => '꽃', '' => '꽈', '' => '꽉', '' => '꽐', '' => '꽜', '' => '꽝', '' => '꽤', '' => '꽥', '' => '꽹', '' => '꾀', '' => '꾄', '' => '꾈', '' => '꾐', '' => '꾑', '' => '꾕', '' => '꾜', '' => '꾸', '' => '꾹', '' => '꾼', '' => '꿀', '' => '꿇', '' => '꿈', '' => '꿉', '' => '꿋', '' => '꿍', '' => '꿎', '' => '꿔', '' => '꿜', '' => '꿨', '' => '꿩', '' => '꿰', '' => '꿱', '' => '꿴', '' => '꿸', '' => '뀀', '' => '뀁', '' => '뀄', '' => '뀌', '' => '뀐', '' => '뀔', '' => '뀜', '' => '뀝', '' => '뀨', '' => '끄', '' => '끅', '' => '끈', '' => '끊', '' => '끌', '' => '끎', '' => '끓', '' => '끔', '' => '끕', '' => '끗', '' => '끙', 'A' => '쿌', 'B' => '쿍', 'C' => '쿎', 'D' => '쿏', 'E' => '쿐', 'F' => '쿑', 'G' => '쿒', 'H' => '쿓', 'I' => '쿔', 'J' => '쿕', 'K' => '쿖', 'L' => '쿗', 'M' => '쿘', 'N' => '쿙', 'O' => '쿚', 'P' => '쿛', 'Q' => '쿜', 'R' => '쿝', 'S' => '쿞', 'T' => '쿟', 'U' => '쿢', 'V' => '쿣', 'W' => '쿥', 'X' => '쿦', 'Y' => '쿧', 'Z' => '쿩', 'a' => '쿪', 'b' => '쿫', 'c' => '쿬', 'd' => '쿭', 'e' => '쿮', 'f' => '쿯', 'g' => '쿲', 'h' => '쿴', 'i' => '쿶', 'j' => '쿷', 'k' => '쿸', 'l' => '쿹', 'm' => '쿺', 'n' => '쿻', 'o' => '쿽', 'p' => '쿾', 'q' => '쿿', 'r' => '퀁', 's' => '퀂', 't' => '퀃', 'u' => '퀅', 'v' => '퀆', 'w' => '퀇', 'x' => '퀈', 'y' => '퀉', 'z' => '퀊', '' => '퀋', '' => '퀌', '' => '퀍', '' => '퀎', '' => '퀏', '' => '퀐', '' => '퀒', '' => '퀓', '' => '퀔', '' => '퀕', '' => '퀖', '' => '퀗', '' => '퀙', '' => '퀚', '' => '퀛', '' => '퀜', '' => '퀝', '' => '퀞', '' => '퀟', '' => '퀠', '' => '퀡', '' => '퀢', '' => '퀣', '' => '퀤', '' => '퀥', '' => '퀦', '' => '퀧', '' => '퀨', '' => '퀩', '' => '퀪', '' => '퀫', '' => '퀬', '' => '끝', '' => '끼', '' => '끽', '' => '낀', '' => '낄', '' => '낌', '' => '낍', '' => '낏', '' => '낑', '' => '나', '' => '낙', '' => '낚', '' => '난', '' => '낟', '' => '날', '' => '낡', '' => '낢', '' => '남', '' => '납', '' => '낫', '' => '났', '' => '낭', '' => '낮', '' => '낯', '' => '낱', '' => '낳', '' => '내', '' => '낵', '' => '낸', '' => '낼', '' => '냄', '' => '냅', '' => '냇', '' => '냈', '' => '냉', '' => '냐', '' => '냑', '' => '냔', '' => '냘', '' => '냠', '' => '냥', '' => '너', '' => '넉', '' => '넋', '' => '넌', '' => '널', '' => '넒', '' => '넓', '' => '넘', '' => '넙', '' => '넛', '' => '넜', '' => '넝', '' => '넣', '' => '네', '' => '넥', '' => '넨', '' => '넬', '' => '넴', '' => '넵', '' => '넷', '' => '넸', '' => '넹', '' => '녀', '' => '녁', '' => '년', '' => '녈', '' => '념', '' => '녑', '' => '녔', '' => '녕', '' => '녘', '' => '녜', '' => '녠', '' => '노', '' => '녹', '' => '논', '' => '놀', '' => '놂', '' => '놈', '' => '놉', '' => '놋', '' => '농', '' => '높', '' => '놓', '' => '놔', '' => '놘', '' => '놜', '' => '놨', '' => '뇌', '' => '뇐', '' => '뇔', '' => '뇜', '' => '뇝', 'A' => '퀮', 'B' => '퀯', 'C' => '퀰', 'D' => '퀱', 'E' => '퀲', 'F' => '퀳', 'G' => '퀶', 'H' => '퀷', 'I' => '퀹', 'J' => '퀺', 'K' => '퀻', 'L' => '퀽', 'M' => '퀾', 'N' => '퀿', 'O' => '큀', 'P' => '큁', 'Q' => '큂', 'R' => '큃', 'S' => '큆', 'T' => '큈', 'U' => '큊', 'V' => '큋', 'W' => '큌', 'X' => '큍', 'Y' => '큎', 'Z' => '큏', 'a' => '큑', 'b' => '큒', 'c' => '큓', 'd' => '큕', 'e' => '큖', 'f' => '큗', 'g' => '큙', 'h' => '큚', 'i' => '큛', 'j' => '큜', 'k' => '큝', 'l' => '큞', 'm' => '큟', 'n' => '큡', 'o' => '큢', 'p' => '큣', 'q' => '큤', 'r' => '큥', 's' => '큦', 't' => '큧', 'u' => '큨', 'v' => '큩', 'w' => '큪', 'x' => '큫', 'y' => '큮', 'z' => '큯', '' => '큱', '' => '큲', '' => '큳', '' => '큵', '' => '큶', '' => '큷', '' => '큸', '' => '큹', '' => '큺', '' => '큻', '' => '큾', '' => '큿', '' => '킀', '' => '킂', '' => '킃', '' => '킄', '' => '킅', '' => '킆', '' => '킇', '' => '킈', '' => '킉', '' => '킊', '' => '킋', '' => '킌', '' => '킍', '' => '킎', '' => '킏', '' => '킐', '' => '킑', '' => '킒', '' => '킓', '' => '킔', '' => '뇟', '' => '뇨', '' => '뇩', '' => '뇬', '' => '뇰', '' => '뇹', '' => '뇻', '' => '뇽', '' => '누', '' => '눅', '' => '눈', '' => '눋', '' => '눌', '' => '눔', '' => '눕', '' => '눗', '' => '눙', '' => '눠', '' => '눴', '' => '눼', '' => '뉘', '' => '뉜', '' => '뉠', '' => '뉨', '' => '뉩', '' => '뉴', '' => '뉵', '' => '뉼', '' => '늄', '' => '늅', '' => '늉', '' => '느', '' => '늑', '' => '는', '' => '늘', '' => '늙', '' => '늚', '' => '늠', '' => '늡', '' => '늣', '' => '능', '' => '늦', '' => '늪', '' => '늬', '' => '늰', '' => '늴', '' => '니', '' => '닉', '' => '닌', '' => '닐', '' => '닒', '' => '님', '' => '닙', '' => '닛', '' => '닝', '' => '닢', '' => '다', '' => '닥', '' => '닦', '' => '단', '' => '닫', '' => '달', '' => '닭', '' => '닮', '' => '닯', '' => '닳', '' => '담', '' => '답', '' => '닷', '' => '닸', '' => '당', '' => '닺', '' => '닻', '' => '닿', '' => '대', '' => '댁', '' => '댄', '' => '댈', '' => '댐', '' => '댑', '' => '댓', '' => '댔', '' => '댕', '' => '댜', '' => '더', '' => '덕', '' => '덖', '' => '던', '' => '덛', '' => '덜', '' => '덞', '' => '덟', '' => '덤', '' => '덥', 'A' => '킕', 'B' => '킖', 'C' => '킗', 'D' => '킘', 'E' => '킙', 'F' => '킚', 'G' => '킛', 'H' => '킜', 'I' => '킝', 'J' => '킞', 'K' => '킟', 'L' => '킠', 'M' => '킡', 'N' => '킢', 'O' => '킣', 'P' => '킦', 'Q' => '킧', 'R' => '킩', 'S' => '킪', 'T' => '킫', 'U' => '킭', 'V' => '킮', 'W' => '킯', 'X' => '킰', 'Y' => '킱', 'Z' => '킲', 'a' => '킳', 'b' => '킶', 'c' => '킸', 'd' => '킺', 'e' => '킻', 'f' => '킼', 'g' => '킽', 'h' => '킾', 'i' => '킿', 'j' => '탂', 'k' => '탃', 'l' => '탅', 'm' => '탆', 'n' => '탇', 'o' => '탊', 'p' => '탋', 'q' => '탌', 'r' => '탍', 's' => '탎', 't' => '탏', 'u' => '탒', 'v' => '탖', 'w' => '탗', 'x' => '탘', 'y' => '탙', 'z' => '탚', '' => '탛', '' => '탞', '' => '탟', '' => '탡', '' => '탢', '' => '탣', '' => '탥', '' => '탦', '' => '탧', '' => '탨', '' => '탩', '' => '탪', '' => '탫', '' => '탮', '' => '탲', '' => '탳', '' => '탴', '' => '탵', '' => '탶', '' => '탷', '' => '탹', '' => '탺', '' => '탻', '' => '탼', '' => '탽', '' => '탾', '' => '탿', '' => '턀', '' => '턁', '' => '턂', '' => '턃', '' => '턄', '' => '덧', '' => '덩', '' => '덫', '' => '덮', '' => '데', '' => '덱', '' => '덴', '' => '델', '' => '뎀', '' => '뎁', '' => '뎃', '' => '뎄', '' => '뎅', '' => '뎌', '' => '뎐', '' => '뎔', '' => '뎠', '' => '뎡', '' => '뎨', '' => '뎬', '' => '도', '' => '독', '' => '돈', '' => '돋', '' => '돌', '' => '돎', '' => '돐', '' => '돔', '' => '돕', '' => '돗', '' => '동', '' => '돛', '' => '돝', '' => '돠', '' => '돤', '' => '돨', '' => '돼', '' => '됐', '' => '되', '' => '된', '' => '될', '' => '됨', '' => '됩', '' => '됫', '' => '됴', '' => '두', '' => '둑', '' => '둔', '' => '둘', '' => '둠', '' => '둡', '' => '둣', '' => '둥', '' => '둬', '' => '뒀', '' => '뒈', '' => '뒝', '' => '뒤', '' => '뒨', '' => '뒬', '' => '뒵', '' => '뒷', '' => '뒹', '' => '듀', '' => '듄', '' => '듈', '' => '듐', '' => '듕', '' => '드', '' => '득', '' => '든', '' => '듣', '' => '들', '' => '듦', '' => '듬', '' => '듭', '' => '듯', '' => '등', '' => '듸', '' => '디', '' => '딕', '' => '딘', '' => '딛', '' => '딜', '' => '딤', '' => '딥', '' => '딧', '' => '딨', '' => '딩', '' => '딪', '' => '따', '' => '딱', '' => '딴', '' => '딸', 'A' => '턅', 'B' => '턆', 'C' => '턇', 'D' => '턈', 'E' => '턉', 'F' => '턊', 'G' => '턋', 'H' => '턌', 'I' => '턎', 'J' => '턏', 'K' => '턐', 'L' => '턑', 'M' => '턒', 'N' => '턓', 'O' => '턔', 'P' => '턕', 'Q' => '턖', 'R' => '턗', 'S' => '턘', 'T' => '턙', 'U' => '턚', 'V' => '턛', 'W' => '턜', 'X' => '턝', 'Y' => '턞', 'Z' => '턟', 'a' => '턠', 'b' => '턡', 'c' => '턢', 'd' => '턣', 'e' => '턤', 'f' => '턥', 'g' => '턦', 'h' => '턧', 'i' => '턨', 'j' => '턩', 'k' => '턪', 'l' => '턫', 'm' => '턬', 'n' => '턭', 'o' => '턮', 'p' => '턯', 'q' => '턲', 'r' => '턳', 's' => '턵', 't' => '턶', 'u' => '턷', 'v' => '턹', 'w' => '턻', 'x' => '턼', 'y' => '턽', 'z' => '턾', '' => '턿', '' => '텂', '' => '텆', '' => '텇', '' => '텈', '' => '텉', '' => '텊', '' => '텋', '' => '텎', '' => '텏', '' => '텑', '' => '텒', '' => '텓', '' => '텕', '' => '텖', '' => '텗', '' => '텘', '' => '텙', '' => '텚', '' => '텛', '' => '텞', '' => '텠', '' => '텢', '' => '텣', '' => '텤', '' => '텥', '' => '텦', '' => '텧', '' => '텩', '' => '텪', '' => '텫', '' => '텭', '' => '땀', '' => '땁', '' => '땃', '' => '땄', '' => '땅', '' => '땋', '' => '때', '' => '땍', '' => '땐', '' => '땔', '' => '땜', '' => '땝', '' => '땟', '' => '땠', '' => '땡', '' => '떠', '' => '떡', '' => '떤', '' => '떨', '' => '떪', '' => '떫', '' => '떰', '' => '떱', '' => '떳', '' => '떴', '' => '떵', '' => '떻', '' => '떼', '' => '떽', '' => '뗀', '' => '뗄', '' => '뗌', '' => '뗍', '' => '뗏', '' => '뗐', '' => '뗑', '' => '뗘', '' => '뗬', '' => '또', '' => '똑', '' => '똔', '' => '똘', '' => '똥', '' => '똬', '' => '똴', '' => '뙈', '' => '뙤', '' => '뙨', '' => '뚜', '' => '뚝', '' => '뚠', '' => '뚤', '' => '뚫', '' => '뚬', '' => '뚱', '' => '뛔', '' => '뛰', '' => '뛴', '' => '뛸', '' => '뜀', '' => '뜁', '' => '뜅', '' => '뜨', '' => '뜩', '' => '뜬', '' => '뜯', '' => '뜰', '' => '뜸', '' => '뜹', '' => '뜻', '' => '띄', '' => '띈', '' => '띌', '' => '띔', '' => '띕', '' => '띠', '' => '띤', '' => '띨', '' => '띰', '' => '띱', '' => '띳', '' => '띵', '' => '라', '' => '락', '' => '란', '' => '랄', '' => '람', '' => '랍', '' => '랏', '' => '랐', '' => '랑', '' => '랒', '' => '랖', '' => '랗', 'A' => '텮', 'B' => '텯', 'C' => '텰', 'D' => '텱', 'E' => '텲', 'F' => '텳', 'G' => '텴', 'H' => '텵', 'I' => '텶', 'J' => '텷', 'K' => '텸', 'L' => '텹', 'M' => '텺', 'N' => '텻', 'O' => '텽', 'P' => '텾', 'Q' => '텿', 'R' => '톀', 'S' => '톁', 'T' => '톂', 'U' => '톃', 'V' => '톅', 'W' => '톆', 'X' => '톇', 'Y' => '톉', 'Z' => '톊', 'a' => '톋', 'b' => '톌', 'c' => '톍', 'd' => '톎', 'e' => '톏', 'f' => '톐', 'g' => '톑', 'h' => '톒', 'i' => '톓', 'j' => '톔', 'k' => '톕', 'l' => '톖', 'm' => '톗', 'n' => '톘', 'o' => '톙', 'p' => '톚', 'q' => '톛', 'r' => '톜', 's' => '톝', 't' => '톞', 'u' => '톟', 'v' => '톢', 'w' => '톣', 'x' => '톥', 'y' => '톦', 'z' => '톧', '' => '톩', '' => '톪', '' => '톫', '' => '톬', '' => '톭', '' => '톮', '' => '톯', '' => '톲', '' => '톴', '' => '톶', '' => '톷', '' => '톸', '' => '톹', '' => '톻', '' => '톽', '' => '톾', '' => '톿', '' => '퇁', '' => '퇂', '' => '퇃', '' => '퇄', '' => '퇅', '' => '퇆', '' => '퇇', '' => '퇈', '' => '퇉', '' => '퇊', '' => '퇋', '' => '퇌', '' => '퇍', '' => '퇎', '' => '퇏', '' => '래', '' => '랙', '' => '랜', '' => '랠', '' => '램', '' => '랩', '' => '랫', '' => '랬', '' => '랭', '' => '랴', '' => '략', '' => '랸', '' => '럇', '' => '량', '' => '러', '' => '럭', '' => '런', '' => '럴', '' => '럼', '' => '럽', '' => '럿', '' => '렀', '' => '렁', '' => '렇', '' => '레', '' => '렉', '' => '렌', '' => '렐', '' => '렘', '' => '렙', '' => '렛', '' => '렝', '' => '려', '' => '력', '' => '련', '' => '렬', '' => '렴', '' => '렵', '' => '렷', '' => '렸', '' => '령', '' => '례', '' => '롄', '' => '롑', '' => '롓', '' => '로', '' => '록', '' => '론', '' => '롤', '' => '롬', '' => '롭', '' => '롯', '' => '롱', '' => '롸', '' => '롼', '' => '뢍', '' => '뢨', '' => '뢰', '' => '뢴', '' => '뢸', '' => '룀', '' => '룁', '' => '룃', '' => '룅', '' => '료', '' => '룐', '' => '룔', '' => '룝', '' => '룟', '' => '룡', '' => '루', '' => '룩', '' => '룬', '' => '룰', '' => '룸', '' => '룹', '' => '룻', '' => '룽', '' => '뤄', '' => '뤘', '' => '뤠', '' => '뤼', '' => '뤽', '' => '륀', '' => '륄', '' => '륌', '' => '륏', '' => '륑', '' => '류', '' => '륙', '' => '륜', '' => '률', '' => '륨', '' => '륩', 'A' => '퇐', 'B' => '퇑', 'C' => '퇒', 'D' => '퇓', 'E' => '퇔', 'F' => '퇕', 'G' => '퇖', 'H' => '퇗', 'I' => '퇙', 'J' => '퇚', 'K' => '퇛', 'L' => '퇜', 'M' => '퇝', 'N' => '퇞', 'O' => '퇟', 'P' => '퇠', 'Q' => '퇡', 'R' => '퇢', 'S' => '퇣', 'T' => '퇤', 'U' => '퇥', 'V' => '퇦', 'W' => '퇧', 'X' => '퇨', 'Y' => '퇩', 'Z' => '퇪', 'a' => '퇫', 'b' => '퇬', 'c' => '퇭', 'd' => '퇮', 'e' => '퇯', 'f' => '퇰', 'g' => '퇱', 'h' => '퇲', 'i' => '퇳', 'j' => '퇵', 'k' => '퇶', 'l' => '퇷', 'm' => '퇹', 'n' => '퇺', 'o' => '퇻', 'p' => '퇼', 'q' => '퇽', 'r' => '퇾', 's' => '퇿', 't' => '툀', 'u' => '툁', 'v' => '툂', 'w' => '툃', 'x' => '툄', 'y' => '툅', 'z' => '툆', '' => '툈', '' => '툊', '' => '툋', '' => '툌', '' => '툍', '' => '툎', '' => '툏', '' => '툑', '' => '툒', '' => '툓', '' => '툔', '' => '툕', '' => '툖', '' => '툗', '' => '툘', '' => '툙', '' => '툚', '' => '툛', '' => '툜', '' => '툝', '' => '툞', '' => '툟', '' => '툠', '' => '툡', '' => '툢', '' => '툣', '' => '툤', '' => '툥', '' => '툦', '' => '툧', '' => '툨', '' => '툩', '' => '륫', '' => '륭', '' => '르', '' => '륵', '' => '른', '' => '를', '' => '름', '' => '릅', '' => '릇', '' => '릉', '' => '릊', '' => '릍', '' => '릎', '' => '리', '' => '릭', '' => '린', '' => '릴', '' => '림', '' => '립', '' => '릿', '' => '링', '' => '마', '' => '막', '' => '만', '' => '많', '' => '맏', '' => '말', '' => '맑', '' => '맒', '' => '맘', '' => '맙', '' => '맛', '' => '망', '' => '맞', '' => '맡', '' => '맣', '' => '매', '' => '맥', '' => '맨', '' => '맬', '' => '맴', '' => '맵', '' => '맷', '' => '맸', '' => '맹', '' => '맺', '' => '먀', '' => '먁', '' => '먈', '' => '먕', '' => '머', '' => '먹', '' => '먼', '' => '멀', '' => '멂', '' => '멈', '' => '멉', '' => '멋', '' => '멍', '' => '멎', '' => '멓', '' => '메', '' => '멕', '' => '멘', '' => '멜', '' => '멤', '' => '멥', '' => '멧', '' => '멨', '' => '멩', '' => '며', '' => '멱', '' => '면', '' => '멸', '' => '몃', '' => '몄', '' => '명', '' => '몇', '' => '몌', '' => '모', '' => '목', '' => '몫', '' => '몬', '' => '몰', '' => '몲', '' => '몸', '' => '몹', '' => '못', '' => '몽', '' => '뫄', '' => '뫈', '' => '뫘', '' => '뫙', '' => '뫼', 'A' => '툪', 'B' => '툫', 'C' => '툮', 'D' => '툯', 'E' => '툱', 'F' => '툲', 'G' => '툳', 'H' => '툵', 'I' => '툶', 'J' => '툷', 'K' => '툸', 'L' => '툹', 'M' => '툺', 'N' => '툻', 'O' => '툾', 'P' => '퉀', 'Q' => '퉂', 'R' => '퉃', 'S' => '퉄', 'T' => '퉅', 'U' => '퉆', 'V' => '퉇', 'W' => '퉉', 'X' => '퉊', 'Y' => '퉋', 'Z' => '퉌', 'a' => '퉍', 'b' => '퉎', 'c' => '퉏', 'd' => '퉐', 'e' => '퉑', 'f' => '퉒', 'g' => '퉓', 'h' => '퉔', 'i' => '퉕', 'j' => '퉖', 'k' => '퉗', 'l' => '퉘', 'm' => '퉙', 'n' => '퉚', 'o' => '퉛', 'p' => '퉝', 'q' => '퉞', 'r' => '퉟', 's' => '퉠', 't' => '퉡', 'u' => '퉢', 'v' => '퉣', 'w' => '퉥', 'x' => '퉦', 'y' => '퉧', 'z' => '퉨', '' => '퉩', '' => '퉪', '' => '퉫', '' => '퉬', '' => '퉭', '' => '퉮', '' => '퉯', '' => '퉰', '' => '퉱', '' => '퉲', '' => '퉳', '' => '퉴', '' => '퉵', '' => '퉶', '' => '퉷', '' => '퉸', '' => '퉹', '' => '퉺', '' => '퉻', '' => '퉼', '' => '퉽', '' => '퉾', '' => '퉿', '' => '튂', '' => '튃', '' => '튅', '' => '튆', '' => '튇', '' => '튉', '' => '튊', '' => '튋', '' => '튌', '' => '묀', '' => '묄', '' => '묍', '' => '묏', '' => '묑', '' => '묘', '' => '묜', '' => '묠', '' => '묩', '' => '묫', '' => '무', '' => '묵', '' => '묶', '' => '문', '' => '묻', '' => '물', '' => '묽', '' => '묾', '' => '뭄', '' => '뭅', '' => '뭇', '' => '뭉', '' => '뭍', '' => '뭏', '' => '뭐', '' => '뭔', '' => '뭘', '' => '뭡', '' => '뭣', '' => '뭬', '' => '뮈', '' => '뮌', '' => '뮐', '' => '뮤', '' => '뮨', '' => '뮬', '' => '뮴', '' => '뮷', '' => '므', '' => '믄', '' => '믈', '' => '믐', '' => '믓', '' => '미', '' => '믹', '' => '민', '' => '믿', '' => '밀', '' => '밂', '' => '밈', '' => '밉', '' => '밋', '' => '밌', '' => '밍', '' => '및', '' => '밑', '' => '바', '' => '박', '' => '밖', '' => '밗', '' => '반', '' => '받', '' => '발', '' => '밝', '' => '밞', '' => '밟', '' => '밤', '' => '밥', '' => '밧', '' => '방', '' => '밭', '' => '배', '' => '백', '' => '밴', '' => '밸', '' => '뱀', '' => '뱁', '' => '뱃', '' => '뱄', '' => '뱅', '' => '뱉', '' => '뱌', '' => '뱍', '' => '뱐', '' => '뱝', '' => '버', '' => '벅', '' => '번', '' => '벋', '' => '벌', '' => '벎', '' => '범', '' => '법', '' => '벗', 'A' => '튍', 'B' => '튎', 'C' => '튏', 'D' => '튒', 'E' => '튓', 'F' => '튔', 'G' => '튖', 'H' => '튗', 'I' => '튘', 'J' => '튙', 'K' => '튚', 'L' => '튛', 'M' => '튝', 'N' => '튞', 'O' => '튟', 'P' => '튡', 'Q' => '튢', 'R' => '튣', 'S' => '튥', 'T' => '튦', 'U' => '튧', 'V' => '튨', 'W' => '튩', 'X' => '튪', 'Y' => '튫', 'Z' => '튭', 'a' => '튮', 'b' => '튯', 'c' => '튰', 'd' => '튲', 'e' => '튳', 'f' => '튴', 'g' => '튵', 'h' => '튶', 'i' => '튷', 'j' => '튺', 'k' => '튻', 'l' => '튽', 'm' => '튾', 'n' => '틁', 'o' => '틃', 'p' => '틄', 'q' => '틅', 'r' => '틆', 's' => '틇', 't' => '틊', 'u' => '틌', 'v' => '틍', 'w' => '틎', 'x' => '틏', 'y' => '틐', 'z' => '틑', '' => '틒', '' => '틓', '' => '틕', '' => '틖', '' => '틗', '' => '틙', '' => '틚', '' => '틛', '' => '틝', '' => '틞', '' => '틟', '' => '틠', '' => '틡', '' => '틢', '' => '틣', '' => '틦', '' => '틧', '' => '틨', '' => '틩', '' => '틪', '' => '틫', '' => '틬', '' => '틭', '' => '틮', '' => '틯', '' => '틲', '' => '틳', '' => '틵', '' => '틶', '' => '틷', '' => '틹', '' => '틺', '' => '벙', '' => '벚', '' => '베', '' => '벡', '' => '벤', '' => '벧', '' => '벨', '' => '벰', '' => '벱', '' => '벳', '' => '벴', '' => '벵', '' => '벼', '' => '벽', '' => '변', '' => '별', '' => '볍', '' => '볏', '' => '볐', '' => '병', '' => '볕', '' => '볘', '' => '볜', '' => '보', '' => '복', '' => '볶', '' => '본', '' => '볼', '' => '봄', '' => '봅', '' => '봇', '' => '봉', '' => '봐', '' => '봔', '' => '봤', '' => '봬', '' => '뵀', '' => '뵈', '' => '뵉', '' => '뵌', '' => '뵐', '' => '뵘', '' => '뵙', '' => '뵤', '' => '뵨', '' => '부', '' => '북', '' => '분', '' => '붇', '' => '불', '' => '붉', '' => '붊', '' => '붐', '' => '붑', '' => '붓', '' => '붕', '' => '붙', '' => '붚', '' => '붜', '' => '붤', '' => '붰', '' => '붸', '' => '뷔', '' => '뷕', '' => '뷘', '' => '뷜', '' => '뷩', '' => '뷰', '' => '뷴', '' => '뷸', '' => '븀', '' => '븃', '' => '븅', '' => '브', '' => '븍', '' => '븐', '' => '블', '' => '븜', '' => '븝', '' => '븟', '' => '비', '' => '빅', '' => '빈', '' => '빌', '' => '빎', '' => '빔', '' => '빕', '' => '빗', '' => '빙', '' => '빚', '' => '빛', '' => '빠', '' => '빡', '' => '빤', 'A' => '틻', 'B' => '틼', 'C' => '틽', 'D' => '틾', 'E' => '틿', 'F' => '팂', 'G' => '팄', 'H' => '팆', 'I' => '팇', 'J' => '팈', 'K' => '팉', 'L' => '팊', 'M' => '팋', 'N' => '팏', 'O' => '팑', 'P' => '팒', 'Q' => '팓', 'R' => '팕', 'S' => '팗', 'T' => '팘', 'U' => '팙', 'V' => '팚', 'W' => '팛', 'X' => '팞', 'Y' => '팢', 'Z' => '팣', 'a' => '팤', 'b' => '팦', 'c' => '팧', 'd' => '팪', 'e' => '팫', 'f' => '팭', 'g' => '팮', 'h' => '팯', 'i' => '팱', 'j' => '팲', 'k' => '팳', 'l' => '팴', 'm' => '팵', 'n' => '팶', 'o' => '팷', 'p' => '팺', 'q' => '팾', 'r' => '팿', 's' => '퍀', 't' => '퍁', 'u' => '퍂', 'v' => '퍃', 'w' => '퍆', 'x' => '퍇', 'y' => '퍈', 'z' => '퍉', '' => '퍊', '' => '퍋', '' => '퍌', '' => '퍍', '' => '퍎', '' => '퍏', '' => '퍐', '' => '퍑', '' => '퍒', '' => '퍓', '' => '퍔', '' => '퍕', '' => '퍖', '' => '퍗', '' => '퍘', '' => '퍙', '' => '퍚', '' => '퍛', '' => '퍜', '' => '퍝', '' => '퍞', '' => '퍟', '' => '퍠', '' => '퍡', '' => '퍢', '' => '퍣', '' => '퍤', '' => '퍥', '' => '퍦', '' => '퍧', '' => '퍨', '' => '퍩', '' => '빨', '' => '빪', '' => '빰', '' => '빱', '' => '빳', '' => '빴', '' => '빵', '' => '빻', '' => '빼', '' => '빽', '' => '뺀', '' => '뺄', '' => '뺌', '' => '뺍', '' => '뺏', '' => '뺐', '' => '뺑', '' => '뺘', '' => '뺙', '' => '뺨', '' => '뻐', '' => '뻑', '' => '뻔', '' => '뻗', '' => '뻘', '' => '뻠', '' => '뻣', '' => '뻤', '' => '뻥', '' => '뻬', '' => '뼁', '' => '뼈', '' => '뼉', '' => '뼘', '' => '뼙', '' => '뼛', '' => '뼜', '' => '뼝', '' => '뽀', '' => '뽁', '' => '뽄', '' => '뽈', '' => '뽐', '' => '뽑', '' => '뽕', '' => '뾔', '' => '뾰', '' => '뿅', '' => '뿌', '' => '뿍', '' => '뿐', '' => '뿔', '' => '뿜', '' => '뿟', '' => '뿡', '' => '쀼', '' => '쁑', '' => '쁘', '' => '쁜', '' => '쁠', '' => '쁨', '' => '쁩', '' => '삐', '' => '삑', '' => '삔', '' => '삘', '' => '삠', '' => '삡', '' => '삣', '' => '삥', '' => '사', '' => '삭', '' => '삯', '' => '산', '' => '삳', '' => '살', '' => '삵', '' => '삶', '' => '삼', '' => '삽', '' => '삿', '' => '샀', '' => '상', '' => '샅', '' => '새', '' => '색', '' => '샌', '' => '샐', '' => '샘', '' => '샙', '' => '샛', '' => '샜', '' => '생', '' => '샤', 'A' => '퍪', 'B' => '퍫', 'C' => '퍬', 'D' => '퍭', 'E' => '퍮', 'F' => '퍯', 'G' => '퍰', 'H' => '퍱', 'I' => '퍲', 'J' => '퍳', 'K' => '퍴', 'L' => '퍵', 'M' => '퍶', 'N' => '퍷', 'O' => '퍸', 'P' => '퍹', 'Q' => '퍺', 'R' => '퍻', 'S' => '퍾', 'T' => '퍿', 'U' => '펁', 'V' => '펂', 'W' => '펃', 'X' => '펅', 'Y' => '펆', 'Z' => '펇', 'a' => '펈', 'b' => '펉', 'c' => '펊', 'd' => '펋', 'e' => '펎', 'f' => '펒', 'g' => '펓', 'h' => '펔', 'i' => '펕', 'j' => '펖', 'k' => '펗', 'l' => '펚', 'm' => '펛', 'n' => '펝', 'o' => '펞', 'p' => '펟', 'q' => '펡', 'r' => '펢', 's' => '펣', 't' => '펤', 'u' => '펥', 'v' => '펦', 'w' => '펧', 'x' => '펪', 'y' => '펬', 'z' => '펮', '' => '펯', '' => '펰', '' => '펱', '' => '펲', '' => '펳', '' => '펵', '' => '펶', '' => '펷', '' => '펹', '' => '펺', '' => '펻', '' => '펽', '' => '펾', '' => '펿', '' => '폀', '' => '폁', '' => '폂', '' => '폃', '' => '폆', '' => '폇', '' => '폊', '' => '폋', '' => '폌', '' => '폍', '' => '폎', '' => '폏', '' => '폑', '' => '폒', '' => '폓', '' => '폔', '' => '폕', '' => '폖', '' => '샥', '' => '샨', '' => '샬', '' => '샴', '' => '샵', '' => '샷', '' => '샹', '' => '섀', '' => '섄', '' => '섈', '' => '섐', '' => '섕', '' => '서', '' => '석', '' => '섞', '' => '섟', '' => '선', '' => '섣', '' => '설', '' => '섦', '' => '섧', '' => '섬', '' => '섭', '' => '섯', '' => '섰', '' => '성', '' => '섶', '' => '세', '' => '섹', '' => '센', '' => '셀', '' => '셈', '' => '셉', '' => '셋', '' => '셌', '' => '셍', '' => '셔', '' => '셕', '' => '션', '' => '셜', '' => '셤', '' => '셥', '' => '셧', '' => '셨', '' => '셩', '' => '셰', '' => '셴', '' => '셸', '' => '솅', '' => '소', '' => '속', '' => '솎', '' => '손', '' => '솔', '' => '솖', '' => '솜', '' => '솝', '' => '솟', '' => '송', '' => '솥', '' => '솨', '' => '솩', '' => '솬', '' => '솰', '' => '솽', '' => '쇄', '' => '쇈', '' => '쇌', '' => '쇔', '' => '쇗', '' => '쇘', '' => '쇠', '' => '쇤', '' => '쇨', '' => '쇰', '' => '쇱', '' => '쇳', '' => '쇼', '' => '쇽', '' => '숀', '' => '숄', '' => '숌', '' => '숍', '' => '숏', '' => '숑', '' => '수', '' => '숙', '' => '순', '' => '숟', '' => '술', '' => '숨', '' => '숩', '' => '숫', '' => '숭', 'A' => '폗', 'B' => '폙', 'C' => '폚', 'D' => '폛', 'E' => '폜', 'F' => '폝', 'G' => '폞', 'H' => '폟', 'I' => '폠', 'J' => '폢', 'K' => '폤', 'L' => '폥', 'M' => '폦', 'N' => '폧', 'O' => '폨', 'P' => '폩', 'Q' => '폪', 'R' => '폫', 'S' => '폮', 'T' => '폯', 'U' => '폱', 'V' => '폲', 'W' => '폳', 'X' => '폵', 'Y' => '폶', 'Z' => '폷', 'a' => '폸', 'b' => '폹', 'c' => '폺', 'd' => '폻', 'e' => '폾', 'f' => '퐀', 'g' => '퐂', 'h' => '퐃', 'i' => '퐄', 'j' => '퐅', 'k' => '퐆', 'l' => '퐇', 'm' => '퐉', 'n' => '퐊', 'o' => '퐋', 'p' => '퐌', 'q' => '퐍', 'r' => '퐎', 's' => '퐏', 't' => '퐐', 'u' => '퐑', 'v' => '퐒', 'w' => '퐓', 'x' => '퐔', 'y' => '퐕', 'z' => '퐖', '' => '퐗', '' => '퐘', '' => '퐙', '' => '퐚', '' => '퐛', '' => '퐜', '' => '퐞', '' => '퐟', '' => '퐠', '' => '퐡', '' => '퐢', '' => '퐣', '' => '퐤', '' => '퐥', '' => '퐦', '' => '퐧', '' => '퐨', '' => '퐩', '' => '퐪', '' => '퐫', '' => '퐬', '' => '퐭', '' => '퐮', '' => '퐯', '' => '퐰', '' => '퐱', '' => '퐲', '' => '퐳', '' => '퐴', '' => '퐵', '' => '퐶', '' => '퐷', '' => '숯', '' => '숱', '' => '숲', '' => '숴', '' => '쉈', '' => '쉐', '' => '쉑', '' => '쉔', '' => '쉘', '' => '쉠', '' => '쉥', '' => '쉬', '' => '쉭', '' => '쉰', '' => '쉴', '' => '쉼', '' => '쉽', '' => '쉿', '' => '슁', '' => '슈', '' => '슉', '' => '슐', '' => '슘', '' => '슛', '' => '슝', '' => '스', '' => '슥', '' => '슨', '' => '슬', '' => '슭', '' => '슴', '' => '습', '' => '슷', '' => '승', '' => '시', '' => '식', '' => '신', '' => '싣', '' => '실', '' => '싫', '' => '심', '' => '십', '' => '싯', '' => '싱', '' => '싶', '' => '싸', '' => '싹', '' => '싻', '' => '싼', '' => '쌀', '' => '쌈', '' => '쌉', '' => '쌌', '' => '쌍', '' => '쌓', '' => '쌔', '' => '쌕', '' => '쌘', '' => '쌜', '' => '쌤', '' => '쌥', '' => '쌨', '' => '쌩', '' => '썅', '' => '써', '' => '썩', '' => '썬', '' => '썰', '' => '썲', '' => '썸', '' => '썹', '' => '썼', '' => '썽', '' => '쎄', '' => '쎈', '' => '쎌', '' => '쏀', '' => '쏘', '' => '쏙', '' => '쏜', '' => '쏟', '' => '쏠', '' => '쏢', '' => '쏨', '' => '쏩', '' => '쏭', '' => '쏴', '' => '쏵', '' => '쏸', '' => '쐈', '' => '쐐', '' => '쐤', '' => '쐬', '' => '쐰', 'A' => '퐸', 'B' => '퐹', 'C' => '퐺', 'D' => '퐻', 'E' => '퐼', 'F' => '퐽', 'G' => '퐾', 'H' => '퐿', 'I' => '푁', 'J' => '푂', 'K' => '푃', 'L' => '푅', 'M' => '푆', 'N' => '푇', 'O' => '푈', 'P' => '푉', 'Q' => '푊', 'R' => '푋', 'S' => '푌', 'T' => '푍', 'U' => '푎', 'V' => '푏', 'W' => '푐', 'X' => '푑', 'Y' => '푒', 'Z' => '푓', 'a' => '푔', 'b' => '푕', 'c' => '푖', 'd' => '푗', 'e' => '푘', 'f' => '푙', 'g' => '푚', 'h' => '푛', 'i' => '푝', 'j' => '푞', 'k' => '푟', 'l' => '푡', 'm' => '푢', 'n' => '푣', 'o' => '푥', 'p' => '푦', 'q' => '푧', 'r' => '푨', 's' => '푩', 't' => '푪', 'u' => '푫', 'v' => '푬', 'w' => '푮', 'x' => '푰', 'y' => '푱', 'z' => '푲', '' => '푳', '' => '푴', '' => '푵', '' => '푶', '' => '푷', '' => '푺', '' => '푻', '' => '푽', '' => '푾', '' => '풁', '' => '풃', '' => '풄', '' => '풅', '' => '풆', '' => '풇', '' => '풊', '' => '풌', '' => '풎', '' => '풏', '' => '풐', '' => '풑', '' => '풒', '' => '풓', '' => '풕', '' => '풖', '' => '풗', '' => '풘', '' => '풙', '' => '풚', '' => '풛', '' => '풜', '' => '풝', '' => '쐴', '' => '쐼', '' => '쐽', '' => '쑈', '' => '쑤', '' => '쑥', '' => '쑨', '' => '쑬', '' => '쑴', '' => '쑵', '' => '쑹', '' => '쒀', '' => '쒔', '' => '쒜', '' => '쒸', '' => '쒼', '' => '쓩', '' => '쓰', '' => '쓱', '' => '쓴', '' => '쓸', '' => '쓺', '' => '쓿', '' => '씀', '' => '씁', '' => '씌', '' => '씐', '' => '씔', '' => '씜', '' => '씨', '' => '씩', '' => '씬', '' => '씰', '' => '씸', '' => '씹', '' => '씻', '' => '씽', '' => '아', '' => '악', '' => '안', '' => '앉', '' => '않', '' => '알', '' => '앍', '' => '앎', '' => '앓', '' => '암', '' => '압', '' => '앗', '' => '았', '' => '앙', '' => '앝', '' => '앞', '' => '애', '' => '액', '' => '앤', '' => '앨', '' => '앰', '' => '앱', '' => '앳', '' => '앴', '' => '앵', '' => '야', '' => '약', '' => '얀', '' => '얄', '' => '얇', '' => '얌', '' => '얍', '' => '얏', '' => '양', '' => '얕', '' => '얗', '' => '얘', '' => '얜', '' => '얠', '' => '얩', '' => '어', '' => '억', '' => '언', '' => '얹', '' => '얻', '' => '얼', '' => '얽', '' => '얾', '' => '엄', '' => '업', '' => '없', '' => '엇', '' => '었', '' => '엉', '' => '엊', '' => '엌', '' => '엎', 'A' => '풞', 'B' => '풟', 'C' => '풠', 'D' => '풡', 'E' => '풢', 'F' => '풣', 'G' => '풤', 'H' => '풥', 'I' => '풦', 'J' => '풧', 'K' => '풨', 'L' => '풪', 'M' => '풫', 'N' => '풬', 'O' => '풭', 'P' => '풮', 'Q' => '풯', 'R' => '풰', 'S' => '풱', 'T' => '풲', 'U' => '풳', 'V' => '풴', 'W' => '풵', 'X' => '풶', 'Y' => '풷', 'Z' => '풸', 'a' => '풹', 'b' => '풺', 'c' => '풻', 'd' => '풼', 'e' => '풽', 'f' => '풾', 'g' => '풿', 'h' => '퓀', 'i' => '퓁', 'j' => '퓂', 'k' => '퓃', 'l' => '퓄', 'm' => '퓅', 'n' => '퓆', 'o' => '퓇', 'p' => '퓈', 'q' => '퓉', 'r' => '퓊', 's' => '퓋', 't' => '퓍', 'u' => '퓎', 'v' => '퓏', 'w' => '퓑', 'x' => '퓒', 'y' => '퓓', 'z' => '퓕', '' => '퓖', '' => '퓗', '' => '퓘', '' => '퓙', '' => '퓚', '' => '퓛', '' => '퓝', '' => '퓞', '' => '퓠', '' => '퓡', '' => '퓢', '' => '퓣', '' => '퓤', '' => '퓥', '' => '퓦', '' => '퓧', '' => '퓩', '' => '퓪', '' => '퓫', '' => '퓭', '' => '퓮', '' => '퓯', '' => '퓱', '' => '퓲', '' => '퓳', '' => '퓴', '' => '퓵', '' => '퓶', '' => '퓷', '' => '퓹', '' => '퓺', '' => '퓼', '' => '에', '' => '엑', '' => '엔', '' => '엘', '' => '엠', '' => '엡', '' => '엣', '' => '엥', '' => '여', '' => '역', '' => '엮', '' => '연', '' => '열', '' => '엶', '' => '엷', '' => '염', '' => '엽', '' => '엾', '' => '엿', '' => '였', '' => '영', '' => '옅', '' => '옆', '' => '옇', '' => '예', '' => '옌', '' => '옐', '' => '옘', '' => '옙', '' => '옛', '' => '옜', '' => '오', '' => '옥', '' => '온', '' => '올', '' => '옭', '' => '옮', '' => '옰', '' => '옳', '' => '옴', '' => '옵', '' => '옷', '' => '옹', '' => '옻', '' => '와', '' => '왁', '' => '완', '' => '왈', '' => '왐', '' => '왑', '' => '왓', '' => '왔', '' => '왕', '' => '왜', '' => '왝', '' => '왠', '' => '왬', '' => '왯', '' => '왱', '' => '외', '' => '왹', '' => '왼', '' => '욀', '' => '욈', '' => '욉', '' => '욋', '' => '욍', '' => '요', '' => '욕', '' => '욘', '' => '욜', '' => '욤', '' => '욥', '' => '욧', '' => '용', '' => '우', '' => '욱', '' => '운', '' => '울', '' => '욹', '' => '욺', '' => '움', '' => '웁', '' => '웃', '' => '웅', '' => '워', '' => '웍', '' => '원', '' => '월', '' => '웜', '' => '웝', '' => '웠', '' => '웡', '' => '웨', 'A' => '퓾', 'B' => '퓿', 'C' => '픀', 'D' => '픁', 'E' => '픂', 'F' => '픃', 'G' => '픅', 'H' => '픆', 'I' => '픇', 'J' => '픉', 'K' => '픊', 'L' => '픋', 'M' => '픍', 'N' => '픎', 'O' => '픏', 'P' => '픐', 'Q' => '픑', 'R' => '픒', 'S' => '픓', 'T' => '픖', 'U' => '픘', 'V' => '픙', 'W' => '픚', 'X' => '픛', 'Y' => '픜', 'Z' => '픝', 'a' => '픞', 'b' => '픟', 'c' => '픠', 'd' => '픡', 'e' => '픢', 'f' => '픣', 'g' => '픤', 'h' => '픥', 'i' => '픦', 'j' => '픧', 'k' => '픨', 'l' => '픩', 'm' => '픪', 'n' => '픫', 'o' => '픬', 'p' => '픭', 'q' => '픮', 'r' => '픯', 's' => '픰', 't' => '픱', 'u' => '픲', 'v' => '픳', 'w' => '픴', 'x' => '픵', 'y' => '픶', 'z' => '픷', '' => '픸', '' => '픹', '' => '픺', '' => '픻', '' => '픾', '' => '픿', '' => '핁', '' => '핂', '' => '핃', '' => '핅', '' => '핆', '' => '핇', '' => '핈', '' => '핉', '' => '핊', '' => '핋', '' => '핎', '' => '핐', '' => '핒', '' => '핓', '' => '핔', '' => '핕', '' => '핖', '' => '핗', '' => '핚', '' => '핛', '' => '핝', '' => '핞', '' => '핟', '' => '핡', '' => '핢', '' => '핣', '' => '웩', '' => '웬', '' => '웰', '' => '웸', '' => '웹', '' => '웽', '' => '위', '' => '윅', '' => '윈', '' => '윌', '' => '윔', '' => '윕', '' => '윗', '' => '윙', '' => '유', '' => '육', '' => '윤', '' => '율', '' => '윰', '' => '윱', '' => '윳', '' => '융', '' => '윷', '' => '으', '' => '윽', '' => '은', '' => '을', '' => '읊', '' => '음', '' => '읍', '' => '읏', '' => '응', '' => '읒', '' => '읓', '' => '읔', '' => '읕', '' => '읖', '' => '읗', '' => '의', '' => '읜', '' => '읠', '' => '읨', '' => '읫', '' => '이', '' => '익', '' => '인', '' => '일', '' => '읽', '' => '읾', '' => '잃', '' => '임', '' => '입', '' => '잇', '' => '있', '' => '잉', '' => '잊', '' => '잎', '' => '자', '' => '작', '' => '잔', '' => '잖', '' => '잗', '' => '잘', '' => '잚', '' => '잠', '' => '잡', '' => '잣', '' => '잤', '' => '장', '' => '잦', '' => '재', '' => '잭', '' => '잰', '' => '잴', '' => '잼', '' => '잽', '' => '잿', '' => '쟀', '' => '쟁', '' => '쟈', '' => '쟉', '' => '쟌', '' => '쟎', '' => '쟐', '' => '쟘', '' => '쟝', '' => '쟤', '' => '쟨', '' => '쟬', '' => '저', '' => '적', '' => '전', '' => '절', '' => '젊', 'A' => '핤', 'B' => '핦', 'C' => '핧', 'D' => '핪', 'E' => '핬', 'F' => '핮', 'G' => '핯', 'H' => '핰', 'I' => '핱', 'J' => '핲', 'K' => '핳', 'L' => '핶', 'M' => '핷', 'N' => '핹', 'O' => '핺', 'P' => '핻', 'Q' => '핽', 'R' => '핾', 'S' => '핿', 'T' => '햀', 'U' => '햁', 'V' => '햂', 'W' => '햃', 'X' => '햆', 'Y' => '햊', 'Z' => '햋', 'a' => '햌', 'b' => '햍', 'c' => '햎', 'd' => '햏', 'e' => '햑', 'f' => '햒', 'g' => '햓', 'h' => '햔', 'i' => '햕', 'j' => '햖', 'k' => '햗', 'l' => '햘', 'm' => '햙', 'n' => '햚', 'o' => '햛', 'p' => '햜', 'q' => '햝', 'r' => '햞', 's' => '햟', 't' => '햠', 'u' => '햡', 'v' => '햢', 'w' => '햣', 'x' => '햤', 'y' => '햦', 'z' => '햧', '' => '햨', '' => '햩', '' => '햪', '' => '햫', '' => '햬', '' => '햭', '' => '햮', '' => '햯', '' => '햰', '' => '햱', '' => '햲', '' => '햳', '' => '햴', '' => '햵', '' => '햶', '' => '햷', '' => '햸', '' => '햹', '' => '햺', '' => '햻', '' => '햼', '' => '햽', '' => '햾', '' => '햿', '' => '헀', '' => '헁', '' => '헂', '' => '헃', '' => '헄', '' => '헅', '' => '헆', '' => '헇', '' => '점', '' => '접', '' => '젓', '' => '정', '' => '젖', '' => '제', '' => '젝', '' => '젠', '' => '젤', '' => '젬', '' => '젭', '' => '젯', '' => '젱', '' => '져', '' => '젼', '' => '졀', '' => '졈', '' => '졉', '' => '졌', '' => '졍', '' => '졔', '' => '조', '' => '족', '' => '존', '' => '졸', '' => '졺', '' => '좀', '' => '좁', '' => '좃', '' => '종', '' => '좆', '' => '좇', '' => '좋', '' => '좌', '' => '좍', '' => '좔', '' => '좝', '' => '좟', '' => '좡', '' => '좨', '' => '좼', '' => '좽', '' => '죄', '' => '죈', '' => '죌', '' => '죔', '' => '죕', '' => '죗', '' => '죙', '' => '죠', '' => '죡', '' => '죤', '' => '죵', '' => '주', '' => '죽', '' => '준', '' => '줄', '' => '줅', '' => '줆', '' => '줌', '' => '줍', '' => '줏', '' => '중', '' => '줘', '' => '줬', '' => '줴', '' => '쥐', '' => '쥑', '' => '쥔', '' => '쥘', '' => '쥠', '' => '쥡', '' => '쥣', '' => '쥬', '' => '쥰', '' => '쥴', '' => '쥼', '' => '즈', '' => '즉', '' => '즌', '' => '즐', '' => '즘', '' => '즙', '' => '즛', '' => '증', '' => '지', '' => '직', '' => '진', '' => '짇', '' => '질', '' => '짊', '' => '짐', '' => '집', '' => '짓', 'A' => '헊', 'B' => '헋', 'C' => '헍', 'D' => '헎', 'E' => '헏', 'F' => '헑', 'G' => '헓', 'H' => '헔', 'I' => '헕', 'J' => '헖', 'K' => '헗', 'L' => '헚', 'M' => '헜', 'N' => '헞', 'O' => '헟', 'P' => '헠', 'Q' => '헡', 'R' => '헢', 'S' => '헣', 'T' => '헦', 'U' => '헧', 'V' => '헩', 'W' => '헪', 'X' => '헫', 'Y' => '헭', 'Z' => '헮', 'a' => '헯', 'b' => '헰', 'c' => '헱', 'd' => '헲', 'e' => '헳', 'f' => '헶', 'g' => '헸', 'h' => '헺', 'i' => '헻', 'j' => '헼', 'k' => '헽', 'l' => '헾', 'm' => '헿', 'n' => '혂', 'o' => '혃', 'p' => '혅', 'q' => '혆', 'r' => '혇', 's' => '혉', 't' => '혊', 'u' => '혋', 'v' => '혌', 'w' => '혍', 'x' => '혎', 'y' => '혏', 'z' => '혒', '' => '혖', '‚' => '혗', 'ƒ' => '혘', '„' => '혙', '…' => '혚', '†' => '혛', '‡' => '혝', 'ˆ' => '혞', '‰' => '혟', 'Š' => '혡', '‹' => '혢', 'Œ' => '혣', '' => '혥', 'Ž' => '혦', '' => '혧', '' => '혨', '‘' => '혩', '’' => '혪', '“' => '혫', '”' => '혬', '•' => '혮', '–' => '혯', '—' => '혰', '˜' => '혱', '™' => '혲', 'š' => '혳', '›' => '혴', 'œ' => '혵', '' => '혶', 'ž' => '혷', 'Ÿ' => '혺', ' ' => '혻', '¡' => '징', '¢' => '짖', '£' => '짙', '¤' => '짚', '¥' => '짜', '¦' => '짝', '§' => '짠', '¨' => '짢', '©' => '짤', 'ª' => '짧', '«' => '짬', '¬' => '짭', '­' => '짯', '®' => '짰', '¯' => '짱', '°' => '째', '±' => '짹', '²' => '짼', '³' => '쨀', '´' => '쨈', 'µ' => '쨉', '¶' => '쨋', '·' => '쨌', '¸' => '쨍', '¹' => '쨔', 'º' => '쨘', '»' => '쨩', '¼' => '쩌', '½' => '쩍', '¾' => '쩐', '¿' => '쩔', '' => '쩜', '' => '쩝', '' => '쩟', '' => '쩠', '' => '쩡', '' => '쩨', '' => '쩽', '' => '쪄', '' => '쪘', '' => '쪼', '' => '쪽', '' => '쫀', '' => '쫄', '' => '쫌', '' => '쫍', '' => '쫏', '' => '쫑', '' => '쫓', '' => '쫘', '' => '쫙', '' => '쫠', '' => '쫬', '' => '쫴', '' => '쬈', '' => '쬐', '' => '쬔', '' => '쬘', '' => '쬠', '' => '쬡', '' => '쭁', '' => '쭈', '' => '쭉', '' => '쭌', '' => '쭐', '' => '쭘', '' => '쭙', '' => '쭝', '' => '쭤', '' => '쭸', '' => '쭹', '' => '쮜', '' => '쮸', '' => '쯔', '' => '쯤', '' => '쯧', '' => '쯩', '' => '찌', '' => '찍', '' => '찐', '' => '찔', '' => '찜', '' => '찝', '' => '찡', '' => '찢', '' => '찧', '' => '차', '' => '착', '' => '찬', '' => '찮', '' => '찰', '' => '참', '' => '찹', '' => '찻', 'A' => '혽', 'B' => '혾', 'C' => '혿', 'D' => '홁', 'E' => '홂', 'F' => '홃', 'G' => '홄', 'H' => '홆', 'I' => '홇', 'J' => '홊', 'K' => '홌', 'L' => '홎', 'M' => '홏', 'N' => '홐', 'O' => '홒', 'P' => '홓', 'Q' => '홖', 'R' => '홗', 'S' => '홙', 'T' => '홚', 'U' => '홛', 'V' => '홝', 'W' => '홞', 'X' => '홟', 'Y' => '홠', 'Z' => '홡', 'a' => '홢', 'b' => '홣', 'c' => '홤', 'd' => '홥', 'e' => '홦', 'f' => '홨', 'g' => '홪', 'h' => '홫', 'i' => '홬', 'j' => '홭', 'k' => '홮', 'l' => '홯', 'm' => '홲', 'n' => '홳', 'o' => '홵', 'p' => '홶', 'q' => '홷', 'r' => '홸', 's' => '홹', 't' => '홺', 'u' => '홻', 'v' => '홼', 'w' => '홽', 'x' => '홾', 'y' => '홿', 'z' => '횀', 'Á' => '횁', 'Â' => '횂', 'Ã' => '횄', 'Ä' => '횆', 'Å' => '횇', 'Æ' => '횈', 'Ç' => '횉', 'È' => '횊', 'É' => '횋', 'Ê' => '횎', 'Ë' => '횏', 'Ì' => '횑', 'Í' => '횒', 'Î' => '횓', 'Ï' => '횕', 'Ð' => '횖', 'Ñ' => '횗', 'Ò' => '횘', 'Ó' => '횙', 'Ô' => '횚', 'Õ' => '횛', 'Ö' => '횜', '×' => '횞', 'Ø' => '횠', 'Ù' => '횢', 'Ú' => '횣', 'Û' => '횤', 'Ü' => '횥', 'Ý' => '횦', 'Þ' => '횧', 'ß' => '횩', 'à' => '횪', 'á' => '찼', 'â' => '창', 'ã' => '찾', 'ä' => '채', 'å' => '책', 'æ' => '챈', 'ç' => '챌', 'è' => '챔', 'é' => '챕', 'ê' => '챗', 'ë' => '챘', 'ì' => '챙', 'í' => '챠', 'î' => '챤', 'ï' => '챦', 'ð' => '챨', 'ñ' => '챰', 'ò' => '챵', 'ó' => '처', 'ô' => '척', 'õ' => '천', 'ö' => '철', '÷' => '첨', 'ø' => '첩', 'ù' => '첫', 'ú' => '첬', 'û' => '청', 'ü' => '체', 'ý' => '첵', 'þ' => '첸', 'ÿ' => '첼', '' => '쳄', '' => '쳅', '' => '쳇', '' => '쳉', '' => '쳐', '' => '쳔', '' => '쳤', '' => '쳬', '' => '쳰', '' => '촁', '' => '초', '' => '촉', '' => '촌', '' => '촐', '' => '촘', '' => '촙', '' => '촛', '' => '총', '' => '촤', '' => '촨', '' => '촬', '' => '촹', '' => '최', '' => '쵠', '' => '쵤', '' => '쵬', '' => '쵭', '' => '쵯', '' => '쵱', '' => '쵸', '' => '춈', '' => '추', '' => '축', '' => '춘', '' => '출', '' => '춤', '' => '춥', '' => '춧', '' => '충', '' => '춰', '' => '췄', '' => '췌', '' => '췐', '' => '취', '' => '췬', '' => '췰', '' => '췸', '' => '췹', '' => '췻', '' => '췽', '' => '츄', '' => '츈', '' => '츌', '' => '츔', '' => '츙', '' => '츠', '' => '측', '' => '츤', '' => '츨', '' => '츰', '' => '츱', '' => '츳', '' => '층', 'A' => '횫', 'B' => '횭', 'C' => '횮', 'D' => '횯', 'E' => '횱', 'F' => '횲', 'G' => '횳', 'H' => '횴', 'I' => '횵', 'J' => '횶', 'K' => '횷', 'L' => '횸', 'M' => '횺', 'N' => '횼', 'O' => '횽', 'P' => '횾', 'Q' => '횿', 'R' => '훀', 'S' => '훁', 'T' => '훂', 'U' => '훃', 'V' => '훆', 'W' => '훇', 'X' => '훉', 'Y' => '훊', 'Z' => '훋', 'a' => '훍', 'b' => '훎', 'c' => '훏', 'd' => '훐', 'e' => '훒', 'f' => '훓', 'g' => '훕', 'h' => '훖', 'i' => '훘', 'j' => '훚', 'k' => '훛', 'l' => '훜', 'm' => '훝', 'n' => '훞', 'o' => '훟', 'p' => '훡', 'q' => '훢', 'r' => '훣', 's' => '훥', 't' => '훦', 'u' => '훧', 'v' => '훩', 'w' => '훪', 'x' => '훫', 'y' => '훬', 'z' => '훭', 'ā' => '훮', 'Ă' => '훯', 'ă' => '훱', 'Ą' => '훲', 'ą' => '훳', 'Ć' => '훴', 'ć' => '훶', 'Ĉ' => '훷', 'ĉ' => '훸', 'Ċ' => '훹', 'ċ' => '훺', 'Č' => '훻', 'č' => '훾', 'Ď' => '훿', 'ď' => '휁', 'Đ' => '휂', 'đ' => '휃', 'Ē' => '휅', 'ē' => '휆', 'Ĕ' => '휇', 'ĕ' => '휈', 'Ė' => '휉', 'ė' => '휊', 'Ę' => '휋', 'ę' => '휌', 'Ě' => '휍', 'ě' => '휎', 'Ĝ' => '휏', 'ĝ' => '휐', 'Ğ' => '휒', 'ğ' => '휓', 'Ġ' => '휔', 'ġ' => '치', 'Ģ' => '칙', 'ģ' => '친', 'Ĥ' => '칟', 'ĥ' => '칠', 'Ħ' => '칡', 'ħ' => '침', 'Ĩ' => '칩', 'ĩ' => '칫', 'Ī' => '칭', 'ī' => '카', 'Ĭ' => '칵', 'ĭ' => '칸', 'Į' => '칼', 'į' => '캄', 'İ' => '캅', 'ı' => '캇', 'IJ' => '캉', 'ij' => '캐', 'Ĵ' => '캑', 'ĵ' => '캔', 'Ķ' => '캘', 'ķ' => '캠', 'ĸ' => '캡', 'Ĺ' => '캣', 'ĺ' => '캤', 'Ļ' => '캥', 'ļ' => '캬', 'Ľ' => '캭', 'ľ' => '컁', 'Ŀ' => '커', '' => '컥', '' => '컨', '' => '컫', '' => '컬', '' => '컴', '' => '컵', '' => '컷', '' => '컸', '' => '컹', '' => '케', '' => '켁', '' => '켄', '' => '켈', '' => '켐', '' => '켑', '' => '켓', '' => '켕', '' => '켜', '' => '켠', '' => '켤', '' => '켬', '' => '켭', '' => '켯', '' => '켰', '' => '켱', '' => '켸', '' => '코', '' => '콕', '' => '콘', '' => '콜', '' => '콤', '' => '콥', '' => '콧', '' => '콩', '' => '콰', '' => '콱', '' => '콴', '' => '콸', '' => '쾀', '' => '쾅', '' => '쾌', '' => '쾡', '' => '쾨', '' => '쾰', '' => '쿄', '' => '쿠', '' => '쿡', '' => '쿤', '' => '쿨', '' => '쿰', '' => '쿱', '' => '쿳', '' => '쿵', '' => '쿼', '' => '퀀', '' => '퀄', '' => '퀑', '' => '퀘', '' => '퀭', '' => '퀴', '' => '퀵', '' => '퀸', '' => '퀼', 'A' => '휕', 'B' => '휖', 'C' => '휗', 'D' => '휚', 'E' => '휛', 'F' => '휝', 'G' => '휞', 'H' => '휟', 'I' => '휡', 'J' => '휢', 'K' => '휣', 'L' => '휤', 'M' => '휥', 'N' => '휦', 'O' => '휧', 'P' => '휪', 'Q' => '휬', 'R' => '휮', 'S' => '휯', 'T' => '휰', 'U' => '휱', 'V' => '휲', 'W' => '휳', 'X' => '휶', 'Y' => '휷', 'Z' => '휹', 'a' => '휺', 'b' => '휻', 'c' => '휽', 'd' => '휾', 'e' => '휿', 'f' => '흀', 'g' => '흁', 'h' => '흂', 'i' => '흃', 'j' => '흅', 'k' => '흆', 'l' => '흈', 'm' => '흊', 'n' => '흋', 'o' => '흌', 'p' => '흍', 'q' => '흎', 'r' => '흏', 's' => '흒', 't' => '흓', 'u' => '흕', 'v' => '흚', 'w' => '흛', 'x' => '흜', 'y' => '흝', 'z' => '흞', 'Ł' => '흟', 'ł' => '흢', 'Ń' => '흤', 'ń' => '흦', 'Ņ' => '흧', 'ņ' => '흨', 'Ň' => '흪', 'ň' => '흫', 'ʼn' => '흭', 'Ŋ' => '흮', 'ŋ' => '흯', 'Ō' => '흱', 'ō' => '흲', 'Ŏ' => '흳', 'ŏ' => '흵', 'Ő' => '흶', 'ő' => '흷', 'Œ' => '흸', 'œ' => '흹', 'Ŕ' => '흺', 'ŕ' => '흻', 'Ŗ' => '흾', 'ŗ' => '흿', 'Ř' => '힀', 'ř' => '힂', 'Ś' => '힃', 'ś' => '힄', 'Ŝ' => '힅', 'ŝ' => '힆', 'Ş' => '힇', 'ş' => '힊', 'Š' => '힋', 'š' => '큄', 'Ţ' => '큅', 'ţ' => '큇', 'Ť' => '큉', 'ť' => '큐', 'Ŧ' => '큔', 'ŧ' => '큘', 'Ũ' => '큠', 'ũ' => '크', 'Ū' => '큭', 'ū' => '큰', 'Ŭ' => '클', 'ŭ' => '큼', 'Ů' => '큽', 'ů' => '킁', 'Ű' => '키', 'ű' => '킥', 'Ų' => '킨', 'ų' => '킬', 'Ŵ' => '킴', 'ŵ' => '킵', 'Ŷ' => '킷', 'ŷ' => '킹', 'Ÿ' => '타', 'Ź' => '탁', 'ź' => '탄', 'Ż' => '탈', 'ż' => '탉', 'Ž' => '탐', 'ž' => '탑', 'ſ' => '탓', '' => '탔', '' => '탕', '' => '태', '' => '택', '' => '탠', '' => '탤', '' => '탬', '' => '탭', '' => '탯', '' => '탰', '' => '탱', '' => '탸', '' => '턍', '' => '터', '' => '턱', '' => '턴', '' => '털', '' => '턺', '' => '텀', '' => '텁', '' => '텃', '' => '텄', '' => '텅', '' => '테', '' => '텍', '' => '텐', '' => '텔', '' => '템', '' => '텝', '' => '텟', '' => '텡', '' => '텨', '' => '텬', '' => '텼', '' => '톄', '' => '톈', '' => '토', '' => '톡', '' => '톤', '' => '톨', '' => '톰', '' => '톱', '' => '톳', '' => '통', '' => '톺', '' => '톼', '' => '퇀', '' => '퇘', '' => '퇴', '' => '퇸', '' => '툇', '' => '툉', '' => '툐', '' => '투', '' => '툭', '' => '툰', '' => '툴', '' => '툼', '' => '툽', '' => '툿', '' => '퉁', '' => '퉈', '' => '퉜', 'A' => '힍', 'B' => '힎', 'C' => '힏', 'D' => '힑', 'E' => '힒', 'F' => '힓', 'G' => '힔', 'H' => '힕', 'I' => '힖', 'J' => '힗', 'K' => '힚', 'L' => '힜', 'M' => '힞', 'N' => '힟', 'O' => '힠', 'P' => '힡', 'Q' => '힢', 'R' => '힣', 'ơ' => '퉤', 'Ƣ' => '튀', 'ƣ' => '튁', 'Ƥ' => '튄', 'ƥ' => '튈', 'Ʀ' => '튐', 'Ƨ' => '튑', 'ƨ' => '튕', 'Ʃ' => '튜', 'ƪ' => '튠', 'ƫ' => '튤', 'Ƭ' => '튬', 'ƭ' => '튱', 'Ʈ' => '트', 'Ư' => '특', 'ư' => '튼', 'Ʊ' => '튿', 'Ʋ' => '틀', 'Ƴ' => '틂', 'ƴ' => '틈', 'Ƶ' => '틉', 'ƶ' => '틋', 'Ʒ' => '틔', 'Ƹ' => '틘', 'ƹ' => '틜', 'ƺ' => '틤', 'ƻ' => '틥', 'Ƽ' => '티', 'ƽ' => '틱', 'ƾ' => '틴', 'ƿ' => '틸', '' => '팀', '' => '팁', '' => '팃', '' => '팅', '' => '파', '' => '팍', '' => '팎', '' => '판', '' => '팔', '' => '팖', '' => '팜', '' => '팝', '' => '팟', '' => '팠', '' => '팡', '' => '팥', '' => '패', '' => '팩', '' => '팬', '' => '팰', '' => '팸', '' => '팹', '' => '팻', '' => '팼', '' => '팽', '' => '퍄', '' => '퍅', '' => '퍼', '' => '퍽', '' => '펀', '' => '펄', '' => '펌', '' => '펍', '' => '펏', '' => '펐', '' => '펑', '' => '페', '' => '펙', '' => '펜', '' => '펠', '' => '펨', '' => '펩', '' => '펫', '' => '펭', '' => '펴', '' => '편', '' => '펼', '' => '폄', '' => '폅', '' => '폈', '' => '평', '' => '폐', '' => '폘', '' => '폡', '' => '폣', '' => '포', '' => '폭', '' => '폰', '' => '폴', '' => '폼', '' => '폽', '' => '폿', '' => '퐁', 'ǡ' => '퐈', 'Ǣ' => '퐝', 'ǣ' => '푀', 'Ǥ' => '푄', 'ǥ' => '표', 'Ǧ' => '푠', 'ǧ' => '푤', 'Ǩ' => '푭', 'ǩ' => '푯', 'Ǫ' => '푸', 'ǫ' => '푹', 'Ǭ' => '푼', 'ǭ' => '푿', 'Ǯ' => '풀', 'ǯ' => '풂', 'ǰ' => '품', 'DZ' => '풉', 'Dz' => '풋', 'dz' => '풍', 'Ǵ' => '풔', 'ǵ' => '풩', 'Ƕ' => '퓌', 'Ƿ' => '퓐', 'Ǹ' => '퓔', 'ǹ' => '퓜', 'Ǻ' => '퓟', 'ǻ' => '퓨', 'Ǽ' => '퓬', 'ǽ' => '퓰', 'Ǿ' => '퓸', 'ǿ' => '퓻', '' => '퓽', '' => '프', '' => '픈', '' => '플', '' => '픔', '' => '픕', '' => '픗', '' => '피', '' => '픽', '' => '핀', '' => '필', '' => '핌', '' => '핍', '' => '핏', '' => '핑', '' => '하', '' => '학', '' => '한', '' => '할', '' => '핥', '' => '함', '' => '합', '' => '핫', '' => '항', '' => '해', '' => '핵', '' => '핸', '' => '핼', '' => '햄', '' => '햅', '' => '햇', '' => '했', '' => '행', '' => '햐', '' => '향', '' => '허', '' => '헉', '' => '헌', '' => '헐', '' => '헒', '' => '험', '' => '헙', '' => '헛', '' => '헝', '' => '헤', '' => '헥', '' => '헨', '' => '헬', '' => '헴', '' => '헵', '' => '헷', '' => '헹', '' => '혀', '' => '혁', '' => '현', '' => '혈', '' => '혐', '' => '협', '' => '혓', '' => '혔', '' => '형', '' => '혜', '' => '혠', 'ȡ' => '혤', 'Ȣ' => '혭', 'ȣ' => '호', 'Ȥ' => '혹', 'ȥ' => '혼', 'Ȧ' => '홀', 'ȧ' => '홅', 'Ȩ' => '홈', 'ȩ' => '홉', 'Ȫ' => '홋', 'ȫ' => '홍', 'Ȭ' => '홑', 'ȭ' => '화', 'Ȯ' => '확', 'ȯ' => '환', 'Ȱ' => '활', 'ȱ' => '홧', 'Ȳ' => '황', 'ȳ' => '홰', 'ȴ' => '홱', 'ȵ' => '홴', 'ȶ' => '횃', 'ȷ' => '횅', 'ȸ' => '회', 'ȹ' => '획', 'Ⱥ' => '횐', 'Ȼ' => '횔', 'ȼ' => '횝', 'Ƚ' => '횟', 'Ⱦ' => '횡', 'ȿ' => '효', '' => '횬', '' => '횰', '' => '횹', '' => '횻', '' => '후', '' => '훅', '' => '훈', '' => '훌', '' => '훑', '' => '훔', '' => '훗', '' => '훙', '' => '훠', '' => '훤', '' => '훨', '' => '훰', '' => '훵', '' => '훼', '' => '훽', '' => '휀', '' => '휄', '' => '휑', '' => '휘', '' => '휙', '' => '휜', '' => '휠', '' => '휨', '' => '휩', '' => '휫', '' => '휭', '' => '휴', '' => '휵', '' => '휸', '' => '휼', '' => '흄', '' => '흇', '' => '흉', '' => '흐', '' => '흑', '' => '흔', '' => '흖', '' => '흗', '' => '흘', '' => '흙', '' => '흠', '' => '흡', '' => '흣', '' => '흥', '' => '흩', '' => '희', '' => '흰', '' => '흴', '' => '흼', '' => '흽', '' => '힁', '' => '히', '' => '힉', '' => '힌', '' => '힐', '' => '힘', '' => '힙', '' => '힛', '' => '힝', 'ʡ' => '伽', 'ʢ' => '佳', 'ʣ' => '假', 'ʤ' => '價', 'ʥ' => '加', 'ʦ' => '可', 'ʧ' => '呵', 'ʨ' => '哥', 'ʩ' => '嘉', 'ʪ' => '嫁', 'ʫ' => '家', 'ʬ' => '暇', 'ʭ' => '架', 'ʮ' => '枷', 'ʯ' => '柯', 'ʰ' => '歌', 'ʱ' => '珂', 'ʲ' => '痂', 'ʳ' => '稼', 'ʴ' => '苛', 'ʵ' => '茄', 'ʶ' => '街', 'ʷ' => '袈', 'ʸ' => '訶', 'ʹ' => '賈', 'ʺ' => '跏', 'ʻ' => '軻', 'ʼ' => '迦', 'ʽ' => '駕', 'ʾ' => '刻', 'ʿ' => '却', '' => '各', '' => '恪', '' => '慤', '' => '殼', '' => '珏', '' => '脚', '' => '覺', '' => '角', '' => '閣', '' => '侃', '' => '刊', '' => '墾', '' => '奸', '' => '姦', '' => '干', '' => '幹', '' => '懇', '' => '揀', '' => '杆', '' => '柬', '' => '桿', '' => '澗', '' => '癎', '' => '看', '' => '磵', '' => '稈', '' => '竿', '' => '簡', '' => '肝', '' => '艮', '' => '艱', '' => '諫', '' => '間', '' => '乫', '' => '喝', '' => '曷', '' => '渴', '' => '碣', '' => '竭', '' => '葛', '' => '褐', '' => '蝎', '' => '鞨', '' => '勘', '' => '坎', '' => '堪', '' => '嵌', '' => '感', '' => '憾', '' => '戡', '' => '敢', '' => '柑', '' => '橄', '' => '減', '' => '甘', '' => '疳', '' => '監', '' => '瞰', '' => '紺', '' => '邯', '' => '鑑', '' => '鑒', '' => '龕', 'ˡ' => '匣', 'ˢ' => '岬', 'ˣ' => '甲', 'ˤ' => '胛', '˥' => '鉀', '˦' => '閘', '˧' => '剛', '˨' => '堈', '˩' => '姜', '˪' => '岡', '˫' => '崗', 'ˬ' => '康', '˭' => '强', 'ˮ' => '彊', '˯' => '慷', '˰' => '江', '˱' => '畺', '˲' => '疆', '˳' => '糠', '˴' => '絳', '˵' => '綱', '˶' => '羌', '˷' => '腔', '˸' => '舡', '˹' => '薑', '˺' => '襁', '˻' => '講', '˼' => '鋼', '˽' => '降', '˾' => '鱇', '˿' => '介', '' => '价', '' => '個', '' => '凱', '' => '塏', '' => '愷', '' => '愾', '' => '慨', '' => '改', '' => '槪', '' => '漑', '' => '疥', '' => '皆', '' => '盖', '' => '箇', '' => '芥', '' => '蓋', '' => '豈', '' => '鎧', '' => '開', '' => '喀', '' => '客', '' => '坑', '' => '更', '' => '粳', '' => '羹', '' => '醵', '' => '倨', '' => '去', '' => '居', '' => '巨', '' => '拒', '' => '据', '' => '據', '' => '擧', '' => '渠', '' => '炬', '' => '祛', '' => '距', '' => '踞', '' => '車', '' => '遽', '' => '鉅', '' => '鋸', '' => '乾', '' => '件', '' => '健', '' => '巾', '' => '建', '' => '愆', '' => '楗', '' => '腱', '' => '虔', '' => '蹇', '' => '鍵', '' => '騫', '' => '乞', '' => '傑', '' => '杰', '' => '桀', '' => '儉', '' => '劍', '' => '劒', '' => '檢', '̡' => '瞼', '̢' => '鈐', '̣' => '黔', '̤' => '劫', '̥' => '怯', '̦' => '迲', '̧' => '偈', '̨' => '憩', '̩' => '揭', '̪' => '擊', '̫' => '格', '̬' => '檄', '̭' => '激', '̮' => '膈', '̯' => '覡', '̰' => '隔', '̱' => '堅', '̲' => '牽', '̳' => '犬', '̴' => '甄', '̵' => '絹', '̶' => '繭', '̷' => '肩', '̸' => '見', '̹' => '譴', '̺' => '遣', '̻' => '鵑', '̼' => '抉', '̽' => '決', '̾' => '潔', '̿' => '結', '' => '缺', '' => '訣', '' => '兼', '' => '慊', '' => '箝', '' => '謙', '' => '鉗', '' => '鎌', '' => '京', '' => '俓', '' => '倞', '' => '傾', '' => '儆', '' => '勁', '' => '勍', '' => '卿', '' => '坰', '' => '境', '' => '庚', '' => '徑', '' => '慶', '' => '憬', '' => '擎', '' => '敬', '' => '景', '' => '暻', '' => '更', '' => '梗', '' => '涇', '' => '炅', '' => '烱', '' => '璟', '' => '璥', '' => '瓊', '' => '痙', '' => '硬', '' => '磬', '' => '竟', '' => '競', '' => '絅', '' => '經', '' => '耕', '' => '耿', '' => '脛', '' => '莖', '' => '警', '' => '輕', '' => '逕', '' => '鏡', '' => '頃', '' => '頸', '' => '驚', '' => '鯨', '' => '係', '' => '啓', '' => '堺', '' => '契', '' => '季', '' => '屆', '' => '悸', '' => '戒', '' => '桂', '' => '械', '͡' => '棨', '͢' => '溪', 'ͣ' => '界', 'ͤ' => '癸', 'ͥ' => '磎', 'ͦ' => '稽', 'ͧ' => '系', 'ͨ' => '繫', 'ͩ' => '繼', 'ͪ' => '計', 'ͫ' => '誡', 'ͬ' => '谿', 'ͭ' => '階', 'ͮ' => '鷄', 'ͯ' => '古', 'Ͱ' => '叩', 'ͱ' => '告', 'Ͳ' => '呱', 'ͳ' => '固', 'ʹ' => '姑', '͵' => '孤', 'Ͷ' => '尻', 'ͷ' => '庫', '͸' => '拷', '͹' => '攷', 'ͺ' => '故', 'ͻ' => '敲', 'ͼ' => '暠', 'ͽ' => '枯', ';' => '槁', 'Ϳ' => '沽', '' => '痼', '' => '皐', '' => '睾', '' => '稿', '' => '羔', '' => '考', '' => '股', '' => '膏', '' => '苦', '' => '苽', '' => '菰', '' => '藁', '' => '蠱', '' => '袴', '' => '誥', '' => '賈', '' => '辜', '' => '錮', '' => '雇', '' => '顧', '' => '高', '' => '鼓', '' => '哭', '' => '斛', '' => '曲', '' => '梏', '' => '穀', '' => '谷', '' => '鵠', '' => '困', '' => '坤', '' => '崑', '' => '昆', '' => '梱', '' => '棍', '' => '滾', '' => '琨', '' => '袞', '' => '鯤', '' => '汨', '' => '滑', '' => '骨', '' => '供', '' => '公', '' => '共', '' => '功', '' => '孔', '' => '工', '' => '恐', '' => '恭', '' => '拱', '' => '控', '' => '攻', '' => '珙', '' => '空', '' => '蚣', '' => '貢', '' => '鞏', '' => '串', '' => '寡', '' => '戈', '' => '果', '' => '瓜', 'Ρ' => '科', '΢' => '菓', 'Σ' => '誇', 'Τ' => '課', 'Υ' => '跨', 'Φ' => '過', 'Χ' => '鍋', 'Ψ' => '顆', 'Ω' => '廓', 'Ϊ' => '槨', 'Ϋ' => '藿', 'ά' => '郭', 'έ' => '串', 'ή' => '冠', 'ί' => '官', 'ΰ' => '寬', 'α' => '慣', 'β' => '棺', 'γ' => '款', 'δ' => '灌', 'ε' => '琯', 'ζ' => '瓘', 'η' => '管', 'θ' => '罐', 'ι' => '菅', 'κ' => '觀', 'λ' => '貫', 'μ' => '關', 'ν' => '館', 'ξ' => '刮', 'ο' => '恝', '' => '括', '' => '适', '' => '侊', '' => '光', '' => '匡', '' => '壙', '' => '廣', '' => '曠', '' => '洸', '' => '炚', '' => '狂', '' => '珖', '' => '筐', '' => '胱', '' => '鑛', '' => '卦', '' => '掛', '' => '罫', '' => '乖', '' => '傀', '' => '塊', '' => '壞', '' => '怪', '' => '愧', '' => '拐', '' => '槐', '' => '魁', '' => '宏', '' => '紘', '' => '肱', '' => '轟', '' => '交', '' => '僑', '' => '咬', '' => '喬', '' => '嬌', '' => '嶠', '' => '巧', '' => '攪', '' => '敎', '' => '校', '' => '橋', '' => '狡', '' => '皎', '' => '矯', '' => '絞', '' => '翹', '' => '膠', '' => '蕎', '' => '蛟', '' => '較', '' => '轎', '' => '郊', '' => '餃', '' => '驕', '' => '鮫', '' => '丘', '' => '久', '' => '九', '' => '仇', '' => '俱', '' => '具', '' => '勾', 'ϡ' => '區', 'Ϣ' => '口', 'ϣ' => '句', 'Ϥ' => '咎', 'ϥ' => '嘔', 'Ϧ' => '坵', 'ϧ' => '垢', 'Ϩ' => '寇', 'ϩ' => '嶇', 'Ϫ' => '廐', 'ϫ' => '懼', 'Ϭ' => '拘', 'ϭ' => '救', 'Ϯ' => '枸', 'ϯ' => '柩', 'ϰ' => '構', 'ϱ' => '歐', 'ϲ' => '毆', 'ϳ' => '毬', 'ϴ' => '求', 'ϵ' => '溝', '϶' => '灸', 'Ϸ' => '狗', 'ϸ' => '玖', 'Ϲ' => '球', 'Ϻ' => '瞿', 'ϻ' => '矩', 'ϼ' => '究', 'Ͻ' => '絿', 'Ͼ' => '耉', 'Ͽ' => '臼', '' => '舅', '' => '舊', '' => '苟', '' => '衢', '' => '謳', '' => '購', '' => '軀', '' => '逑', '' => '邱', '' => '鉤', '' => '銶', '' => '駒', '' => '驅', '' => '鳩', '' => '鷗', '' => '龜', '' => '國', '' => '局', '' => '菊', '' => '鞠', '' => '鞫', '' => '麴', '' => '君', '' => '窘', '' => '群', '' => '裙', '' => '軍', '' => '郡', '' => '堀', '' => '屈', '' => '掘', '' => '窟', '' => '宮', '' => '弓', '' => '穹', '' => '窮', '' => '芎', '' => '躬', '' => '倦', '' => '券', '' => '勸', '' => '卷', '' => '圈', '' => '拳', '' => '捲', '' => '權', '' => '淃', '' => '眷', '' => '厥', '' => '獗', '' => '蕨', '' => '蹶', '' => '闕', '' => '机', '' => '櫃', '' => '潰', '' => '詭', '' => '軌', '' => '饋', '' => '句', '' => '晷', '' => '歸', '' => '貴', 'С' => '鬼', 'Т' => '龜', 'У' => '叫', 'Ф' => '圭', 'Х' => '奎', 'Ц' => '揆', 'Ч' => '槻', 'Ш' => '珪', 'Щ' => '硅', 'Ъ' => '窺', 'Ы' => '竅', 'Ь' => '糾', 'Э' => '葵', 'Ю' => '規', 'Я' => '赳', 'а' => '逵', 'б' => '閨', 'в' => '勻', 'г' => '均', 'д' => '畇', 'е' => '筠', 'ж' => '菌', 'з' => '鈞', 'и' => '龜', 'й' => '橘', 'к' => '克', 'л' => '剋', 'м' => '劇', 'н' => '戟', 'о' => '棘', 'п' => '極', '' => '隙', '' => '僅', '' => '劤', '' => '勤', '' => '懃', '' => '斤', '' => '根', '' => '槿', '' => '瑾', '' => '筋', '' => '芹', '' => '菫', '' => '覲', '' => '謹', '' => '近', '' => '饉', '' => '契', '' => '今', '' => '妗', '' => '擒', '' => '昑', '' => '檎', '' => '琴', '' => '禁', '' => '禽', '' => '芩', '' => '衾', '' => '衿', '' => '襟', '' => '金', '' => '錦', '' => '伋', '' => '及', '' => '急', '' => '扱', '' => '汲', '' => '級', '' => '給', '' => '亘', '' => '兢', '' => '矜', '' => '肯', '' => '企', '' => '伎', '' => '其', '' => '冀', '' => '嗜', '' => '器', '' => '圻', '' => '基', '' => '埼', '' => '夔', '' => '奇', '' => '妓', '' => '寄', '' => '岐', '' => '崎', '' => '己', '' => '幾', '' => '忌', '' => '技', '' => '旗', '' => '旣', 'ѡ' => '朞', 'Ѣ' => '期', 'ѣ' => '杞', 'Ѥ' => '棋', 'ѥ' => '棄', 'Ѧ' => '機', 'ѧ' => '欺', 'Ѩ' => '氣', 'ѩ' => '汽', 'Ѫ' => '沂', 'ѫ' => '淇', 'Ѭ' => '玘', 'ѭ' => '琦', 'Ѯ' => '琪', 'ѯ' => '璂', 'Ѱ' => '璣', 'ѱ' => '畸', 'Ѳ' => '畿', 'ѳ' => '碁', 'Ѵ' => '磯', 'ѵ' => '祁', 'Ѷ' => '祇', 'ѷ' => '祈', 'Ѹ' => '祺', 'ѹ' => '箕', 'Ѻ' => '紀', 'ѻ' => '綺', 'Ѽ' => '羈', 'ѽ' => '耆', 'Ѿ' => '耭', 'ѿ' => '肌', '' => '記', '' => '譏', '' => '豈', '' => '起', '' => '錡', '' => '錤', '' => '飢', '' => '饑', '' => '騎', '' => '騏', '' => '驥', '' => '麒', '' => '緊', '' => '佶', '' => '吉', '' => '拮', '' => '桔', '' => '金', '' => '喫', '' => '儺', '' => '喇', '' => '奈', '' => '娜', '' => '懦', '' => '懶', '' => '拏', '' => '拿', '' => '癩', '' => '羅', '' => '蘿', '' => '螺', '' => '裸', '' => '邏', '' => '那', '' => '樂', '' => '洛', '' => '烙', '' => '珞', '' => '落', '' => '諾', '' => '酪', '' => '駱', '' => '亂', '' => '卵', '' => '暖', '' => '欄', '' => '煖', '' => '爛', '' => '蘭', '' => '難', '' => '鸞', '' => '捏', '' => '捺', '' => '南', '' => '嵐', '' => '枏', '' => '楠', '' => '湳', '' => '濫', '' => '男', '' => '藍', '' => '襤', '' => '拉', 'ҡ' => '納', 'Ң' => '臘', 'ң' => '蠟', 'Ҥ' => '衲', 'ҥ' => '囊', 'Ҧ' => '娘', 'ҧ' => '廊', 'Ҩ' => '朗', 'ҩ' => '浪', 'Ҫ' => '狼', 'ҫ' => '郎', 'Ҭ' => '乃', 'ҭ' => '來', 'Ү' => '內', 'ү' => '奈', 'Ұ' => '柰', 'ұ' => '耐', 'Ҳ' => '冷', 'ҳ' => '女', 'Ҵ' => '年', 'ҵ' => '撚', 'Ҷ' => '秊', 'ҷ' => '念', 'Ҹ' => '恬', 'ҹ' => '拈', 'Һ' => '捻', 'һ' => '寧', 'Ҽ' => '寗', 'ҽ' => '努', 'Ҿ' => '勞', 'ҿ' => '奴', '' => '弩', '' => '怒', '' => '擄', '' => '櫓', '' => '爐', '' => '瑙', '' => '盧', '' => '老', '' => '蘆', '' => '虜', '' => '路', '' => '露', '' => '駑', '' => '魯', '' => '鷺', '' => '碌', '' => '祿', '' => '綠', '' => '菉', '' => '錄', '' => '鹿', '' => '論', '' => '壟', '' => '弄', '' => '濃', '' => '籠', '' => '聾', '' => '膿', '' => '農', '' => '惱', '' => '牢', '' => '磊', '' => '腦', '' => '賂', '' => '雷', '' => '尿', '' => '壘', '' => '屢', '' => '樓', '' => '淚', '' => '漏', '' => '累', '' => '縷', '' => '陋', '' => '嫩', '' => '訥', '' => '杻', '' => '紐', '' => '勒', '' => '肋', '' => '凜', '' => '凌', '' => '稜', '' => '綾', '' => '能', '' => '菱', '' => '陵', '' => '尼', '' => '泥', '' => '匿', '' => '溺', '' => '多', '' => '茶', 'ӡ' => '丹', 'Ӣ' => '亶', 'ӣ' => '但', 'Ӥ' => '單', 'ӥ' => '團', 'Ӧ' => '壇', 'ӧ' => '彖', 'Ө' => '斷', 'ө' => '旦', 'Ӫ' => '檀', 'ӫ' => '段', 'Ӭ' => '湍', 'ӭ' => '短', 'Ӯ' => '端', 'ӯ' => '簞', 'Ӱ' => '緞', 'ӱ' => '蛋', 'Ӳ' => '袒', 'ӳ' => '鄲', 'Ӵ' => '鍛', 'ӵ' => '撻', 'Ӷ' => '澾', 'ӷ' => '獺', 'Ӹ' => '疸', 'ӹ' => '達', 'Ӻ' => '啖', 'ӻ' => '坍', 'Ӽ' => '憺', 'ӽ' => '擔', 'Ӿ' => '曇', 'ӿ' => '淡', '' => '湛', '' => '潭', '' => '澹', '' => '痰', '' => '聃', '' => '膽', '' => '蕁', '' => '覃', '' => '談', '' => '譚', '' => '錟', '' => '沓', '' => '畓', '' => '答', '' => '踏', '' => '遝', '' => '唐', '' => '堂', '' => '塘', '' => '幢', '' => '戇', '' => '撞', '' => '棠', '' => '當', '' => '糖', '' => '螳', '' => '黨', '' => '代', '' => '垈', '' => '坮', '' => '大', '' => '對', '' => '岱', '' => '帶', '' => '待', '' => '戴', '' => '擡', '' => '玳', '' => '臺', '' => '袋', '' => '貸', '' => '隊', '' => '黛', '' => '宅', '' => '德', '' => '悳', '' => '倒', '' => '刀', '' => '到', '' => '圖', '' => '堵', '' => '塗', '' => '導', '' => '屠', '' => '島', '' => '嶋', '' => '度', '' => '徒', '' => '悼', '' => '挑', '' => '掉', '' => '搗', '' => '桃', 'ԡ' => '棹', 'Ԣ' => '櫂', 'ԣ' => '淘', 'Ԥ' => '渡', 'ԥ' => '滔', 'Ԧ' => '濤', 'ԧ' => '燾', 'Ԩ' => '盜', 'ԩ' => '睹', 'Ԫ' => '禱', 'ԫ' => '稻', 'Ԭ' => '萄', 'ԭ' => '覩', 'Ԯ' => '賭', 'ԯ' => '跳', '԰' => '蹈', 'Ա' => '逃', 'Բ' => '途', 'Գ' => '道', 'Դ' => '都', 'Ե' => '鍍', 'Զ' => '陶', 'Է' => '韜', 'Ը' => '毒', 'Թ' => '瀆', 'Ժ' => '牘', 'Ի' => '犢', 'Լ' => '獨', 'Խ' => '督', 'Ծ' => '禿', 'Կ' => '篤', '' => '纛', '' => '讀', '' => '墩', '' => '惇', '' => '敦', '' => '旽', '' => '暾', '' => '沌', '' => '焞', '' => '燉', '' => '豚', '' => '頓', '' => '乭', '' => '突', '' => '仝', '' => '冬', '' => '凍', '' => '動', '' => '同', '' => '憧', '' => '東', '' => '桐', '' => '棟', '' => '洞', '' => '潼', '' => '疼', '' => '瞳', '' => '童', '' => '胴', '' => '董', '' => '銅', '' => '兜', '' => '斗', '' => '杜', '' => '枓', '' => '痘', '' => '竇', '' => '荳', '' => '讀', '' => '豆', '' => '逗', '' => '頭', '' => '屯', '' => '臀', '' => '芚', '' => '遁', '' => '遯', '' => '鈍', '' => '得', '' => '嶝', '' => '橙', '' => '燈', '' => '登', '' => '等', '' => '藤', '' => '謄', '' => '鄧', '' => '騰', '' => '喇', '' => '懶', '' => '拏', '' => '癩', '' => '羅', 'ա' => '蘿', 'բ' => '螺', 'գ' => '裸', 'դ' => '邏', 'ե' => '樂', 'զ' => '洛', 'է' => '烙', 'ը' => '珞', 'թ' => '絡', 'ժ' => '落', 'ի' => '諾', 'լ' => '酪', 'խ' => '駱', 'ծ' => '丹', 'կ' => '亂', 'հ' => '卵', 'ձ' => '欄', 'ղ' => '欒', 'ճ' => '瀾', 'մ' => '爛', 'յ' => '蘭', 'ն' => '鸞', 'շ' => '剌', 'ո' => '辣', 'չ' => '嵐', 'պ' => '擥', 'ջ' => '攬', 'ռ' => '欖', 'ս' => '濫', 'վ' => '籃', 'տ' => '纜', '' => '藍', '' => '襤', '' => '覽', '' => '拉', '' => '臘', '' => '蠟', '' => '廊', '' => '朗', '' => '浪', '' => '狼', '' => '琅', '' => '瑯', '' => '螂', '' => '郞', '' => '來', '' => '崍', '' => '徠', '' => '萊', '' => '冷', '' => '掠', '' => '略', '' => '亮', '' => '倆', '' => '兩', '' => '凉', '' => '梁', '' => '樑', '' => '粮', '' => '粱', '' => '糧', '' => '良', '' => '諒', '' => '輛', '' => '量', '' => '侶', '' => '儷', '' => '勵', '' => '呂', '' => '廬', '' => '慮', '' => '戾', '' => '旅', '' => '櫚', '' => '濾', '' => '礪', '' => '藜', '' => '蠣', '' => '閭', '' => '驢', '' => '驪', '' => '麗', '' => '黎', '' => '力', '' => '曆', '' => '歷', '' => '瀝', '' => '礫', '' => '轢', '' => '靂', '' => '憐', '' => '戀', '' => '攣', '' => '漣', '֡' => '煉', '֢' => '璉', '֣' => '練', '֤' => '聯', '֥' => '蓮', '֦' => '輦', '֧' => '連', '֨' => '鍊', '֩' => '冽', '֪' => '列', '֫' => '劣', '֬' => '洌', '֭' => '烈', '֮' => '裂', '֯' => '廉', 'ְ' => '斂', 'ֱ' => '殮', 'ֲ' => '濂', 'ֳ' => '簾', 'ִ' => '獵', 'ֵ' => '令', 'ֶ' => '伶', 'ַ' => '囹', 'ָ' => '寧', 'ֹ' => '岺', 'ֺ' => '嶺', 'ֻ' => '怜', 'ּ' => '玲', 'ֽ' => '笭', '־' => '羚', 'ֿ' => '翎', '' => '聆', '' => '逞', '' => '鈴', '' => '零', '' => '靈', '' => '領', '' => '齡', '' => '例', '' => '澧', '' => '禮', '' => '醴', '' => '隷', '' => '勞', '' => '怒', '' => '撈', '' => '擄', '' => '櫓', '' => '潞', '' => '瀘', '' => '爐', '' => '盧', '' => '老', '' => '蘆', '' => '虜', '' => '路', '' => '輅', '' => '露', '' => '魯', '' => '鷺', '' => '鹵', '' => '碌', '' => '祿', '' => '綠', '' => '菉', '' => '錄', '' => '鹿', '' => '麓', '' => '論', '' => '壟', '' => '弄', '' => '朧', '' => '瀧', '' => '瓏', '' => '籠', '' => '聾', '' => '儡', '' => '瀨', '' => '牢', '' => '磊', '' => '賂', '' => '賚', '' => '賴', '' => '雷', '' => '了', '' => '僚', '' => '寮', '' => '廖', '' => '料', '' => '燎', '' => '療', '' => '瞭', '' => '聊', '' => '蓼', 'ס' => '遼', 'ע' => '鬧', 'ף' => '龍', 'פ' => '壘', 'ץ' => '婁', 'צ' => '屢', 'ק' => '樓', 'ר' => '淚', 'ש' => '漏', 'ת' => '瘻', '׫' => '累', '׬' => '縷', '׭' => '蔞', '׮' => '褸', 'ׯ' => '鏤', 'װ' => '陋', 'ױ' => '劉', 'ײ' => '旒', '׳' => '柳', '״' => '榴', '׵' => '流', '׶' => '溜', '׷' => '瀏', '׸' => '琉', '׹' => '瑠', '׺' => '留', '׻' => '瘤', '׼' => '硫', '׽' => '謬', '׾' => '類', '׿' => '六', '' => '戮', '' => '陸', '' => '侖', '' => '倫', '' => '崙', '' => '淪', '' => '綸', '' => '輪', '' => '律', '' => '慄', '' => '栗', '' => '率', '' => '隆', '' => '勒', '' => '肋', '' => '凜', '' => '凌', '' => '楞', '' => '稜', '' => '綾', '' => '菱', '' => '陵', '' => '俚', '' => '利', '' => '厘', '' => '吏', '' => '唎', '' => '履', '' => '悧', '' => '李', '' => '梨', '' => '浬', '' => '犁', '' => '狸', '' => '理', '' => '璃', '' => '異', '' => '痢', '' => '籬', '' => '罹', '' => '羸', '' => '莉', '' => '裏', '' => '裡', '' => '里', '' => '釐', '' => '離', '' => '鯉', '' => '吝', '' => '潾', '' => '燐', '' => '璘', '' => '藺', '' => '躪', '' => '隣', '' => '鱗', '' => '麟', '' => '林', '' => '淋', '' => '琳', '' => '臨', '' => '霖', '' => '砬', 'ء' => '立', 'آ' => '笠', 'أ' => '粒', 'ؤ' => '摩', 'إ' => '瑪', 'ئ' => '痲', 'ا' => '碼', 'ب' => '磨', 'ة' => '馬', 'ت' => '魔', 'ث' => '麻', 'ج' => '寞', 'ح' => '幕', 'خ' => '漠', 'د' => '膜', 'ذ' => '莫', 'ر' => '邈', 'ز' => '万', 'س' => '卍', 'ش' => '娩', 'ص' => '巒', 'ض' => '彎', 'ط' => '慢', 'ظ' => '挽', 'ع' => '晩', 'غ' => '曼', 'ػ' => '滿', 'ؼ' => '漫', 'ؽ' => '灣', 'ؾ' => '瞞', 'ؿ' => '萬', '' => '蔓', '' => '蠻', '' => '輓', '' => '饅', '' => '鰻', '' => '唜', '' => '抹', '' => '末', '' => '沫', '' => '茉', '' => '襪', '' => '靺', '' => '亡', '' => '妄', '' => '忘', '' => '忙', '' => '望', '' => '網', '' => '罔', '' => '芒', '' => '茫', '' => '莽', '' => '輞', '' => '邙', '' => '埋', '' => '妹', '' => '媒', '' => '寐', '' => '昧', '' => '枚', '' => '梅', '' => '每', '' => '煤', '' => '罵', '' => '買', '' => '賣', '' => '邁', '' => '魅', '' => '脈', '' => '貊', '' => '陌', '' => '驀', '' => '麥', '' => '孟', '' => '氓', '' => '猛', '' => '盲', '' => '盟', '' => '萌', '' => '冪', '' => '覓', '' => '免', '' => '冕', '' => '勉', '' => '棉', '' => '沔', '' => '眄', '' => '眠', '' => '綿', '' => '緬', '' => '面', '' => '麵', '' => '滅', '١' => '蔑', '٢' => '冥', '٣' => '名', '٤' => '命', '٥' => '明', '٦' => '暝', '٧' => '椧', '٨' => '溟', '٩' => '皿', '٪' => '瞑', '٫' => '茗', '٬' => '蓂', '٭' => '螟', 'ٮ' => '酩', 'ٯ' => '銘', 'ٰ' => '鳴', 'ٱ' => '袂', 'ٲ' => '侮', 'ٳ' => '冒', 'ٴ' => '募', 'ٵ' => '姆', 'ٶ' => '帽', 'ٷ' => '慕', 'ٸ' => '摸', 'ٹ' => '摹', 'ٺ' => '暮', 'ٻ' => '某', 'ټ' => '模', 'ٽ' => '母', 'پ' => '毛', 'ٿ' => '牟', '' => '牡', '' => '瑁', '' => '眸', '' => '矛', '' => '耗', '' => '芼', '' => '茅', '' => '謀', '' => '謨', '' => '貌', '' => '木', '' => '沐', '' => '牧', '' => '目', '' => '睦', '' => '穆', '' => '鶩', '' => '歿', '' => '沒', '' => '夢', '' => '朦', '' => '蒙', '' => '卯', '' => '墓', '' => '妙', '' => '廟', '' => '描', '' => '昴', '' => '杳', '' => '渺', '' => '猫', '' => '竗', '' => '苗', '' => '錨', '' => '務', '' => '巫', '' => '憮', '' => '懋', '' => '戊', '' => '拇', '' => '撫', '' => '无', '' => '楙', '' => '武', '' => '毋', '' => '無', '' => '珷', '' => '畝', '' => '繆', '' => '舞', '' => '茂', '' => '蕪', '' => '誣', '' => '貿', '' => '霧', '' => '鵡', '' => '墨', '' => '默', '' => '們', '' => '刎', '' => '吻', '' => '問', '' => '文', 'ڡ' => '汶', 'ڢ' => '紊', 'ڣ' => '紋', 'ڤ' => '聞', 'ڥ' => '蚊', 'ڦ' => '門', 'ڧ' => '雯', 'ڨ' => '勿', 'ک' => '沕', 'ڪ' => '物', 'ګ' => '味', 'ڬ' => '媚', 'ڭ' => '尾', 'ڮ' => '嵋', 'گ' => '彌', 'ڰ' => '微', 'ڱ' => '未', 'ڲ' => '梶', 'ڳ' => '楣', 'ڴ' => '渼', 'ڵ' => '湄', 'ڶ' => '眉', 'ڷ' => '米', 'ڸ' => '美', 'ڹ' => '薇', 'ں' => '謎', 'ڻ' => '迷', 'ڼ' => '靡', 'ڽ' => '黴', 'ھ' => '岷', 'ڿ' => '悶', '' => '愍', '' => '憫', '' => '敏', '' => '旻', '' => '旼', '' => '民', '' => '泯', '' => '玟', '' => '珉', '' => '緡', '' => '閔', '' => '密', '' => '蜜', '' => '謐', '' => '剝', '' => '博', '' => '拍', '' => '搏', '' => '撲', '' => '朴', '' => '樸', '' => '泊', '' => '珀', '' => '璞', '' => '箔', '' => '粕', '' => '縛', '' => '膊', '' => '舶', '' => '薄', '' => '迫', '' => '雹', '' => '駁', '' => '伴', '' => '半', '' => '反', '' => '叛', '' => '拌', '' => '搬', '' => '攀', '' => '斑', '' => '槃', '' => '泮', '' => '潘', '' => '班', '' => '畔', '' => '瘢', '' => '盤', '' => '盼', '' => '磐', '' => '磻', '' => '礬', '' => '絆', '' => '般', '' => '蟠', '' => '返', '' => '頒', '' => '飯', '' => '勃', '' => '拔', '' => '撥', '' => '渤', '' => '潑', 'ۡ' => '發', 'ۢ' => '跋', 'ۣ' => '醱', 'ۤ' => '鉢', 'ۥ' => '髮', 'ۦ' => '魃', 'ۧ' => '倣', 'ۨ' => '傍', '۩' => '坊', '۪' => '妨', '۫' => '尨', '۬' => '幇', 'ۭ' => '彷', 'ۮ' => '房', 'ۯ' => '放', '۰' => '方', '۱' => '旁', '۲' => '昉', '۳' => '枋', '۴' => '榜', '۵' => '滂', '۶' => '磅', '۷' => '紡', '۸' => '肪', '۹' => '膀', 'ۺ' => '舫', 'ۻ' => '芳', 'ۼ' => '蒡', '۽' => '蚌', '۾' => '訪', 'ۿ' => '謗', '' => '邦', '' => '防', '' => '龐', '' => '倍', '' => '俳', '' => '北', '' => '培', '' => '徘', '' => '拜', '' => '排', '' => '杯', '' => '湃', '' => '焙', '' => '盃', '' => '背', '' => '胚', '' => '裴', '' => '裵', '' => '褙', '' => '賠', '' => '輩', '' => '配', '' => '陪', '' => '伯', '' => '佰', '' => '帛', '' => '柏', '' => '栢', '' => '白', '' => '百', '' => '魄', '' => '幡', '' => '樊', '' => '煩', '' => '燔', '' => '番', '' => '磻', '' => '繁', '' => '蕃', '' => '藩', '' => '飜', '' => '伐', '' => '筏', '' => '罰', '' => '閥', '' => '凡', '' => '帆', '' => '梵', '' => '氾', '' => '汎', '' => '泛', '' => '犯', '' => '範', '' => '范', '' => '法', '' => '琺', '' => '僻', '' => '劈', '' => '壁', '' => '擘', '' => '檗', '' => '璧', '' => '癖', 'ܡ' => '碧', 'ܢ' => '蘗', 'ܣ' => '闢', 'ܤ' => '霹', 'ܥ' => '便', 'ܦ' => '卞', 'ܧ' => '弁', 'ܨ' => '變', 'ܩ' => '辨', 'ܪ' => '辯', 'ܫ' => '邊', 'ܬ' => '別', 'ܭ' => '瞥', 'ܮ' => '鱉', 'ܯ' => '鼈', 'ܰ' => '丙', 'ܱ' => '倂', 'ܲ' => '兵', 'ܳ' => '屛', 'ܴ' => '幷', 'ܵ' => '昞', 'ܶ' => '昺', 'ܷ' => '柄', 'ܸ' => '棅', 'ܹ' => '炳', 'ܺ' => '甁', 'ܻ' => '病', 'ܼ' => '秉', 'ܽ' => '竝', 'ܾ' => '輧', 'ܿ' => '餠', '' => '騈', '' => '保', '' => '堡', '' => '報', '' => '寶', '' => '普', '' => '步', '' => '洑', '' => '湺', '' => '潽', '' => '珤', '' => '甫', '' => '菩', '' => '補', '' => '褓', '' => '譜', '' => '輔', '' => '伏', '' => '僕', '' => '匐', '' => '卜', '' => '宓', '' => '復', '' => '服', '' => '福', '' => '腹', '' => '茯', '' => '蔔', '' => '複', '' => '覆', '' => '輹', '' => '輻', '' => '馥', '' => '鰒', '' => '本', '' => '乶', '' => '俸', '' => '奉', '' => '封', '' => '峯', '' => '峰', '' => '捧', '' => '棒', '' => '烽', '' => '熢', '' => '琫', '' => '縫', '' => '蓬', '' => '蜂', '' => '逢', '' => '鋒', '' => '鳳', '' => '不', '' => '付', '' => '俯', '' => '傅', '' => '剖', '' => '副', '' => '否', '' => '咐', '' => '埠', '' => '夫', '' => '婦', 'ݡ' => '孚', 'ݢ' => '孵', 'ݣ' => '富', 'ݤ' => '府', 'ݥ' => '復', 'ݦ' => '扶', 'ݧ' => '敷', 'ݨ' => '斧', 'ݩ' => '浮', 'ݪ' => '溥', 'ݫ' => '父', 'ݬ' => '符', 'ݭ' => '簿', 'ݮ' => '缶', 'ݯ' => '腐', 'ݰ' => '腑', 'ݱ' => '膚', 'ݲ' => '艀', 'ݳ' => '芙', 'ݴ' => '莩', 'ݵ' => '訃', 'ݶ' => '負', 'ݷ' => '賦', 'ݸ' => '賻', 'ݹ' => '赴', 'ݺ' => '趺', 'ݻ' => '部', 'ݼ' => '釜', 'ݽ' => '阜', 'ݾ' => '附', 'ݿ' => '駙', '' => '鳧', '' => '北', '' => '分', '' => '吩', '' => '噴', '' => '墳', '' => '奔', '' => '奮', '' => '忿', '' => '憤', '' => '扮', '' => '昐', '' => '汾', '' => '焚', '' => '盆', '' => '粉', '' => '糞', '' => '紛', '' => '芬', '' => '賁', '' => '雰', '' => '不', '' => '佛', '' => '弗', '' => '彿', '' => '拂', '' => '崩', '' => '朋', '' => '棚', '' => '硼', '' => '繃', '' => '鵬', '' => '丕', '' => '備', '' => '匕', '' => '匪', '' => '卑', '' => '妃', '' => '婢', '' => '庇', '' => '悲', '' => '憊', '' => '扉', '' => '批', '' => '斐', '' => '枇', '' => '榧', '' => '比', '' => '毖', '' => '毗', '' => '毘', '' => '沸', '' => '泌', '' => '琵', '' => '痺', '' => '砒', '' => '碑', '' => '秕', '' => '秘', '' => '粃', '' => '緋', '' => '翡', '' => '肥', 'ޡ' => '脾', 'ޢ' => '臂', 'ޣ' => '菲', 'ޤ' => '蜚', 'ޥ' => '裨', 'ަ' => '誹', 'ާ' => '譬', 'ި' => '費', 'ީ' => '鄙', 'ު' => '非', 'ޫ' => '飛', 'ެ' => '鼻', 'ޭ' => '嚬', 'ޮ' => '嬪', 'ޯ' => '彬', 'ް' => '斌', 'ޱ' => '檳', '޲' => '殯', '޳' => '浜', '޴' => '濱', '޵' => '瀕', '޶' => '牝', '޷' => '玭', '޸' => '貧', '޹' => '賓', '޺' => '頻', '޻' => '憑', '޼' => '氷', '޽' => '聘', '޾' => '騁', '޿' => '乍', '' => '事', '' => '些', '' => '仕', '' => '伺', '' => '似', '' => '使', '' => '俟', '' => '僿', '' => '史', '' => '司', '' => '唆', '' => '嗣', '' => '四', '' => '士', '' => '奢', '' => '娑', '' => '寫', '' => '寺', '' => '射', '' => '巳', '' => '師', '' => '徙', '' => '思', '' => '捨', '' => '斜', '' => '斯', '' => '柶', '' => '査', '' => '梭', '' => '死', '' => '沙', '' => '泗', '' => '渣', '' => '瀉', '' => '獅', '' => '砂', '' => '社', '' => '祀', '' => '祠', '' => '私', '' => '篩', '' => '紗', '' => '絲', '' => '肆', '' => '舍', '' => '莎', '' => '蓑', '' => '蛇', '' => '裟', '' => '詐', '' => '詞', '' => '謝', '' => '賜', '' => '赦', '' => '辭', '' => '邪', '' => '飼', '' => '駟', '' => '麝', '' => '削', '' => '數', '' => '朔', '' => '索', 'ߡ' => '傘', 'ߢ' => '刪', 'ߣ' => '山', 'ߤ' => '散', 'ߥ' => '汕', 'ߦ' => '珊', 'ߧ' => '産', 'ߨ' => '疝', 'ߩ' => '算', 'ߪ' => '蒜', '߫' => '酸', '߬' => '霰', '߭' => '乷', '߮' => '撒', '߯' => '殺', '߰' => '煞', '߱' => '薩', '߲' => '三', '߳' => '參', 'ߴ' => '杉', 'ߵ' => '森', '߶' => '渗', '߷' => '芟', '߸' => '蔘', '߹' => '衫', 'ߺ' => '揷', '߻' => '澁', '߼' => '鈒', '߽' => '颯', '߾' => '上', '߿' => '傷', '' => '像', '' => '償', '' => '商', '' => '喪', '' => '嘗', '' => '孀', '' => '尙', '' => '峠', '' => '常', '' => '床', '' => '庠', '' => '廂', '' => '想', '' => '桑', '' => '橡', '' => '湘', '' => '爽', '' => '牀', '' => '狀', '' => '相', '' => '祥', '' => '箱', '' => '翔', '' => '裳', '' => '觴', '' => '詳', '' => '象', '' => '賞', '' => '霜', '' => '塞', '' => '璽', '' => '賽', '' => '嗇', '' => '塞', '' => '穡', '' => '索', '' => '色', '' => '牲', '' => '生', '' => '甥', '' => '省', '' => '笙', '' => '墅', '' => '壻', '' => '嶼', '' => '序', '' => '庶', '' => '徐', '' => '恕', '' => '抒', '' => '捿', '' => '敍', '' => '暑', '' => '曙', '' => '書', '' => '栖', '' => '棲', '' => '犀', '' => '瑞', '' => '筮', '' => '絮', '' => '緖', '' => '署', '' => '胥', '' => '舒', '' => '薯', '' => '西', '' => '誓', '' => '逝', '' => '鋤', '' => '黍', '' => '鼠', '' => '夕', '' => '奭', '' => '席', '' => '惜', '' => '昔', '' => '晳', '' => '析', '' => '汐', '' => '淅', '' => '潟', '' => '石', '' => '碩', '' => '蓆', '' => '釋', '' => '錫', '' => '仙', '' => '僊', '' => '先', '' => '善', '' => '嬋', '' => '宣', '' => '扇', '' => '敾', '' => '旋', '' => '渲', '' => '煽', '' => '琁', '' => '瑄', '' => '璇', '' => '璿', '' => '癬', '' => '禪', '' => '線', '' => '繕', '' => '羨', '' => '腺', '' => '膳', '' => '船', '' => '蘚', '' => '蟬', '' => '詵', '' => '跣', '' => '選', '' => '銑', '' => '鐥', '' => '饍', '' => '鮮', '' => '卨', '' => '屑', '' => '楔', '' => '泄', '' => '洩', '' => '渫', '' => '舌', '' => '薛', '' => '褻', '' => '設', '' => '說', '' => '雪', '' => '齧', '' => '剡', '' => '暹', '' => '殲', '' => '纖', '' => '蟾', '' => '贍', '' => '閃', '' => '陝', '' => '攝', '' => '涉', '' => '燮', '' => '葉', '' => '城', '' => '姓', '' => '宬', '' => '性', '' => '惺', '' => '成', '' => '星', '' => '晟', '' => '猩', '' => '珹', '' => '盛', '' => '省', '' => '筬', '' => '聖', '' => '聲', '' => '腥', '' => '誠', '' => '醒', '' => '世', '' => '勢', '' => '歲', '' => '洗', '' => '稅', '' => '笹', '' => '細', '' => '說', '' => '貰', '' => '召', '' => '嘯', '' => '塑', '' => '宵', '' => '小', '' => '少', '' => '巢', '' => '所', '' => '掃', '' => '搔', '' => '昭', '' => '梳', '' => '沼', '' => '消', '' => '溯', '' => '瀟', '' => '炤', '' => '燒', '' => '甦', '' => '疏', '' => '疎', '' => '瘙', '' => '笑', '' => '篠', '' => '簫', '' => '素', '' => '紹', '' => '蔬', '' => '蕭', '' => '蘇', '' => '訴', '' => '逍', '' => '遡', '' => '邵', '' => '銷', '' => '韶', '' => '騷', '' => '俗', '' => '屬', '' => '束', '' => '涑', '' => '粟', '' => '續', '' => '謖', '' => '贖', '' => '速', '' => '孫', '' => '巽', '' => '損', '' => '蓀', '' => '遜', '' => '飡', '' => '率', '' => '宋', '' => '悚', '' => '松', '' => '淞', '' => '訟', '' => '誦', '' => '送', '' => '頌', '' => '刷', '' => '殺', '' => '灑', '' => '碎', '' => '鎖', '' => '衰', '' => '釗', '' => '修', '' => '受', '' => '嗽', '' => '囚', '' => '垂', '' => '壽', '' => '嫂', '' => '守', '' => '岫', '' => '峀', '' => '帥', '' => '愁', '' => '戍', '' => '手', '' => '授', '' => '搜', '' => '收', '' => '數', '' => '樹', '' => '殊', '' => '水', '' => '洙', '' => '漱', '' => '燧', '' => '狩', '' => '獸', '' => '琇', '' => '璲', '' => '瘦', '' => '睡', '' => '秀', '' => '穗', '' => '竪', '' => '粹', '' => '綏', '' => '綬', '' => '繡', '' => '羞', '' => '脩', '' => '茱', '' => '蒐', '' => '蓚', '' => '藪', '' => '袖', '' => '誰', '' => '讐', '' => '輸', '' => '遂', '' => '邃', '' => '酬', '' => '銖', '' => '銹', '' => '隋', '' => '隧', '' => '隨', '' => '雖', '' => '需', '' => '須', '' => '首', '' => '髓', '' => '鬚', '' => '叔', '' => '塾', '' => '夙', '' => '孰', '' => '宿', '' => '淑', '' => '潚', '' => '熟', '' => '琡', '' => '璹', '' => '肅', '' => '菽', '' => '巡', '' => '徇', '' => '循', '' => '恂', '' => '旬', '' => '栒', '' => '楯', '' => '橓', '' => '殉', '' => '洵', '' => '淳', '' => '珣', '' => '盾', '' => '瞬', '' => '筍', '' => '純', '' => '脣', '' => '舜', '' => '荀', '' => '蓴', '' => '蕣', '' => '詢', '' => '諄', '' => '醇', '' => '錞', '' => '順', '' => '馴', '' => '戌', '' => '術', '' => '述', '' => '鉥', '' => '崇', '' => '崧', '' => '嵩', '' => '瑟', '' => '膝', '' => '蝨', '' => '濕', '' => '拾', '' => '習', '' => '褶', '' => '襲', '' => '丞', '' => '乘', '' => '僧', '' => '勝', '' => '升', '' => '承', '' => '昇', '' => '繩', '' => '蠅', '' => '陞', '' => '侍', '' => '匙', '' => '嘶', '' => '始', '' => '媤', '' => '尸', '' => '屎', '' => '屍', '' => '市', '' => '弑', '' => '恃', '' => '施', '' => '是', '' => '時', '' => '枾', '' => '柴', '' => '猜', '' => '矢', '' => '示', '' => '翅', '' => '蒔', '' => '蓍', '' => '視', '' => '試', '' => '詩', '' => '諡', '' => '豕', '' => '豺', '' => '埴', '' => '寔', '' => '式', '' => '息', '' => '拭', '' => '植', '' => '殖', '' => '湜', '' => '熄', '' => '篒', '' => '蝕', '' => '識', '' => '軾', '' => '食', '' => '飾', '' => '伸', '' => '侁', '' => '信', '' => '呻', '' => '娠', '' => '宸', '' => '愼', '' => '新', '' => '晨', '' => '燼', '' => '申', '' => '神', '' => '紳', '' => '腎', '' => '臣', '' => '莘', '' => '薪', '' => '藎', '' => '蜃', '' => '訊', '' => '身', '' => '辛', '' => '辰', '' => '迅', '' => '失', '' => '室', '' => '實', '' => '悉', '' => '審', '' => '尋', '' => '心', '' => '沁', '' => '沈', '' => '深', '' => '瀋', '' => '甚', '' => '芯', '' => '諶', '' => '什', '' => '十', '' => '拾', '' => '雙', '' => '氏', '' => '亞', '' => '俄', '' => '兒', '' => '啞', '' => '娥', '' => '峨', '' => '我', '' => '牙', '' => '芽', '' => '莪', '' => '蛾', '' => '衙', '' => '訝', '' => '阿', '' => '雅', '' => '餓', '' => '鴉', '' => '鵝', '' => '堊', '' => '岳', '' => '嶽', '' => '幄', '' => '惡', '' => '愕', '' => '握', '' => '樂', '' => '渥', '' => '鄂', '' => '鍔', '' => '顎', '' => '鰐', '' => '齷', '' => '安', '' => '岸', '' => '按', '' => '晏', '' => '案', '' => '眼', '' => '雁', '' => '鞍', '' => '顔', '' => '鮟', '' => '斡', '' => '謁', '' => '軋', '' => '閼', '' => '唵', '' => '岩', '' => '巖', '' => '庵', '' => '暗', '' => '癌', '' => '菴', '' => '闇', '' => '壓', '' => '押', '' => '狎', '' => '鴨', '' => '仰', '' => '央', '' => '怏', '' => '昻', '' => '殃', '' => '秧', '' => '鴦', '' => '厓', '' => '哀', '' => '埃', '' => '崖', '' => '愛', '' => '曖', '' => '涯', '' => '碍', '' => '艾', '' => '隘', '' => '靄', '' => '厄', '' => '扼', '' => '掖', '' => '液', '' => '縊', '' => '腋', '' => '額', '' => '櫻', '' => '罌', '' => '鶯', '' => '鸚', '' => '也', '' => '倻', '' => '冶', '' => '夜', '' => '惹', '' => '揶', '' => '椰', '' => '爺', '' => '耶', '' => '若', '' => '野', '' => '弱', '' => '掠', '' => '略', '' => '約', '' => '若', '' => '葯', '' => '蒻', '' => '藥', '' => '躍', '' => '亮', '' => '佯', '' => '兩', '' => '凉', '' => '壤', '' => '孃', '' => '恙', '' => '揚', '' => '攘', '' => '敭', '' => '暘', '' => '梁', '' => '楊', '' => '樣', '' => '洋', '' => '瀁', '' => '煬', '' => '痒', '' => '瘍', '' => '禳', '' => '穰', '' => '糧', '' => '羊', '' => '良', '' => '襄', '' => '諒', '' => '讓', '' => '釀', '' => '陽', '' => '量', '' => '養', '' => '圄', '' => '御', '' => '於', '' => '漁', '' => '瘀', '' => '禦', '' => '語', '' => '馭', '' => '魚', '' => '齬', '' => '億', '' => '憶', '' => '抑', '' => '檍', '' => '臆', '' => '偃', '' => '堰', '' => '彦', '' => '焉', '' => '言', '' => '諺', '' => '孼', '' => '蘖', '' => '俺', '' => '儼', '' => '嚴', '' => '奄', '' => '掩', '' => '淹', '' => '嶪', '' => '業', '' => '円', '' => '予', '' => '余', '' => '勵', '' => '呂', '' => '女', '' => '如', '' => '廬', '' => '旅', '' => '歟', '' => '汝', '' => '濾', '' => '璵', '' => '礖', '' => '礪', '' => '與', '' => '艅', '' => '茹', '' => '輿', '' => '轝', '' => '閭', '' => '餘', '' => '驪', '' => '麗', '' => '黎', '' => '亦', '' => '力', '' => '域', '' => '役', '' => '易', '' => '曆', '' => '歷', '' => '疫', '' => '繹', '' => '譯', '' => '轢', '' => '逆', '' => '驛', '' => '嚥', '' => '堧', '' => '姸', '' => '娟', '' => '宴', '' => '年', '' => '延', '' => '憐', '' => '戀', '' => '捐', '' => '挻', '' => '撚', '' => '椽', '' => '沇', '' => '沿', '' => '涎', '' => '涓', '' => '淵', '' => '演', '' => '漣', '' => '烟', '' => '然', '' => '煙', '' => '煉', '' => '燃', '' => '燕', '' => '璉', '' => '硏', '' => '硯', '' => '秊', '' => '筵', '' => '緣', '' => '練', '' => '縯', '' => '聯', '' => '衍', '' => '軟', '' => '輦', '' => '蓮', '' => '連', '' => '鉛', '' => '鍊', '' => '鳶', '' => '列', '' => '劣', '' => '咽', '' => '悅', '' => '涅', '' => '烈', '' => '熱', '' => '裂', '' => '說', '' => '閱', '' => '厭', '' => '廉', '' => '念', '' => '捻', '' => '染', '' => '殮', '' => '炎', '' => '焰', '' => '琰', '' => '艶', '' => '苒', '' => '簾', '' => '閻', '' => '髥', '' => '鹽', '' => '曄', '' => '獵', '' => '燁', '' => '葉', '' => '令', '' => '囹', '' => '塋', '' => '寧', '' => '嶺', '' => '嶸', '' => '影', '' => '怜', '' => '映', '' => '暎', '' => '楹', '' => '榮', '' => '永', '' => '泳', '' => '渶', '' => '潁', '' => '濚', '' => '瀛', '' => '瀯', '' => '煐', '' => '營', '' => '獰', '' => '玲', '' => '瑛', '' => '瑩', '' => '瓔', '' => '盈', '' => '穎', '' => '纓', '' => '羚', '' => '聆', '' => '英', '' => '詠', '' => '迎', '' => '鈴', '' => '鍈', '' => '零', '' => '霙', '' => '靈', '' => '領', '' => '乂', '' => '倪', '' => '例', '' => '刈', '' => '叡', '' => '曳', '' => '汭', '' => '濊', '' => '猊', '' => '睿', '' => '穢', '' => '芮', '' => '藝', '' => '蘂', '' => '禮', '' => '裔', '' => '詣', '' => '譽', '' => '豫', '' => '醴', '' => '銳', '' => '隸', '' => '霓', '' => '預', '' => '五', '' => '伍', '' => '俉', '' => '傲', '' => '午', '' => '吾', '' => '吳', '' => '嗚', '' => '塢', '' => '墺', '' => '奧', '' => '娛', '' => '寤', '' => '悟', '' => '惡', '' => '懊', '' => '敖', '' => '旿', '' => '晤', '' => '梧', '' => '汚', '' => '澳', '' => '烏', '' => '熬', '' => '獒', '' => '筽', '' => '蜈', '' => '誤', '' => '鰲', '' => '鼇', '' => '屋', '' => '沃', '' => '獄', '' => '玉', '' => '鈺', '' => '溫', '' => '瑥', '' => '瘟', '' => '穩', '' => '縕', '' => '蘊', '' => '兀', '' => '壅', '' => '擁', '' => '瓮', '' => '甕', '' => '癰', '' => '翁', '' => '邕', '' => '雍', '' => '饔', '' => '渦', '' => '瓦', '' => '窩', '' => '窪', '' => '臥', '' => '蛙', '' => '蝸', '' => '訛', '' => '婉', '' => '完', '' => '宛', '' => '梡', '' => '椀', '' => '浣', '' => '玩', '' => '琓', '' => '琬', '' => '碗', '' => '緩', '' => '翫', '' => '脘', '' => '腕', '' => '莞', '' => '豌', '' => '阮', '' => '頑', '' => '曰', '' => '往', '' => '旺', '' => '枉', '' => '汪', '' => '王', '' => '倭', '' => '娃', '' => '歪', '' => '矮', '' => '外', '' => '嵬', '' => '巍', '' => '猥', '' => '畏', '' => '了', '' => '僚', '' => '僥', '' => '凹', '' => '堯', '' => '夭', '' => '妖', '' => '姚', '' => '寥', '' => '寮', '' => '尿', '' => '嶢', '' => '拗', '' => '搖', '' => '撓', '' => '擾', '' => '料', '' => '曜', '' => '樂', '' => '橈', '' => '燎', '' => '燿', '' => '瑤', '' => '療', '' => '窈', '' => '窯', '' => '繇', '' => '繞', '' => '耀', '' => '腰', '' => '蓼', '' => '蟯', '' => '要', '' => '謠', '' => '遙', '' => '遼', '' => '邀', '' => '饒', '' => '慾', '' => '欲', '' => '浴', '' => '縟', '' => '褥', '' => '辱', '' => '俑', '' => '傭', '' => '冗', '' => '勇', '' => '埇', '' => '墉', '' => '容', '' => '庸', '' => '慂', '' => '榕', '' => '涌', '' => '湧', '' => '溶', '' => '熔', '' => '瑢', '' => '用', '' => '甬', '' => '聳', '' => '茸', '' => '蓉', '' => '踊', '' => '鎔', '' => '鏞', '' => '龍', '' => '于', '' => '佑', '' => '偶', '' => '優', '' => '又', '' => '友', '' => '右', '' => '宇', '' => '寓', '' => '尤', '' => '愚', '' => '憂', '' => '旴', '' => '牛', '' => '玗', '' => '瑀', '' => '盂', '' => '祐', '' => '禑', '' => '禹', '' => '紆', '' => '羽', '' => '芋', '' => '藕', '' => '虞', '' => '迂', '' => '遇', '' => '郵', '' => '釪', '' => '隅', '' => '雨', '' => '雩', '' => '勖', '' => '彧', '' => '旭', '' => '昱', '' => '栯', '' => '煜', '' => '稶', '' => '郁', '' => '頊', '' => '云', '' => '暈', '' => '橒', '' => '殞', '' => '澐', '' => '熉', '' => '耘', '' => '芸', '' => '蕓', '' => '運', '' => '隕', '' => '雲', '' => '韻', '' => '蔚', '' => '鬱', '' => '亐', '' => '熊', '' => '雄', '' => '元', '' => '原', '' => '員', '' => '圓', '' => '園', '' => '垣', '' => '媛', '' => '嫄', '' => '寃', '' => '怨', '' => '愿', '' => '援', '' => '沅', '' => '洹', '' => '湲', '' => '源', '' => '爰', '' => '猿', '' => '瑗', '' => '苑', '' => '袁', '' => '轅', '' => '遠', '' => '阮', '' => '院', '' => '願', '' => '鴛', '' => '月', '' => '越', '' => '鉞', '' => '位', '' => '偉', '' => '僞', '' => '危', '' => '圍', '' => '委', '' => '威', '' => '尉', '' => '慰', '' => '暐', '' => '渭', '' => '爲', '' => '瑋', '' => '緯', '' => '胃', '' => '萎', '' => '葦', '' => '蔿', '' => '蝟', '' => '衛', '' => '褘', '' => '謂', '' => '違', '' => '韋', '' => '魏', '' => '乳', '' => '侑', '' => '儒', '' => '兪', '' => '劉', '' => '唯', '' => '喩', '' => '孺', '' => '宥', '' => '幼', '' => '幽', '' => '庾', '' => '悠', '' => '惟', '' => '愈', '' => '愉', '' => '揄', '' => '攸', '' => '有', '' => '杻', '' => '柔', '' => '柚', '' => '柳', '' => '楡', '' => '楢', '' => '油', '' => '洧', '' => '流', '' => '游', '' => '溜', '' => '濡', '' => '猶', '' => '猷', '' => '琉', '' => '瑜', '' => '由', '' => '留', '' => '癒', '' => '硫', '' => '紐', '' => '維', '' => '臾', '' => '萸', '' => '裕', '' => '誘', '' => '諛', '' => '諭', '' => '踰', '' => '蹂', '' => '遊', '' => '逾', '' => '遺', '' => '酉', '' => '釉', '' => '鍮', '' => '類', '' => '六', '' => '堉', '' => '戮', '' => '毓', '' => '肉', '' => '育', '' => '陸', '' => '倫', '' => '允', '' => '奫', '' => '尹', '' => '崙', '' => '淪', '' => '潤', '' => '玧', '' => '胤', '' => '贇', '' => '輪', '' => '鈗', '' => '閏', '' => '律', '' => '慄', '' => '栗', '' => '率', '' => '聿', '' => '戎', '' => '瀜', '' => '絨', '' => '融', '' => '隆', '' => '垠', '' => '恩', '' => '慇', '' => '殷', '' => '誾', '' => '銀', '' => '隱', '' => '乙', '' => '吟', '' => '淫', '' => '蔭', '' => '陰', '' => '音', '' => '飮', '' => '揖', '' => '泣', '' => '邑', '' => '凝', '' => '應', '' => '膺', '' => '鷹', '' => '依', '' => '倚', '' => '儀', '' => '宜', '' => '意', '' => '懿', '' => '擬', '' => '椅', '' => '毅', '' => '疑', '' => '矣', '' => '義', '' => '艤', '' => '薏', '' => '蟻', '' => '衣', '' => '誼', '' => '議', '' => '醫', '' => '二', '' => '以', '' => '伊', '' => '利', '' => '吏', '' => '夷', '' => '姨', '' => '履', '' => '已', '' => '弛', '' => '彛', '' => '怡', '' => '易', '' => '李', '' => '梨', '' => '泥', '' => '爾', '' => '珥', '' => '理', '' => '異', '' => '痍', '' => '痢', '' => '移', '' => '罹', '' => '而', '' => '耳', '' => '肄', '' => '苡', '' => '荑', '' => '裏', '' => '裡', '' => '貽', '' => '貳', '' => '邇', '' => '里', '' => '離', '' => '飴', '' => '餌', '' => '匿', '' => '溺', '' => '瀷', '' => '益', '' => '翊', '' => '翌', '' => '翼', '' => '謚', '' => '人', '' => '仁', '' => '刃', '' => '印', '' => '吝', '' => '咽', '' => '因', '' => '姻', '' => '寅', '' => '引', '' => '忍', '' => '湮', '' => '燐', '' => '璘', '' => '絪', '' => '茵', '' => '藺', '' => '蚓', '' => '認', '' => '隣', '' => '靭', '' => '靷', '' => '鱗', '' => '麟', '' => '一', '' => '佚', '' => '佾', '' => '壹', '' => '日', '' => '溢', '' => '逸', '' => '鎰', '' => '馹', '' => '任', '' => '壬', '' => '妊', '' => '姙', '' => '恁', '' => '林', '' => '淋', '' => '稔', '' => '臨', '' => '荏', '' => '賃', '' => '入', '' => '卄', '' => '立', '' => '笠', '' => '粒', '' => '仍', '' => '剩', '' => '孕', '' => '芿', '' => '仔', '' => '刺', '' => '咨', '' => '姉', '' => '姿', '' => '子', '' => '字', '' => '孜', '' => '恣', '' => '慈', '' => '滋', '' => '炙', '' => '煮', '' => '玆', '' => '瓷', '' => '疵', '' => '磁', '' => '紫', '' => '者', '' => '自', '' => '茨', '' => '蔗', '' => '藉', '' => '諮', '' => '資', '' => '雌', '' => '作', '' => '勺', '' => '嚼', '' => '斫', '' => '昨', '' => '灼', '' => '炸', '' => '爵', '' => '綽', '' => '芍', '' => '酌', '' => '雀', '' => '鵲', '' => '孱', '' => '棧', '' => '殘', '' => '潺', '' => '盞', '' => '岑', '' => '暫', '' => '潛', '' => '箴', '' => '簪', '' => '蠶', '' => '雜', '' => '丈', '' => '仗', '' => '匠', '' => '場', '' => '墻', '' => '壯', '' => '奬', '' => '將', '' => '帳', '' => '庄', '' => '張', '' => '掌', '' => '暲', '' => '杖', '' => '樟', '' => '檣', '' => '欌', '' => '漿', '' => '牆', '' => '狀', '' => '獐', '' => '璋', '' => '章', '' => '粧', '' => '腸', '' => '臟', '' => '臧', '' => '莊', '' => '葬', '' => '蔣', '' => '薔', '' => '藏', '' => '裝', '' => '贓', '' => '醬', '' => '長', '' => '障', '' => '再', '' => '哉', '' => '在', '' => '宰', '' => '才', '' => '材', '' => '栽', '' => '梓', '' => '渽', '' => '滓', '' => '災', '' => '縡', '' => '裁', '' => '財', '' => '載', '' => '齋', '' => '齎', '' => '爭', '' => '箏', '' => '諍', '' => '錚', '' => '佇', '' => '低', '' => '儲', '' => '咀', '' => '姐', '' => '底', '' => '抵', '' => '杵', '' => '楮', '' => '樗', '' => '沮', '' => '渚', '' => '狙', '' => '猪', '' => '疽', '' => '箸', '' => '紵', '' => '苧', '' => '菹', '' => '著', '' => '藷', '' => '詛', '' => '貯', '' => '躇', '' => '這', '' => '邸', '' => '雎', '' => '齟', '' => '勣', '' => '吊', '' => '嫡', '' => '寂', '' => '摘', '' => '敵', '' => '滴', '' => '狄', '' => '炙', '' => '的', '' => '積', '' => '笛', '' => '籍', '' => '績', '' => '翟', '' => '荻', '' => '謫', '' => '賊', '' => '赤', '' => '跡', '' => '蹟', '' => '迪', '' => '迹', '' => '適', '' => '鏑', '' => '佃', '' => '佺', '' => '傳', '' => '全', '' => '典', '' => '前', '' => '剪', '' => '塡', '' => '塼', '' => '奠', '' => '專', '' => '展', '' => '廛', '' => '悛', '' => '戰', '' => '栓', '' => '殿', '' => '氈', '' => '澱', '' => '煎', '' => '琠', '' => '田', '' => '甸', '' => '畑', '' => '癲', '' => '筌', '' => '箋', '' => '箭', '' => '篆', '' => '纏', '' => '詮', '' => '輾', '' => '轉', '' => '鈿', '' => '銓', '' => '錢', '' => '鐫', '' => '電', '' => '顚', '' => '顫', '' => '餞', '' => '切', '' => '截', '' => '折', '' => '浙', '' => '癤', '' => '竊', '' => '節', '' => '絶', '' => '占', '' => '岾', '' => '店', '' => '漸', '' => '点', '' => '粘', '' => '霑', '' => '鮎', '' => '點', '' => '接', '' => '摺', '' => '蝶', '' => '丁', '' => '井', '' => '亭', '' => '停', '' => '偵', '' => '呈', '' => '姃', '' => '定', '' => '幀', '' => '庭', '' => '廷', '' => '征', '' => '情', '' => '挺', '' => '政', '' => '整', '' => '旌', '' => '晶', '' => '晸', '' => '柾', '' => '楨', '' => '檉', '' => '正', '' => '汀', '' => '淀', '' => '淨', '' => '渟', '' => '湞', '' => '瀞', '' => '炡', '' => '玎', '' => '珽', '' => '町', '' => '睛', '' => '碇', '' => '禎', '' => '程', '' => '穽', '' => '精', '' => '綎', '' => '艇', '' => '訂', '' => '諪', '' => '貞', '' => '鄭', '' => '酊', '' => '釘', '' => '鉦', '' => '鋌', '' => '錠', '' => '霆', '' => '靖', '' => '靜', '' => '頂', '' => '鼎', '' => '制', '' => '劑', '' => '啼', '' => '堤', '' => '帝', '' => '弟', '' => '悌', '' => '提', '' => '梯', '' => '濟', '' => '祭', '' => '第', '' => '臍', '' => '薺', '' => '製', '' => '諸', '' => '蹄', '' => '醍', '' => '除', '' => '際', '' => '霽', '' => '題', '' => '齊', '' => '俎', '' => '兆', '' => '凋', '' => '助', '' => '嘲', '' => '弔', '' => '彫', '' => '措', '' => '操', '' => '早', '' => '晁', '' => '曺', '' => '曹', '' => '朝', '' => '條', '' => '棗', '' => '槽', '' => '漕', '' => '潮', '' => '照', '' => '燥', '' => '爪', '' => '璪', '' => '眺', '' => '祖', '' => '祚', '' => '租', '' => '稠', '' => '窕', '' => '粗', '' => '糟', '' => '組', '' => '繰', '' => '肇', '' => '藻', '' => '蚤', '' => '詔', '' => '調', '' => '趙', '' => '躁', '' => '造', '' => '遭', '' => '釣', '' => '阻', '' => '雕', '' => '鳥', '' => '族', '' => '簇', '' => '足', '' => '鏃', '' => '存', '' => '尊', '' => '卒', '' => '拙', '' => '猝', '' => '倧', '' => '宗', '' => '從', '' => '悰', '' => '慫', '' => '棕', '' => '淙', '' => '琮', '' => '種', '' => '終', '' => '綜', '' => '縱', '' => '腫', '' => '踪', '' => '踵', '' => '鍾', '' => '鐘', '' => '佐', '' => '坐', '' => '左', '' => '座', '' => '挫', '' => '罪', '' => '主', '' => '住', '' => '侏', '' => '做', '' => '姝', '' => '胄', '' => '呪', '' => '周', '' => '嗾', '' => '奏', '' => '宙', '' => '州', '' => '廚', '' => '晝', '' => '朱', '' => '柱', '' => '株', '' => '注', '' => '洲', '' => '湊', '' => '澍', '' => '炷', '' => '珠', '' => '疇', '' => '籌', '' => '紂', '' => '紬', '' => '綢', '' => '舟', '' => '蛛', '' => '註', '' => '誅', '' => '走', '' => '躊', '' => '輳', '' => '週', '' => '酎', '' => '酒', '' => '鑄', '' => '駐', '' => '竹', '' => '粥', '' => '俊', '' => '儁', '' => '准', '' => '埈', '' => '寯', '' => '峻', '' => '晙', '' => '樽', '' => '浚', '' => '準', '' => '濬', '' => '焌', '' => '畯', '' => '竣', '' => '蠢', '' => '逡', '' => '遵', '' => '雋', '' => '駿', '' => '茁', '' => '中', '' => '仲', '' => '衆', '' => '重', '' => '卽', '' => '櫛', '' => '楫', '' => '汁', '' => '葺', '' => '增', '' => '憎', '' => '曾', '' => '拯', '' => '烝', '' => '甑', '' => '症', '' => '繒', '' => '蒸', '' => '證', '' => '贈', '' => '之', '' => '只', '' => '咫', '' => '地', '' => '址', '' => '志', '' => '持', '' => '指', '' => '摯', '' => '支', '' => '旨', '' => '智', '' => '枝', '' => '枳', '' => '止', '' => '池', '' => '沚', '' => '漬', '' => '知', '' => '砥', '' => '祉', '' => '祗', '' => '紙', '' => '肢', '' => '脂', '' => '至', '' => '芝', '' => '芷', '' => '蜘', '' => '誌', '' => '識', '' => '贄', '' => '趾', '' => '遲', '' => '直', '' => '稙', '' => '稷', '' => '織', '' => '職', '' => '唇', '' => '嗔', '' => '塵', '' => '振', '' => '搢', '' => '晉', '' => '晋', '' => '桭', '' => '榛', '' => '殄', '' => '津', '' => '溱', '' => '珍', '' => '瑨', '' => '璡', '' => '畛', '' => '疹', '' => '盡', '' => '眞', '' => '瞋', '' => '秦', '' => '縉', '' => '縝', '' => '臻', '' => '蔯', '' => '袗', '' => '診', '' => '賑', '' => '軫', '' => '辰', '' => '進', '' => '鎭', '' => '陣', '' => '陳', '' => '震', '' => '侄', '' => '叱', '' => '姪', '' => '嫉', '' => '帙', '' => '桎', '' => '瓆', '' => '疾', '' => '秩', '' => '窒', '' => '膣', '' => '蛭', '' => '質', '' => '跌', '' => '迭', '' => '斟', '' => '朕', '' => '什', '' => '執', '' => '潗', '' => '緝', '' => '輯', '' => '鏶', '' => '集', '' => '徵', '' => '懲', '' => '澄', '' => '且', '' => '侘', '' => '借', '' => '叉', '' => '嗟', '' => '嵯', '' => '差', '' => '次', '' => '此', '' => '磋', '' => '箚', '' => '茶', '' => '蹉', '' => '車', '' => '遮', '' => '捉', '' => '搾', '' => '着', '' => '窄', '' => '錯', '' => '鑿', '' => '齪', '' => '撰', '' => '澯', '' => '燦', '' => '璨', '' => '瓚', '' => '竄', '' => '簒', '' => '纂', '' => '粲', '' => '纘', '' => '讚', '' => '贊', '' => '鑽', '' => '餐', '' => '饌', '' => '刹', '' => '察', '' => '擦', '' => '札', '' => '紮', '' => '僭', '' => '參', '' => '塹', '' => '慘', '' => '慙', '' => '懺', '' => '斬', '' => '站', '' => '讒', '' => '讖', '' => '倉', '' => '倡', '' => '創', '' => '唱', '' => '娼', '' => '廠', '' => '彰', '' => '愴', '' => '敞', '' => '昌', '' => '昶', '' => '暢', '' => '槍', '' => '滄', '' => '漲', '' => '猖', '' => '瘡', '' => '窓', '' => '脹', '' => '艙', '' => '菖', '' => '蒼', '' => '債', '' => '埰', '' => '寀', '' => '寨', '' => '彩', '' => '採', '' => '砦', '' => '綵', '' => '菜', '' => '蔡', '' => '采', '' => '釵', '' => '冊', '' => '柵', '' => '策', '' => '責', '' => '凄', '' => '妻', '' => '悽', '' => '處', '' => '倜', '' => '刺', '' => '剔', '' => '尺', '' => '慽', '' => '戚', '' => '拓', '' => '擲', '' => '斥', '' => '滌', '' => '瘠', '' => '脊', '' => '蹠', '' => '陟', '' => '隻', '' => '仟', '' => '千', '' => '喘', '' => '天', '' => '川', '' => '擅', '' => '泉', '' => '淺', '' => '玔', '' => '穿', '' => '舛', '' => '薦', '' => '賤', '' => '踐', '' => '遷', '' => '釧', '' => '闡', '' => '阡', '' => '韆', '' => '凸', '' => '哲', '' => '喆', '' => '徹', '' => '撤', '' => '澈', '' => '綴', '' => '輟', '' => '轍', '' => '鐵', '' => '僉', '' => '尖', '' => '沾', '' => '添', '' => '甛', '' => '瞻', '' => '簽', '' => '籤', '' => '詹', '' => '諂', '' => '堞', '' => '妾', '' => '帖', '' => '捷', '' => '牒', '' => '疊', '' => '睫', '' => '諜', '' => '貼', '' => '輒', '' => '廳', '' => '晴', '' => '淸', '' => '聽', '' => '菁', '' => '請', '' => '靑', '' => '鯖', '' => '切', '' => '剃', '' => '替', '' => '涕', '' => '滯', '' => '締', '' => '諦', '' => '逮', '' => '遞', '' => '體', '' => '初', '' => '剿', '' => '哨', '' => '憔', '' => '抄', '' => '招', '' => '梢', '' => '椒', '' => '楚', '' => '樵', '' => '炒', '' => '焦', '' => '硝', '' => '礁', '' => '礎', '' => '秒', '' => '稍', '' => '肖', '' => '艸', '' => '苕', '' => '草', '' => '蕉', '' => '貂', '' => '超', '' => '酢', '' => '醋', '' => '醮', '' => '促', '' => '囑', '' => '燭', '' => '矗', '' => '蜀', '' => '觸', '' => '寸', '' => '忖', '' => '村', '' => '邨', '' => '叢', '' => '塚', '' => '寵', '' => '悤', '' => '憁', '' => '摠', '' => '總', '' => '聰', '' => '蔥', '' => '銃', '' => '撮', '' => '催', '' => '崔', '' => '最', '' => '墜', '' => '抽', '' => '推', '' => '椎', '' => '楸', '' => '樞', '' => '湫', '' => '皺', '' => '秋', '' => '芻', '' => '萩', '' => '諏', '' => '趨', '' => '追', '' => '鄒', '' => '酋', '' => '醜', '' => '錐', '' => '錘', '' => '鎚', '' => '雛', '' => '騶', '' => '鰍', '' => '丑', '' => '畜', '' => '祝', '' => '竺', '' => '筑', '' => '築', '' => '縮', '' => '蓄', '' => '蹙', '' => '蹴', '' => '軸', '' => '逐', '' => '春', '' => '椿', '' => '瑃', '' => '出', '' => '朮', '' => '黜', '' => '充', '' => '忠', '' => '沖', '' => '蟲', '' => '衝', '' => '衷', '' => '悴', '' => '膵', '' => '萃', '' => '贅', '' => '取', '' => '吹', '' => '嘴', '' => '娶', '' => '就', '' => '炊', '' => '翠', '' => '聚', '' => '脆', '' => '臭', '' => '趣', '' => '醉', '' => '驟', '' => '鷲', '' => '側', '' => '仄', '' => '厠', '' => '惻', '' => '測', '' => '層', '' => '侈', '' => '値', '' => '嗤', '' => '峙', '' => '幟', '' => '恥', '' => '梔', '' => '治', '' => '淄', '' => '熾', '' => '痔', '' => '痴', '' => '癡', '' => '稚', '' => '穉', '' => '緇', '' => '緻', '' => '置', '' => '致', '' => '蚩', '' => '輜', '' => '雉', '' => '馳', '' => '齒', '' => '則', '' => '勅', '' => '飭', '' => '親', '' => '七', '' => '柒', '' => '漆', '' => '侵', '' => '寢', '' => '枕', '' => '沈', '' => '浸', '' => '琛', '' => '砧', '' => '針', '' => '鍼', '' => '蟄', '' => '秤', '' => '稱', '' => '快', '' => '他', '' => '咤', '' => '唾', '' => '墮', '' => '妥', '' => '惰', '' => '打', '' => '拖', '' => '朶', '' => '楕', '' => '舵', '' => '陀', '' => '馱', '' => '駝', '' => '倬', '' => '卓', '' => '啄', '' => '坼', '' => '度', '' => '托', '' => '拓', '' => '擢', '' => '晫', '' => '柝', '' => '濁', '' => '濯', '' => '琢', '' => '琸', '' => '託', '' => '鐸', '' => '呑', '' => '嘆', '' => '坦', '' => '彈', '' => '憚', '' => '歎', '' => '灘', '' => '炭', '' => '綻', '' => '誕', '' => '奪', '' => '脫', '' => '探', '' => '眈', '' => '耽', '' => '貪', '' => '塔', '' => '搭', '' => '榻', '' => '宕', '' => '帑', '' => '湯', '' => '糖', '' => '蕩', '' => '兌', '' => '台', '' => '太', '' => '怠', '' => '態', '' => '殆', '' => '汰', '' => '泰', '' => '笞', '' => '胎', '' => '苔', '' => '跆', '' => '邰', '' => '颱', '' => '宅', '' => '擇', '' => '澤', '' => '撑', '' => '攄', '' => '兎', '' => '吐', '' => '土', '' => '討', '' => '慟', '' => '桶', '' => '洞', '' => '痛', '' => '筒', '' => '統', '' => '通', '' => '堆', '' => '槌', '' => '腿', '' => '褪', '' => '退', '' => '頹', '' => '偸', '' => '套', '' => '妬', '' => '投', '' => '透', '' => '鬪', '' => '慝', '' => '特', '' => '闖', '' => '坡', '' => '婆', '' => '巴', '' => '把', '' => '播', '' => '擺', '' => '杷', '' => '波', '' => '派', '' => '爬', '' => '琶', '' => '破', '' => '罷', '' => '芭', '' => '跛', '' => '頗', '' => '判', '' => '坂', '' => '板', '' => '版', '' => '瓣', '' => '販', '' => '辦', '' => '鈑', '' => '阪', '' => '八', '' => '叭', '' => '捌', '' => '佩', '' => '唄', '' => '悖', '' => '敗', '' => '沛', '' => '浿', '' => '牌', '' => '狽', '' => '稗', '' => '覇', '' => '貝', '' => '彭', '' => '澎', '' => '烹', '' => '膨', '' => '愎', '' => '便', '' => '偏', '' => '扁', '' => '片', '' => '篇', '' => '編', '' => '翩', '' => '遍', '' => '鞭', '' => '騙', '' => '貶', '' => '坪', '' => '平', '' => '枰', '' => '萍', '' => '評', '' => '吠', '' => '嬖', '' => '幣', '' => '廢', '' => '弊', '' => '斃', '' => '肺', '' => '蔽', '' => '閉', '' => '陛', '' => '佈', '' => '包', '' => '匍', '' => '匏', '' => '咆', '' => '哺', '' => '圃', '' => '布', '' => '怖', '' => '抛', '' => '抱', '' => '捕', '' => '暴', '' => '泡', '' => '浦', '' => '疱', '' => '砲', '' => '胞', '' => '脯', '' => '苞', '' => '葡', '' => '蒲', '' => '袍', '' => '褒', '' => '逋', '' => '鋪', '' => '飽', '' => '鮑', '' => '幅', '' => '暴', '' => '曝', '' => '瀑', '' => '爆', '' => '輻', '' => '俵', '' => '剽', '' => '彪', '' => '慓', '' => '杓', '' => '標', '' => '漂', '' => '瓢', '' => '票', '' => '表', '' => '豹', '' => '飇', '' => '飄', '' => '驃', '' => '品', '' => '稟', '' => '楓', '' => '諷', '' => '豊', '' => '風', '' => '馮', '' => '彼', '' => '披', '' => '疲', '' => '皮', '' => '被', '' => '避', '' => '陂', '' => '匹', '' => '弼', '' => '必', '' => '泌', '' => '珌', '' => '畢', '' => '疋', '' => '筆', '' => '苾', '' => '馝', '' => '乏', '' => '逼', '' => '下', '' => '何', '' => '厦', '' => '夏', '' => '廈', '' => '昰', '' => '河', '' => '瑕', '' => '荷', '' => '蝦', '' => '賀', '' => '遐', '' => '霞', '' => '鰕', '' => '壑', '' => '學', '' => '虐', '' => '謔', '' => '鶴', '' => '寒', '' => '恨', '' => '悍', '' => '旱', '' => '汗', '' => '漢', '' => '澣', '' => '瀚', '' => '罕', '' => '翰', '' => '閑', '' => '閒', '' => '限', '' => '韓', '' => '割', '' => '轄', '' => '函', '' => '含', '' => '咸', '' => '啣', '' => '喊', '' => '檻', '' => '涵', '' => '緘', '' => '艦', '' => '銜', '' => '陷', '' => '鹹', '' => '合', '' => '哈', '' => '盒', '' => '蛤', '' => '閤', '' => '闔', '' => '陜', '' => '亢', '' => '伉', '' => '姮', '' => '嫦', '' => '巷', '' => '恒', '' => '抗', '' => '杭', '' => '桁', '' => '沆', '' => '港', '' => '缸', '' => '肛', '' => '航', '' => '行', '' => '降', '' => '項', '' => '亥', '' => '偕', '' => '咳', '' => '垓', '' => '奚', '' => '孩', '' => '害', '' => '懈', '' => '楷', '' => '海', '' => '瀣', '' => '蟹', '' => '解', '' => '該', '' => '諧', '' => '邂', '' => '駭', '' => '骸', '' => '劾', '' => '核', '' => '倖', '' => '幸', '' => '杏', '' => '荇', '' => '行', '' => '享', '' => '向', '' => '嚮', '' => '珦', '' => '鄕', '' => '響', '' => '餉', '' => '饗', '' => '香', '' => '噓', '' => '墟', '' => '虛', '' => '許', '' => '憲', '' => '櫶', '' => '獻', '' => '軒', '' => '歇', '' => '險', '' => '驗', '' => '奕', '' => '爀', '' => '赫', '' => '革', '' => '俔', '' => '峴', '' => '弦', '' => '懸', '' => '晛', '' => '泫', '' => '炫', '' => '玄', '' => '玹', '' => '現', '' => '眩', '' => '睍', '' => '絃', '' => '絢', '' => '縣', '' => '舷', '' => '衒', '' => '見', '' => '賢', '' => '鉉', '' => '顯', '' => '孑', '' => '穴', '' => '血', '' => '頁', '' => '嫌', '' => '俠', '' => '協', '' => '夾', '' => '峽', '' => '挾', '' => '浹', '' => '狹', '' => '脅', '' => '脇', '' => '莢', '' => '鋏', '' => '頰', '' => '亨', '' => '兄', '' => '刑', '' => '型', '' => '形', '' => '泂', '' => '滎', '' => '瀅', '' => '灐', '' => '炯', '' => '熒', '' => '珩', '' => '瑩', '' => '荊', '' => '螢', '' => '衡', '' => '逈', '' => '邢', '' => '鎣', '' => '馨', '' => '兮', '' => '彗', '' => '惠', '' => '慧', '' => '暳', '' => '蕙', '' => '蹊', '' => '醯', '' => '鞋', '' => '乎', '' => '互', '' => '呼', '' => '壕', '' => '壺', '' => '好', '' => '岵', '' => '弧', '' => '戶', '' => '扈', '' => '昊', '' => '晧', '' => '毫', '' => '浩', '' => '淏', '' => '湖', '' => '滸', '' => '澔', '' => '濠', '' => '濩', '' => '灝', '' => '狐', '' => '琥', '' => '瑚', '' => '瓠', '' => '皓', '' => '祜', '' => '糊', '' => '縞', '' => '胡', '' => '芦', '' => '葫', '' => '蒿', '' => '虎', '' => '號', '' => '蝴', '' => '護', '' => '豪', '' => '鎬', '' => '頀', '' => '顥', '' => '惑', '' => '或', '' => '酷', '' => '婚', '' => '昏', '' => '混', '' => '渾', '' => '琿', '' => '魂', '' => '忽', '' => '惚', '' => '笏', '' => '哄', '' => '弘', '' => '汞', '' => '泓', '' => '洪', '' => '烘', '' => '紅', '' => '虹', '' => '訌', '' => '鴻', '' => '化', '' => '和', '' => '嬅', '' => '樺', '' => '火', '' => '畵', '' => '禍', '' => '禾', '' => '花', '' => '華', '' => '話', '' => '譁', '' => '貨', '' => '靴', '' => '廓', '' => '擴', '' => '攫', '' => '確', '' => '碻', '' => '穫', '' => '丸', '' => '喚', '' => '奐', '' => '宦', '' => '幻', '' => '患', '' => '換', '' => '歡', '' => '晥', '' => '桓', '' => '渙', '' => '煥', '' => '環', '' => '紈', '' => '還', '' => '驩', '' => '鰥', '' => '活', '' => '滑', '' => '猾', '' => '豁', '' => '闊', '' => '凰', '' => '幌', '' => '徨', '' => '恍', '' => '惶', '' => '愰', '' => '慌', '' => '晃', '' => '晄', '' => '榥', '' => '況', '' => '湟', '' => '滉', '' => '潢', '' => '煌', '' => '璜', '' => '皇', '' => '篁', '' => '簧', '' => '荒', '' => '蝗', '' => '遑', '' => '隍', '' => '黃', '' => '匯', '' => '回', '' => '廻', '' => '徊', '' => '恢', '' => '悔', '' => '懷', '' => '晦', '' => '會', '' => '檜', '' => '淮', '' => '澮', '' => '灰', '' => '獪', '' => '繪', '' => '膾', '' => '茴', '' => '蛔', '' => '誨', '' => '賄', '' => '劃', '' => '獲', '' => '宖', '' => '橫', '' => '鐄', '' => '哮', '' => '嚆', '' => '孝', '' => '效', '' => '斅', '' => '曉', '' => '梟', '' => '涍', '' => '淆', '' => '爻', '' => '肴', '' => '酵', '' => '驍', '' => '侯', '' => '候', '' => '厚', '' => '后', '' => '吼', '' => '喉', '' => '嗅', '' => '帿', '' => '後', '' => '朽', '' => '煦', '' => '珝', '' => '逅', '' => '勛', '' => '勳', '' => '塤', '' => '壎', '' => '焄', '' => '熏', '' => '燻', '' => '薰', '' => '訓', '' => '暈', '' => '薨', '' => '喧', '' => '暄', '' => '煊', '' => '萱', '' => '卉', '' => '喙', '' => '毁', '' => '彙', '' => '徽', '' => '揮', '' => '暉', '' => '煇', '' => '諱', '' => '輝', '' => '麾', '' => '休', '' => '携', '' => '烋', '' => '畦', '' => '虧', '' => '恤', '' => '譎', '' => '鷸', '' => '兇', '' => '凶', '' => '匈', '' => '洶', '' => '胸', '' => '黑', '' => '昕', '' => '欣', '' => '炘', '' => '痕', '' => '吃', '' => '屹', '' => '紇', '' => '訖', '' => '欠', '' => '欽', '' => '歆', '' => '吸', '' => '恰', '' => '洽', '' => '翕', '' => '興', '' => '僖', '' => '凞', '' => '喜', '' => '噫', '' => '囍', '' => '姬', '' => '嬉', '' => '希', '' => '憙', '' => '憘', '' => '戱', '' => '晞', '' => '曦', '' => '熙', '' => '熹', '' => '熺', '' => '犧', '' => '禧', '' => '稀', '' => '羲', '' => '詰', ); $result =& $data; unset($data); return $result; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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' => '┌', '{' => '┐', '|' => '└', '}' => '┘', '~' => '╭', '' => '╮', '' => '╰', '' => '╯', '' => '═', '' => '╞', '' => '╪', '' => '╡', '' => '◢', '' => '◣', '' => '◥', '' => '◤', '' => '╱', '' => '╲', '' => '╳', '' => '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', 'A' => 'x', 'B' => 'y', 'C' => 'z', 'D' => 'Α', 'E' => 'Β', 'F' => 'Γ', 'G' => 'Δ', 'H' => 'Ε', 'I' => 'Ζ', 'J' => 'Η', 'K' => 'Θ', 'L' => 'Ι', 'M' => 'Κ', 'N' => 'Λ', 'O' => 'Μ', 'P' => 'Ν', 'Q' => 'Ξ', 'R' => 'Ο', 'S' => 'Π', 'T' => 'Ρ', 'U' => 'Σ', 'V' => 'Τ', 'W' => 'Υ', 'X' => 'Φ', 'Y' => 'Χ', 'Z' => 'Ψ', '[' => 'Ω', '\\' => 'α', ']' => 'β', '^' => 'γ', '_' => 'δ', '`' => 'ε', 'a' => 'ζ', 'b' => 'η', 'c' => 'θ', 'd' => 'ι', 'e' => 'κ', 'f' => 'λ', 'g' => 'μ', 'h' => 'ν', 'i' => 'ξ', 'j' => 'ο', 'k' => 'π', 'l' => 'ρ', 'm' => 'σ', 'n' => 'τ', 'o' => 'υ', 'p' => 'φ', 'q' => 'χ', 'r' => 'ψ', 's' => 'ω', 't' => 'ㄅ', 'u' => 'ㄆ', 'v' => 'ㄇ', 'w' => 'ㄈ', 'x' => 'ㄉ', 'y' => 'ㄊ', 'z' => 'ㄋ', '{' => 'ㄌ', '|' => 'ㄍ', '}' => 'ㄎ', '~' => 'ㄏ', '' => 'ㄐ', '' => 'ㄑ', '' => 'ㄒ', '' => 'ㄓ', '' => 'ㄔ', '' => 'ㄕ', '' => 'ㄖ', '' => 'ㄗ', '' => 'ㄘ', '' => 'ㄙ', '' => 'ㄚ', '' => 'ㄛ', '' => 'ㄜ', '' => 'ㄝ', '' => 'ㄞ', '' => 'ㄟ', '' => 'ㄠ', '' => 'ㄡ', '' => 'ㄢ', '' => 'ㄣ', '' => 'ㄤ', '' => 'ㄥ', '' => 'ㄦ', '' => 'ㄧ', '' => 'ㄨ', '' => 'ㄩ', '' => '˙', '' => 'ˉ', '' => 'ˊ', '' => 'ˇ', '' => 'ˋ', '' => '€', '@' => '一', 'A' => '乙', 'B' => '丁', 'C' => '七', 'D' => '乃', 'E' => '九', 'F' => '了', 'G' => '二', 'H' => '人', 'I' => '儿', 'J' => '入', 'K' => '八', 'L' => '几', 'M' => '刀', 'N' => '刁', 'O' => '力', 'P' => '匕', 'Q' => '十', 'R' => '卜', 'S' => '又', 'T' => '三', 'U' => '下', 'V' => '丈', 'W' => '上', 'X' => '丫', 'Y' => '丸', 'Z' => '凡', '[' => '久', '\\' => '么', ']' => '也', '^' => '乞', '_' => '于', '`' => '亡', 'a' => '兀', 'b' => '刃', 'c' => '勺', 'd' => '千', 'e' => '叉', 'f' => '口', 'g' => '土', 'h' => '士', 'i' => '夕', 'j' => '大', 'k' => '女', 'l' => '子', 'm' => '孑', 'n' => '孓', 'o' => '寸', 'p' => '小', 'q' => '尢', 'r' => '尸', 's' => '山', 't' => '川', 'u' => '工', 'v' => '己', 'w' => '已', 'x' => '巳', 'y' => '巾', 'z' => '干', '{' => '廾', '|' => '弋', '}' => '弓', '~' => '才', '' => '丑', '' => '丐', '' => '不', '' => '中', '' => '丰', '' => '丹', '' => '之', '' => '尹', '' => '予', '' => '云', '' => '井', '' => '互', '' => '五', '' => '亢', '' => '仁', '' => '什', '' => '仃', '' => '仆', '' => '仇', '' => '仍', '' => '今', '' => '介', '' => '仄', '' => '元', '' => '允', '' => '內', '' => '六', '' => '兮', '' => '公', '' => '冗', '' => '凶', '' => '分', '' => '切', '' => '刈', '' => '勻', '' => '勾', '' => '勿', '' => '化', '' => '匹', '' => '午', '' => '升', '' => '卅', '' => '卞', '' => '厄', '' => '友', '' => '及', '' => '反', '' => '壬', '' => '天', '' => '夫', '' => '太', '' => '夭', '' => '孔', '' => '少', '' => '尤', '' => '尺', '' => '屯', '' => '巴', '' => '幻', '' => '廿', '' => '弔', '' => '引', '' => '心', '' => '戈', '' => '戶', '' => '手', '' => '扎', '' => '支', '' => '文', '' => '斗', '' => '斤', '' => '方', '' => '日', '' => '曰', '' => '月', '' => '木', '' => '欠', '' => '止', '' => '歹', '' => '毋', '' => '比', '' => '毛', '' => '氏', '' => '水', '' => '火', '' => '爪', '' => '父', '' => '爻', '' => '片', '' => '牙', '' => '牛', '' => '犬', '' => '王', '' => '丙', '@' => '世', 'A' => '丕', 'B' => '且', 'C' => '丘', 'D' => '主', 'E' => '乍', 'F' => '乏', 'G' => '乎', 'H' => '以', 'I' => '付', 'J' => '仔', 'K' => '仕', 'L' => '他', 'M' => '仗', 'N' => '代', 'O' => '令', 'P' => '仙', 'Q' => '仞', 'R' => '充', 'S' => '兄', 'T' => '冉', 'U' => '冊', 'V' => '冬', 'W' => '凹', 'X' => '出', 'Y' => '凸', 'Z' => '刊', '[' => '加', '\\' => '功', ']' => '包', '^' => '匆', '_' => '北', '`' => '匝', 'a' => '仟', 'b' => '半', 'c' => '卉', 'd' => '卡', 'e' => '占', 'f' => '卯', 'g' => '卮', 'h' => '去', 'i' => '可', 'j' => '古', 'k' => '右', 'l' => '召', 'm' => '叮', 'n' => '叩', 'o' => '叨', 'p' => '叼', 'q' => '司', 'r' => '叵', 's' => '叫', 't' => '另', 'u' => '只', 'v' => '史', 'w' => '叱', 'x' => '台', 'y' => '句', 'z' => '叭', '{' => '叻', '|' => '四', '}' => '囚', '~' => '外', '' => '央', '' => '失', '' => '奴', '' => '奶', '' => '孕', '' => '它', '' => '尼', '' => '巨', '' => '巧', '' => '左', '' => '市', '' => '布', '' => '平', '' => '幼', '' => '弁', '' => '弘', '' => '弗', '' => '必', '' => '戊', '' => '打', '' => '扔', '' => '扒', '' => '扑', '' => '斥', '' => '旦', '' => '朮', '' => '本', '' => '未', '' => '末', '' => '札', '' => '正', '' => '母', '' => '民', '' => '氐', '' => '永', '' => '汁', '' => '汀', '' => '氾', '' => '犯', '' => '玄', '' => '玉', '' => '瓜', '' => '瓦', '' => '甘', '' => '生', '' => '用', '' => '甩', '' => '田', '' => '由', '' => '甲', '' => '申', '' => '疋', '' => '白', '' => '皮', '' => '皿', '' => '目', '' => '矛', '' => '矢', '' => '石', '' => '示', '' => '禾', '' => '穴', '' => '立', '' => '丞', '' => '丟', '' => '乒', '' => '乓', '' => '乩', '' => '亙', '' => '交', '' => '亦', '' => '亥', '' => '仿', '' => '伉', '' => '伙', '' => '伊', '' => '伕', '' => '伍', '' => '伐', '' => '休', '' => '伏', '' => '仲', '' => '件', '' => '任', '' => '仰', '' => '仳', '' => '份', '' => '企', '' => '伋', '' => '光', '' => '兇', '' => '兆', '' => '先', '' => '全', '@' => '共', 'A' => '再', 'B' => '冰', 'C' => '列', 'D' => '刑', 'E' => '划', 'F' => '刎', 'G' => '刖', 'H' => '劣', 'I' => '匈', 'J' => '匡', 'K' => '匠', 'L' => '印', 'M' => '危', 'N' => '吉', 'O' => '吏', 'P' => '同', 'Q' => '吊', 'R' => '吐', 'S' => '吁', 'T' => '吋', 'U' => '各', 'V' => '向', 'W' => '名', 'X' => '合', 'Y' => '吃', 'Z' => '后', '[' => '吆', '\\' => '吒', ']' => '因', '^' => '回', '_' => '囝', '`' => '圳', 'a' => '地', 'b' => '在', 'c' => '圭', 'd' => '圬', 'e' => '圯', 'f' => '圩', 'g' => '夙', 'h' => '多', 'i' => '夷', 'j' => '夸', 'k' => '妄', 'l' => '奸', 'm' => '妃', 'n' => '好', 'o' => '她', 'p' => '如', 'q' => '妁', 'r' => '字', 's' => '存', 't' => '宇', 'u' => '守', 'v' => '宅', 'w' => '安', 'x' => '寺', 'y' => '尖', 'z' => '屹', '{' => '州', '|' => '帆', '}' => '并', '~' => '年', '' => '式', '' => '弛', '' => '忙', '' => '忖', '' => '戎', '' => '戌', '' => '戍', '' => '成', '' => '扣', '' => '扛', '' => '托', '' => '收', '' => '早', '' => '旨', '' => '旬', '' => '旭', '' => '曲', '' => '曳', '' => '有', '' => '朽', '' => '朴', '' => '朱', '' => '朵', '' => '次', '' => '此', '' => '死', '' => '氖', '' => '汝', '' => '汗', '' => '汙', '' => '江', '' => '池', '' => '汐', '' => '汕', '' => '污', '' => '汛', '' => '汍', '' => '汎', '' => '灰', '' => '牟', '' => '牝', '' => '百', '' => '竹', '' => '米', '' => '糸', '' => '缶', '' => '羊', '' => '羽', '' => '老', '' => '考', '' => '而', '' => '耒', '' => '耳', '' => '聿', '' => '肉', '' => '肋', '' => '肌', '' => '臣', '' => '自', '' => '至', '' => '臼', '' => '舌', '' => '舛', '' => '舟', '' => '艮', '' => '色', '' => '艾', '' => '虫', '' => '血', '' => '行', '' => '衣', '' => '西', '' => '阡', '' => '串', '' => '亨', '' => '位', '' => '住', '' => '佇', '' => '佗', '' => '佞', '' => '伴', '' => '佛', '' => '何', '' => '估', '' => '佐', '' => '佑', '' => '伽', '' => '伺', '' => '伸', '' => '佃', '' => '佔', '' => '似', '' => '但', '' => '佣', '@' => '作', 'A' => '你', 'B' => '伯', 'C' => '低', 'D' => '伶', 'E' => '余', 'F' => '佝', 'G' => '佈', 'H' => '佚', 'I' => '兌', 'J' => '克', 'K' => '免', 'L' => '兵', 'M' => '冶', 'N' => '冷', 'O' => '別', 'P' => '判', 'Q' => '利', 'R' => '刪', 'S' => '刨', 'T' => '劫', 'U' => '助', 'V' => '努', 'W' => '劬', 'X' => '匣', 'Y' => '即', 'Z' => '卵', '[' => '吝', '\\' => '吭', ']' => '吞', '^' => '吾', '_' => '否', '`' => '呎', 'a' => '吧', 'b' => '呆', 'c' => '呃', 'd' => '吳', 'e' => '呈', 'f' => '呂', 'g' => '君', 'h' => '吩', 'i' => '告', 'j' => '吹', 'k' => '吻', 'l' => '吸', 'm' => '吮', 'n' => '吵', 'o' => '吶', 'p' => '吠', 'q' => '吼', 'r' => '呀', 's' => '吱', 't' => '含', 'u' => '吟', 'v' => '听', 'w' => '囪', 'x' => '困', 'y' => '囤', 'z' => '囫', '{' => '坊', '|' => '坑', '}' => '址', '~' => '坍', '' => '均', '' => '坎', '' => '圾', '' => '坐', '' => '坏', '' => '圻', '' => '壯', '' => '夾', '' => '妝', '' => '妒', '' => '妨', '' => '妞', '' => '妣', '' => '妙', '' => '妖', '' => '妍', '' => '妤', '' => '妓', '' => '妊', '' => '妥', '' => '孝', '' => '孜', '' => '孚', '' => '孛', '' => '完', '' => '宋', '' => '宏', '' => '尬', '' => '局', '' => '屁', '' => '尿', '' => '尾', '' => '岐', '' => '岑', '' => '岔', '' => '岌', '' => '巫', '' => '希', '' => '序', '' => '庇', '' => '床', '' => '廷', '' => '弄', '' => '弟', '' => '彤', '' => '形', '' => '彷', '' => '役', '' => '忘', '' => '忌', '' => '志', '' => '忍', '' => '忱', '' => '快', '' => '忸', '' => '忪', '' => '戒', '' => '我', '' => '抄', '' => '抗', '' => '抖', '' => '技', '' => '扶', '' => '抉', '' => '扭', '' => '把', '' => '扼', '' => '找', '' => '批', '' => '扳', '' => '抒', '' => '扯', '' => '折', '' => '扮', '' => '投', '' => '抓', '' => '抑', '' => '抆', '' => '改', '' => '攻', '' => '攸', '' => '旱', '' => '更', '' => '束', '' => '李', '' => '杏', '' => '材', '' => '村', '' => '杜', '' => '杖', '' => '杞', '' => '杉', '' => '杆', '' => '杠', '@' => '杓', 'A' => '杗', 'B' => '步', 'C' => '每', 'D' => '求', 'E' => '汞', 'F' => '沙', 'G' => '沁', 'H' => '沈', 'I' => '沉', 'J' => '沅', 'K' => '沛', 'L' => '汪', 'M' => '決', 'N' => '沐', 'O' => '汰', 'P' => '沌', 'Q' => '汨', 'R' => '沖', 'S' => '沒', 'T' => '汽', 'U' => '沃', 'V' => '汲', 'W' => '汾', 'X' => '汴', 'Y' => '沆', 'Z' => '汶', '[' => '沍', '\\' => '沔', ']' => '沘', '^' => '沂', '_' => '灶', '`' => '灼', 'a' => '災', 'b' => '灸', 'c' => '牢', 'd' => '牡', 'e' => '牠', 'f' => '狄', 'g' => '狂', 'h' => '玖', 'i' => '甬', 'j' => '甫', 'k' => '男', 'l' => '甸', 'm' => '皂', 'n' => '盯', 'o' => '矣', 'p' => '私', 'q' => '秀', 'r' => '禿', 's' => '究', 't' => '系', 'u' => '罕', 'v' => '肖', 'w' => '肓', 'x' => '肝', 'y' => '肘', 'z' => '肛', '{' => '肚', '|' => '育', '}' => '良', '~' => '芒', '' => '芋', '' => '芍', '' => '見', '' => '角', '' => '言', '' => '谷', '' => '豆', '' => '豕', '' => '貝', '' => '赤', '' => '走', '' => '足', '' => '身', '' => '車', '' => '辛', '' => '辰', '' => '迂', '' => '迆', '' => '迅', '' => '迄', '' => '巡', '' => '邑', '' => '邢', '' => '邪', '' => '邦', '' => '那', '' => '酉', '' => '釆', '' => '里', '' => '防', '' => '阮', '' => '阱', '' => '阪', '' => '阬', '' => '並', '' => '乖', '' => '乳', '' => '事', '' => '些', '' => '亞', '' => '享', '' => '京', '' => '佯', '' => '依', '' => '侍', '' => '佳', '' => '使', '' => '佬', '' => '供', '' => '例', '' => '來', '' => '侃', '' => '佰', '' => '併', '' => '侈', '' => '佩', '' => '佻', '' => '侖', '' => '佾', '' => '侏', '' => '侑', '' => '佺', '' => '兔', '' => '兒', '' => '兕', '' => '兩', '' => '具', '' => '其', '' => '典', '' => '冽', '' => '函', '' => '刻', '' => '券', '' => '刷', '' => '刺', '' => '到', '' => '刮', '' => '制', '' => '剁', '' => '劾', '' => '劻', '' => '卒', '' => '協', '' => '卓', '' => '卑', '' => '卦', '' => '卷', '' => '卸', '' => '卹', '' => '取', '' => '叔', '' => '受', '' => '味', '' => '呵', '@' => '咖', 'A' => '呸', 'B' => '咕', 'C' => '咀', 'D' => '呻', 'E' => '呷', 'F' => '咄', 'G' => '咒', 'H' => '咆', 'I' => '呼', 'J' => '咐', 'K' => '呱', 'L' => '呶', 'M' => '和', 'N' => '咚', 'O' => '呢', 'P' => '周', 'Q' => '咋', 'R' => '命', 'S' => '咎', 'T' => '固', 'U' => '垃', 'V' => '坷', 'W' => '坪', 'X' => '坩', 'Y' => '坡', 'Z' => '坦', '[' => '坤', '\\' => '坼', ']' => '夜', '^' => '奉', '_' => '奇', '`' => '奈', 'a' => '奄', 'b' => '奔', 'c' => '妾', 'd' => '妻', 'e' => '委', 'f' => '妹', 'g' => '妮', 'h' => '姑', 'i' => '姆', 'j' => '姐', 'k' => '姍', 'l' => '始', 'm' => '姓', 'n' => '姊', 'o' => '妯', 'p' => '妳', 'q' => '姒', 'r' => '姅', 's' => '孟', 't' => '孤', 'u' => '季', 'v' => '宗', 'w' => '定', 'x' => '官', 'y' => '宜', 'z' => '宙', '{' => '宛', '|' => '尚', '}' => '屈', '~' => '居', '' => '屆', '' => '岷', '' => '岡', '' => '岸', '' => '岩', '' => '岫', '' => '岱', '' => '岳', '' => '帘', '' => '帚', '' => '帖', '' => '帕', '' => '帛', '' => '帑', '' => '幸', '' => '庚', '' => '店', '' => '府', '' => '底', '' => '庖', '' => '延', '' => '弦', '' => '弧', '' => '弩', '' => '往', '' => '征', '' => '彿', '' => '彼', '' => '忝', '' => '忠', '' => '忽', '' => '念', '' => '忿', '' => '怏', '' => '怔', '' => '怯', '' => '怵', '' => '怖', '' => '怪', '' => '怕', '' => '怡', '' => '性', '' => '怩', '' => '怫', '' => '怛', '' => '或', '' => '戕', '' => '房', '' => '戾', '' => '所', '' => '承', '' => '拉', '' => '拌', '' => '拄', '' => '抿', '' => '拂', '' => '抹', '' => '拒', '' => '招', '' => '披', '' => '拓', '' => '拔', '' => '拋', '' => '拈', '' => '抨', '' => '抽', '' => '押', '' => '拐', '' => '拙', '' => '拇', '' => '拍', '' => '抵', '' => '拚', '' => '抱', '' => '拘', '' => '拖', '' => '拗', '' => '拆', '' => '抬', '' => '拎', '' => '放', '' => '斧', '' => '於', '' => '旺', '' => '昔', '' => '易', '' => '昌', '' => '昆', '' => '昂', '' => '明', '' => '昀', '' => '昏', '' => '昕', '' => '昊', '@' => '昇', 'A' => '服', 'B' => '朋', 'C' => '杭', 'D' => '枋', 'E' => '枕', 'F' => '東', 'G' => '果', 'H' => '杳', 'I' => '杷', 'J' => '枇', 'K' => '枝', 'L' => '林', 'M' => '杯', 'N' => '杰', 'O' => '板', 'P' => '枉', 'Q' => '松', 'R' => '析', 'S' => '杵', 'T' => '枚', 'U' => '枓', 'V' => '杼', 'W' => '杪', 'X' => '杲', 'Y' => '欣', 'Z' => '武', '[' => '歧', '\\' => '歿', ']' => '氓', '^' => '氛', '_' => '泣', '`' => '注', 'a' => '泳', 'b' => '沱', 'c' => '泌', 'd' => '泥', 'e' => '河', 'f' => '沽', 'g' => '沾', 'h' => '沼', 'i' => '波', 'j' => '沫', 'k' => '法', 'l' => '泓', 'm' => '沸', 'n' => '泄', 'o' => '油', 'p' => '況', 'q' => '沮', 'r' => '泗', 's' => '泅', 't' => '泱', 'u' => '沿', 'v' => '治', 'w' => '泡', 'x' => '泛', 'y' => '泊', 'z' => '沬', '{' => '泯', '|' => '泜', '}' => '泖', '~' => '泠', '' => '炕', '' => '炎', '' => '炒', '' => '炊', '' => '炙', '' => '爬', '' => '爭', '' => '爸', '' => '版', '' => '牧', '' => '物', '' => '狀', '' => '狎', '' => '狙', '' => '狗', '' => '狐', '' => '玩', '' => '玨', '' => '玟', '' => '玫', '' => '玥', '' => '甽', '' => '疝', '' => '疙', '' => '疚', '' => '的', '' => '盂', '' => '盲', '' => '直', '' => '知', '' => '矽', '' => '社', '' => '祀', '' => '祁', '' => '秉', '' => '秈', '' => '空', '' => '穹', '' => '竺', '' => '糾', '' => '罔', '' => '羌', '' => '羋', '' => '者', '' => '肺', '' => '肥', '' => '肢', '' => '肱', '' => '股', '' => '肫', '' => '肩', '' => '肴', '' => '肪', '' => '肯', '' => '臥', '' => '臾', '' => '舍', '' => '芳', '' => '芝', '' => '芙', '' => '芭', '' => '芽', '' => '芟', '' => '芹', '' => '花', '' => '芬', '' => '芥', '' => '芯', '' => '芸', '' => '芣', '' => '芰', '' => '芾', '' => '芷', '' => '虎', '' => '虱', '' => '初', '' => '表', '' => '軋', '' => '迎', '' => '返', '' => '近', '' => '邵', '' => '邸', '' => '邱', '' => '邶', '' => '采', '' => '金', '' => '長', '' => '門', '' => '阜', '' => '陀', '' => '阿', '' => '阻', '' => '附', '@' => '陂', 'A' => '隹', 'B' => '雨', 'C' => '青', 'D' => '非', 'E' => '亟', 'F' => '亭', 'G' => '亮', 'H' => '信', 'I' => '侵', 'J' => '侯', 'K' => '便', 'L' => '俠', 'M' => '俑', 'N' => '俏', 'O' => '保', 'P' => '促', 'Q' => '侶', 'R' => '俘', 'S' => '俟', 'T' => '俊', 'U' => '俗', 'V' => '侮', 'W' => '俐', 'X' => '俄', 'Y' => '係', 'Z' => '俚', '[' => '俎', '\\' => '俞', ']' => '侷', '^' => '兗', '_' => '冒', '`' => '冑', 'a' => '冠', 'b' => '剎', 'c' => '剃', 'd' => '削', 'e' => '前', 'f' => '剌', 'g' => '剋', 'h' => '則', 'i' => '勇', 'j' => '勉', 'k' => '勃', 'l' => '勁', 'm' => '匍', 'n' => '南', 'o' => '卻', 'p' => '厚', 'q' => '叛', 'r' => '咬', 's' => '哀', 't' => '咨', 'u' => '哎', 'v' => '哉', 'w' => '咸', 'x' => '咦', 'y' => '咳', 'z' => '哇', '{' => '哂', '|' => '咽', '}' => '咪', '~' => '品', '' => '哄', '' => '哈', '' => '咯', '' => '咫', '' => '咱', '' => '咻', '' => '咩', '' => '咧', '' => '咿', '' => '囿', '' => '垂', '' => '型', '' => '垠', '' => '垣', '' => '垢', '' => '城', '' => '垮', '' => '垓', '' => '奕', '' => '契', '' => '奏', '' => '奎', '' => '奐', '' => '姜', '' => '姘', '' => '姿', '' => '姣', '' => '姨', '' => '娃', '' => '姥', '' => '姪', '' => '姚', '' => '姦', '' => '威', '' => '姻', '' => '孩', '' => '宣', '' => '宦', '' => '室', '' => '客', '' => '宥', '' => '封', '' => '屎', '' => '屏', '' => '屍', '' => '屋', '' => '峙', '' => '峒', '' => '巷', '' => '帝', '' => '帥', '' => '帟', '' => '幽', '' => '庠', '' => '度', '' => '建', '' => '弈', '' => '弭', '' => '彥', '' => '很', '' => '待', '' => '徊', '' => '律', '' => '徇', '' => '後', '' => '徉', '' => '怒', '' => '思', '' => '怠', '' => '急', '' => '怎', '' => '怨', '' => '恍', '' => '恰', '' => '恨', '' => '恢', '' => '恆', '' => '恃', '' => '恬', '' => '恫', '' => '恪', '' => '恤', '' => '扁', '' => '拜', '' => '挖', '' => '按', '' => '拼', '' => '拭', '' => '持', '' => '拮', '' => '拽', '' => '指', '' => '拱', '' => '拷', '@' => '拯', 'A' => '括', 'B' => '拾', 'C' => '拴', 'D' => '挑', 'E' => '挂', 'F' => '政', 'G' => '故', 'H' => '斫', 'I' => '施', 'J' => '既', 'K' => '春', 'L' => '昭', 'M' => '映', 'N' => '昧', 'O' => '是', 'P' => '星', 'Q' => '昨', 'R' => '昱', 'S' => '昤', 'T' => '曷', 'U' => '柿', 'V' => '染', 'W' => '柱', 'X' => '柔', 'Y' => '某', 'Z' => '柬', '[' => '架', '\\' => '枯', ']' => '柵', '^' => '柩', '_' => '柯', '`' => '柄', 'a' => '柑', 'b' => '枴', 'c' => '柚', 'd' => '查', 'e' => '枸', 'f' => '柏', 'g' => '柞', 'h' => '柳', 'i' => '枰', 'j' => '柙', 'k' => '柢', 'l' => '柝', 'm' => '柒', 'n' => '歪', 'o' => '殃', 'p' => '殆', 'q' => '段', 'r' => '毒', 's' => '毗', 't' => '氟', 'u' => '泉', 'v' => '洋', 'w' => '洲', 'x' => '洪', 'y' => '流', 'z' => '津', '{' => '洌', '|' => '洱', '}' => '洞', '~' => '洗', '' => '活', '' => '洽', '' => '派', '' => '洶', '' => '洛', '' => '泵', '' => '洹', '' => '洧', '' => '洸', '' => '洩', '' => '洮', '' => '洵', '' => '洎', '' => '洫', '' => '炫', '' => '為', '' => '炳', '' => '炬', '' => '炯', '' => '炭', '' => '炸', '' => '炮', '' => '炤', '' => '爰', '' => '牲', '' => '牯', '' => '牴', '' => '狩', '' => '狠', '' => '狡', '' => '玷', '' => '珊', '' => '玻', '' => '玲', '' => '珍', '' => '珀', '' => '玳', '' => '甚', '' => '甭', '' => '畏', '' => '界', '' => '畎', '' => '畋', '' => '疫', '' => '疤', '' => '疥', '' => '疢', '' => '疣', '' => '癸', '' => '皆', '' => '皇', '' => '皈', '' => '盈', '' => '盆', '' => '盃', '' => '盅', '' => '省', '' => '盹', '' => '相', '' => '眉', '' => '看', '' => '盾', '' => '盼', '' => '眇', '' => '矜', '' => '砂', '' => '研', '' => '砌', '' => '砍', '' => '祆', '' => '祉', '' => '祈', '' => '祇', '' => '禹', '' => '禺', '' => '科', '' => '秒', '' => '秋', '' => '穿', '' => '突', '' => '竿', '' => '竽', '' => '籽', '' => '紂', '' => '紅', '' => '紀', '' => '紉', '' => '紇', '' => '約', '' => '紆', '' => '缸', '' => '美', '' => '羿', '' => '耄', '@' => '耐', 'A' => '耍', 'B' => '耑', 'C' => '耶', 'D' => '胖', 'E' => '胥', 'F' => '胚', 'G' => '胃', 'H' => '胄', 'I' => '背', 'J' => '胡', 'K' => '胛', 'L' => '胎', 'M' => '胞', 'N' => '胤', 'O' => '胝', 'P' => '致', 'Q' => '舢', 'R' => '苧', 'S' => '范', 'T' => '茅', 'U' => '苣', 'V' => '苛', 'W' => '苦', 'X' => '茄', 'Y' => '若', 'Z' => '茂', '[' => '茉', '\\' => '苒', ']' => '苗', '^' => '英', '_' => '茁', '`' => '苜', 'a' => '苔', 'b' => '苑', 'c' => '苞', 'd' => '苓', 'e' => '苟', 'f' => '苯', 'g' => '茆', 'h' => '虐', 'i' => '虹', 'j' => '虻', 'k' => '虺', 'l' => '衍', 'm' => '衫', 'n' => '要', 'o' => '觔', 'p' => '計', 'q' => '訂', 'r' => '訃', 's' => '貞', 't' => '負', 'u' => '赴', 'v' => '赳', 'w' => '趴', 'x' => '軍', 'y' => '軌', 'z' => '述', '{' => '迦', '|' => '迢', '}' => '迪', '~' => '迥', '' => '迭', '' => '迫', '' => '迤', '' => '迨', '' => '郊', '' => '郎', '' => '郁', '' => '郃', '' => '酋', '' => '酊', '' => '重', '' => '閂', '' => '限', '' => '陋', '' => '陌', '' => '降', '' => '面', '' => '革', '' => '韋', '' => '韭', '' => '音', '' => '頁', '' => '風', '' => '飛', '' => '食', '' => '首', '' => '香', '' => '乘', '' => '亳', '' => '倌', '' => '倍', '' => '倣', '' => '俯', '' => '倦', '' => '倥', '' => '俸', '' => '倩', '' => '倖', '' => '倆', '' => '值', '' => '借', '' => '倚', '' => '倒', '' => '們', '' => '俺', '' => '倀', '' => '倔', '' => '倨', '' => '俱', '' => '倡', '' => '個', '' => '候', '' => '倘', '' => '俳', '' => '修', '' => '倭', '' => '倪', '' => '俾', '' => '倫', '' => '倉', '' => '兼', '' => '冤', '' => '冥', '' => '冢', '' => '凍', '' => '凌', '' => '准', '' => '凋', '' => '剖', '' => '剜', '' => '剔', '' => '剛', '' => '剝', '' => '匪', '' => '卿', '' => '原', '' => '厝', '' => '叟', '' => '哨', '' => '唐', '' => '唁', '' => '唷', '' => '哼', '' => '哥', '' => '哲', '' => '唆', '' => '哺', '' => '唔', '' => '哩', '' => '哭', '' => '員', '' => '唉', '' => '哮', '' => '哪', '@' => '哦', 'A' => '唧', 'B' => '唇', 'C' => '哽', 'D' => '唏', 'E' => '圃', 'F' => '圄', 'G' => '埂', 'H' => '埔', 'I' => '埋', 'J' => '埃', 'K' => '堉', 'L' => '夏', 'M' => '套', 'N' => '奘', 'O' => '奚', 'P' => '娑', 'Q' => '娘', 'R' => '娜', 'S' => '娟', 'T' => '娛', 'U' => '娓', 'V' => '姬', 'W' => '娠', 'X' => '娣', 'Y' => '娩', 'Z' => '娥', '[' => '娌', '\\' => '娉', ']' => '孫', '^' => '屘', '_' => '宰', '`' => '害', 'a' => '家', 'b' => '宴', 'c' => '宮', 'd' => '宵', 'e' => '容', 'f' => '宸', 'g' => '射', 'h' => '屑', 'i' => '展', 'j' => '屐', 'k' => '峭', 'l' => '峽', 'm' => '峻', 'n' => '峪', 'o' => '峨', 'p' => '峰', 'q' => '島', 'r' => '崁', 's' => '峴', 't' => '差', 'u' => '席', 'v' => '師', 'w' => '庫', 'x' => '庭', 'y' => '座', 'z' => '弱', '{' => '徒', '|' => '徑', '}' => '徐', '~' => '恙', '' => '恣', '' => '恥', '' => '恐', '' => '恕', '' => '恭', '' => '恩', '' => '息', '' => '悄', '' => '悟', '' => '悚', '' => '悍', '' => '悔', '' => '悌', '' => '悅', '' => '悖', '' => '扇', '' => '拳', '' => '挈', '' => '拿', '' => '捎', '' => '挾', '' => '振', '' => '捕', '' => '捂', '' => '捆', '' => '捏', '' => '捉', '' => '挺', '' => '捐', '' => '挽', '' => '挪', '' => '挫', '' => '挨', '' => '捍', '' => '捌', '' => '效', '' => '敉', '' => '料', '' => '旁', '' => '旅', '' => '時', '' => '晉', '' => '晏', '' => '晃', '' => '晒', '' => '晌', '' => '晅', '' => '晁', '' => '書', '' => '朔', '' => '朕', '' => '朗', '' => '校', '' => '核', '' => '案', '' => '框', '' => '桓', '' => '根', '' => '桂', '' => '桔', '' => '栩', '' => '梳', '' => '栗', '' => '桌', '' => '桑', '' => '栽', '' => '柴', '' => '桐', '' => '桀', '' => '格', '' => '桃', '' => '株', '' => '桅', '' => '栓', '' => '栘', '' => '桁', '' => '殊', '' => '殉', '' => '殷', '' => '氣', '' => '氧', '' => '氨', '' => '氦', '' => '氤', '' => '泰', '' => '浪', '' => '涕', '' => '消', '' => '涇', '' => '浦', '' => '浸', '' => '海', '' => '浙', '' => '涓', '@' => '浬', 'A' => '涉', 'B' => '浮', 'C' => '浚', 'D' => '浴', 'E' => '浩', 'F' => '涌', 'G' => '涊', 'H' => '浹', 'I' => '涅', 'J' => '浥', 'K' => '涔', 'L' => '烊', 'M' => '烘', 'N' => '烤', 'O' => '烙', 'P' => '烈', 'Q' => '烏', 'R' => '爹', 'S' => '特', 'T' => '狼', 'U' => '狹', 'V' => '狽', 'W' => '狸', 'X' => '狷', 'Y' => '玆', 'Z' => '班', '[' => '琉', '\\' => '珮', ']' => '珠', '^' => '珪', '_' => '珞', '`' => '畔', 'a' => '畝', 'b' => '畜', 'c' => '畚', 'd' => '留', 'e' => '疾', 'f' => '病', 'g' => '症', 'h' => '疲', 'i' => '疳', 'j' => '疽', 'k' => '疼', 'l' => '疹', 'm' => '痂', 'n' => '疸', 'o' => '皋', 'p' => '皰', 'q' => '益', 'r' => '盍', 's' => '盎', 't' => '眩', 'u' => '真', 'v' => '眠', 'w' => '眨', 'x' => '矩', 'y' => '砰', 'z' => '砧', '{' => '砸', '|' => '砝', '}' => '破', '~' => '砷', '' => '砥', '' => '砭', '' => '砠', '' => '砟', '' => '砲', '' => '祕', '' => '祐', '' => '祠', '' => '祟', '' => '祖', '' => '神', '' => '祝', '' => '祗', '' => '祚', '' => '秤', '' => '秣', '' => '秧', '' => '租', '' => '秦', '' => '秩', '' => '秘', '' => '窄', '' => '窈', '' => '站', '' => '笆', '' => '笑', '' => '粉', '' => '紡', '' => '紗', '' => '紋', '' => '紊', '' => '素', '' => '索', '' => '純', '' => '紐', '' => '紕', '' => '級', '' => '紜', '' => '納', '' => '紙', '' => '紛', '' => '缺', '' => '罟', '' => '羔', '' => '翅', '' => '翁', '' => '耆', '' => '耘', '' => '耕', '' => '耙', '' => '耗', '' => '耽', '' => '耿', '' => '胱', '' => '脂', '' => '胰', '' => '脅', '' => '胭', '' => '胴', '' => '脆', '' => '胸', '' => '胳', '' => '脈', '' => '能', '' => '脊', '' => '胼', '' => '胯', '' => '臭', '' => '臬', '' => '舀', '' => '舐', '' => '航', '' => '舫', '' => '舨', '' => '般', '' => '芻', '' => '茫', '' => '荒', '' => '荔', '' => '荊', '' => '茸', '' => '荐', '' => '草', '' => '茵', '' => '茴', '' => '荏', '' => '茲', '' => '茹', '' => '茶', '' => '茗', '' => '荀', '' => '茱', '' => '茨', '' => '荃', '@' => '虔', 'A' => '蚊', 'B' => '蚪', 'C' => '蚓', 'D' => '蚤', 'E' => '蚩', 'F' => '蚌', 'G' => '蚣', 'H' => '蚜', 'I' => '衰', 'J' => '衷', 'K' => '袁', 'L' => '袂', 'M' => '衽', 'N' => '衹', 'O' => '記', 'P' => '訐', 'Q' => '討', 'R' => '訌', 'S' => '訕', 'T' => '訊', 'U' => '託', 'V' => '訓', 'W' => '訖', 'X' => '訏', 'Y' => '訑', 'Z' => '豈', '[' => '豺', '\\' => '豹', ']' => '財', '^' => '貢', '_' => '起', '`' => '躬', 'a' => '軒', 'b' => '軔', 'c' => '軏', 'd' => '辱', 'e' => '送', 'f' => '逆', 'g' => '迷', 'h' => '退', 'i' => '迺', 'j' => '迴', 'k' => '逃', 'l' => '追', 'm' => '逅', 'n' => '迸', 'o' => '邕', 'p' => '郡', 'q' => '郝', 'r' => '郢', 's' => '酒', 't' => '配', 'u' => '酌', 'v' => '釘', 'w' => '針', 'x' => '釗', 'y' => '釜', 'z' => '釙', '{' => '閃', '|' => '院', '}' => '陣', '~' => '陡', '' => '陛', '' => '陝', '' => '除', '' => '陘', '' => '陞', '' => '隻', '' => '飢', '' => '馬', '' => '骨', '' => '高', '' => '鬥', '' => '鬲', '' => '鬼', '' => '乾', '' => '偺', '' => '偽', '' => '停', '' => '假', '' => '偃', '' => '偌', '' => '做', '' => '偉', '' => '健', '' => '偶', '' => '偎', '' => '偕', '' => '偵', '' => '側', '' => '偷', '' => '偏', '' => '倏', '' => '偯', '' => '偭', '' => '兜', '' => '冕', '' => '凰', '' => '剪', '' => '副', '' => '勒', '' => '務', '' => '勘', '' => '動', '' => '匐', '' => '匏', '' => '匙', '' => '匿', '' => '區', '' => '匾', '' => '參', '' => '曼', '' => '商', '' => '啪', '' => '啦', '' => '啄', '' => '啞', '' => '啡', '' => '啃', '' => '啊', '' => '唱', '' => '啖', '' => '問', '' => '啕', '' => '唯', '' => '啤', '' => '唸', '' => '售', '' => '啜', '' => '唬', '' => '啣', '' => '唳', '' => '啁', '' => '啗', '' => '圈', '' => '國', '' => '圉', '' => '域', '' => '堅', '' => '堊', '' => '堆', '' => '埠', '' => '埤', '' => '基', '' => '堂', '' => '堵', '' => '執', '' => '培', '' => '夠', '' => '奢', '' => '娶', '' => '婁', '' => '婉', '' => '婦', '' => '婪', '' => '婀', '@' => '娼', 'A' => '婢', 'B' => '婚', 'C' => '婆', 'D' => '婊', 'E' => '孰', 'F' => '寇', 'G' => '寅', 'H' => '寄', 'I' => '寂', 'J' => '宿', 'K' => '密', 'L' => '尉', 'M' => '專', 'N' => '將', 'O' => '屠', 'P' => '屜', 'Q' => '屝', 'R' => '崇', 'S' => '崆', 'T' => '崎', 'U' => '崛', 'V' => '崖', 'W' => '崢', 'X' => '崑', 'Y' => '崩', 'Z' => '崔', '[' => '崙', '\\' => '崤', ']' => '崧', '^' => '崗', '_' => '巢', '`' => '常', 'a' => '帶', 'b' => '帳', 'c' => '帷', 'd' => '康', 'e' => '庸', 'f' => '庶', 'g' => '庵', 'h' => '庾', 'i' => '張', 'j' => '強', 'k' => '彗', 'l' => '彬', 'm' => '彩', 'n' => '彫', 'o' => '得', 'p' => '徙', 'q' => '從', 'r' => '徘', 's' => '御', 't' => '徠', 'u' => '徜', 'v' => '恿', 'w' => '患', 'x' => '悉', 'y' => '悠', 'z' => '您', '{' => '惋', '|' => '悴', '}' => '惦', '~' => '悽', '' => '情', '' => '悻', '' => '悵', '' => '惜', '' => '悼', '' => '惘', '' => '惕', '' => '惆', '' => '惟', '' => '悸', '' => '惚', '' => '惇', '' => '戚', '' => '戛', '' => '扈', '' => '掠', '' => '控', '' => '捲', '' => '掖', '' => '探', '' => '接', '' => '捷', '' => '捧', '' => '掘', '' => '措', '' => '捱', '' => '掩', '' => '掉', '' => '掃', '' => '掛', '' => '捫', '' => '推', '' => '掄', '' => '授', '' => '掙', '' => '採', '' => '掬', '' => '排', '' => '掏', '' => '掀', '' => '捻', '' => '捩', '' => '捨', '' => '捺', '' => '敝', '' => '敖', '' => '救', '' => '教', '' => '敗', '' => '啟', '' => '敏', '' => '敘', '' => '敕', '' => '敔', '' => '斜', '' => '斛', '' => '斬', '' => '族', '' => '旋', '' => '旌', '' => '旎', '' => '晝', '' => '晚', '' => '晤', '' => '晨', '' => '晦', '' => '晞', '' => '曹', '' => '勗', '' => '望', '' => '梁', '' => '梯', '' => '梢', '' => '梓', '' => '梵', '' => '桿', '' => '桶', '' => '梱', '' => '梧', '' => '梗', '' => '械', '' => '梃', '' => '棄', '' => '梭', '' => '梆', '' => '梅', '' => '梔', '' => '條', '' => '梨', '' => '梟', '' => '梡', '' => '梂', '' => '欲', '' => '殺', '@' => '毫', 'A' => '毬', 'B' => '氫', 'C' => '涎', 'D' => '涼', 'E' => '淳', 'F' => '淙', 'G' => '液', 'H' => '淡', 'I' => '淌', 'J' => '淤', 'K' => '添', 'L' => '淺', 'M' => '清', 'N' => '淇', 'O' => '淋', 'P' => '涯', 'Q' => '淑', 'R' => '涮', 'S' => '淞', 'T' => '淹', 'U' => '涸', 'V' => '混', 'W' => '淵', 'X' => '淅', 'Y' => '淒', 'Z' => '渚', '[' => '涵', '\\' => '淚', ']' => '淫', '^' => '淘', '_' => '淪', '`' => '深', 'a' => '淮', 'b' => '淨', 'c' => '淆', 'd' => '淄', 'e' => '涪', 'f' => '淬', 'g' => '涿', 'h' => '淦', 'i' => '烹', 'j' => '焉', 'k' => '焊', 'l' => '烽', 'm' => '烯', 'n' => '爽', 'o' => '牽', 'p' => '犁', 'q' => '猜', 'r' => '猛', 's' => '猖', 't' => '猓', 'u' => '猙', 'v' => '率', 'w' => '琅', 'x' => '琊', 'y' => '球', 'z' => '理', '{' => '現', '|' => '琍', '}' => '瓠', '~' => '瓶', '' => '瓷', '' => '甜', '' => '產', '' => '略', '' => '畦', '' => '畢', '' => '異', '' => '疏', '' => '痔', '' => '痕', '' => '疵', '' => '痊', '' => '痍', '' => '皎', '' => '盔', '' => '盒', '' => '盛', '' => '眷', '' => '眾', '' => '眼', '' => '眶', '' => '眸', '' => '眺', '' => '硫', '' => '硃', '' => '硎', '' => '祥', '' => '票', '' => '祭', '' => '移', '' => '窒', '' => '窕', '' => '笠', '' => '笨', '' => '笛', '' => '第', '' => '符', '' => '笙', '' => '笞', '' => '笮', '' => '粒', '' => '粗', '' => '粕', '' => '絆', '' => '絃', '' => '統', '' => '紮', '' => '紹', '' => '紼', '' => '絀', '' => '細', '' => '紳', '' => '組', '' => '累', '' => '終', '' => '紲', '' => '紱', '' => '缽', '' => '羞', '' => '羚', '' => '翌', '' => '翎', '' => '習', '' => '耜', '' => '聊', '' => '聆', '' => '脯', '' => '脖', '' => '脣', '' => '脫', '' => '脩', '' => '脰', '' => '脤', '' => '舂', '' => '舵', '' => '舷', '' => '舶', '' => '船', '' => '莎', '' => '莞', '' => '莘', '' => '荸', '' => '莢', '' => '莖', '' => '莽', '' => '莫', '' => '莒', '' => '莊', '' => '莓', '' => '莉', '' => '莠', '' => '荷', '' => '荻', '' => '荼', '@' => '莆', 'A' => '莧', 'B' => '處', 'C' => '彪', 'D' => '蛇', 'E' => '蛀', 'F' => '蚶', 'G' => '蛄', 'H' => '蚵', 'I' => '蛆', 'J' => '蛋', 'K' => '蚱', 'L' => '蚯', 'M' => '蛉', 'N' => '術', 'O' => '袞', 'P' => '袈', 'Q' => '被', 'R' => '袒', 'S' => '袖', 'T' => '袍', 'U' => '袋', 'V' => '覓', 'W' => '規', 'X' => '訪', 'Y' => '訝', 'Z' => '訣', '[' => '訥', '\\' => '許', ']' => '設', '^' => '訟', '_' => '訛', '`' => '訢', 'a' => '豉', 'b' => '豚', 'c' => '販', 'd' => '責', 'e' => '貫', 'f' => '貨', 'g' => '貪', 'h' => '貧', 'i' => '赧', 'j' => '赦', 'k' => '趾', 'l' => '趺', 'm' => '軛', 'n' => '軟', 'o' => '這', 'p' => '逍', 'q' => '通', 'r' => '逗', 's' => '連', 't' => '速', 'u' => '逝', 'v' => '逐', 'w' => '逕', 'x' => '逞', 'y' => '造', 'z' => '透', '{' => '逢', '|' => '逖', '}' => '逛', '~' => '途', '' => '部', '' => '郭', '' => '都', '' => '酗', '' => '野', '' => '釵', '' => '釦', '' => '釣', '' => '釧', '' => '釭', '' => '釩', '' => '閉', '' => '陪', '' => '陵', '' => '陳', '' => '陸', '' => '陰', '' => '陴', '' => '陶', '' => '陷', '' => '陬', '' => '雀', '' => '雪', '' => '雩', '' => '章', '' => '竟', '' => '頂', '' => '頃', '' => '魚', '' => '鳥', '' => '鹵', '' => '鹿', '' => '麥', '' => '麻', '' => '傢', '' => '傍', '' => '傅', '' => '備', '' => '傑', '' => '傀', '' => '傖', '' => '傘', '' => '傚', '' => '最', '' => '凱', '' => '割', '' => '剴', '' => '創', '' => '剩', '' => '勞', '' => '勝', '' => '勛', '' => '博', '' => '厥', '' => '啻', '' => '喀', '' => '喧', '' => '啼', '' => '喊', '' => '喝', '' => '喘', '' => '喂', '' => '喜', '' => '喪', '' => '喔', '' => '喇', '' => '喋', '' => '喃', '' => '喳', '' => '單', '' => '喟', '' => '唾', '' => '喲', '' => '喚', '' => '喻', '' => '喬', '' => '喱', '' => '啾', '' => '喉', '' => '喫', '' => '喙', '' => '圍', '' => '堯', '' => '堪', '' => '場', '' => '堤', '' => '堰', '' => '報', '' => '堡', '' => '堝', '' => '堠', '' => '壹', '' => '壺', '' => '奠', '@' => '婷', 'A' => '媚', 'B' => '婿', 'C' => '媒', 'D' => '媛', 'E' => '媧', 'F' => '孳', 'G' => '孱', 'H' => '寒', 'I' => '富', 'J' => '寓', 'K' => '寐', 'L' => '尊', 'M' => '尋', 'N' => '就', 'O' => '嵌', 'P' => '嵐', 'Q' => '崴', 'R' => '嵇', 'S' => '巽', 'T' => '幅', 'U' => '帽', 'V' => '幀', 'W' => '幃', 'X' => '幾', 'Y' => '廊', 'Z' => '廁', '[' => '廂', '\\' => '廄', ']' => '弼', '^' => '彭', '_' => '復', '`' => '循', 'a' => '徨', 'b' => '惑', 'c' => '惡', 'd' => '悲', 'e' => '悶', 'f' => '惠', 'g' => '愜', 'h' => '愣', 'i' => '惺', 'j' => '愕', 'k' => '惰', 'l' => '惻', 'm' => '惴', 'n' => '慨', 'o' => '惱', 'p' => '愎', 'q' => '惶', 'r' => '愉', 's' => '愀', 't' => '愒', 'u' => '戟', 'v' => '扉', 'w' => '掣', 'x' => '掌', 'y' => '描', 'z' => '揀', '{' => '揩', '|' => '揉', '}' => '揆', '~' => '揍', '' => '插', '' => '揣', '' => '提', '' => '握', '' => '揖', '' => '揭', '' => '揮', '' => '捶', '' => '援', '' => '揪', '' => '換', '' => '摒', '' => '揚', '' => '揹', '' => '敞', '' => '敦', '' => '敢', '' => '散', '' => '斑', '' => '斐', '' => '斯', '' => '普', '' => '晰', '' => '晴', '' => '晶', '' => '景', '' => '暑', '' => '智', '' => '晾', '' => '晷', '' => '曾', '' => '替', '' => '期', '' => '朝', '' => '棺', '' => '棕', '' => '棠', '' => '棘', '' => '棗', '' => '椅', '' => '棟', '' => '棵', '' => '森', '' => '棧', '' => '棹', '' => '棒', '' => '棲', '' => '棣', '' => '棋', '' => '棍', '' => '植', '' => '椒', '' => '椎', '' => '棉', '' => '棚', '' => '楮', '' => '棻', '' => '款', '' => '欺', '' => '欽', '' => '殘', '' => '殖', '' => '殼', '' => '毯', '' => '氮', '' => '氯', '' => '氬', '' => '港', '' => '游', '' => '湔', '' => '渡', '' => '渲', '' => '湧', '' => '湊', '' => '渠', '' => '渥', '' => '渣', '' => '減', '' => '湛', '' => '湘', '' => '渤', '' => '湖', '' => '湮', '' => '渭', '' => '渦', '' => '湯', '' => '渴', '' => '湍', '' => '渺', '' => '測', '' => '湃', '' => '渝', '' => '渾', '' => '滋', '@' => '溉', 'A' => '渙', 'B' => '湎', 'C' => '湣', 'D' => '湄', 'E' => '湲', 'F' => '湩', 'G' => '湟', 'H' => '焙', 'I' => '焚', 'J' => '焦', 'K' => '焰', 'L' => '無', 'M' => '然', 'N' => '煮', 'O' => '焜', 'P' => '牌', 'Q' => '犄', 'R' => '犀', 'S' => '猶', 'T' => '猥', 'U' => '猴', 'V' => '猩', 'W' => '琺', 'X' => '琪', 'Y' => '琳', 'Z' => '琢', '[' => '琥', '\\' => '琵', ']' => '琶', '^' => '琴', '_' => '琯', '`' => '琛', 'a' => '琦', 'b' => '琨', 'c' => '甥', 'd' => '甦', 'e' => '畫', 'f' => '番', 'g' => '痢', 'h' => '痛', 'i' => '痣', 'j' => '痙', 'k' => '痘', 'l' => '痞', 'm' => '痠', 'n' => '登', 'o' => '發', 'p' => '皖', 'q' => '皓', 'r' => '皴', 's' => '盜', 't' => '睏', 'u' => '短', 'v' => '硝', 'w' => '硬', 'x' => '硯', 'y' => '稍', 'z' => '稈', '{' => '程', '|' => '稅', '}' => '稀', '~' => '窘', '' => '窗', '' => '窖', '' => '童', '' => '竣', '' => '等', '' => '策', '' => '筆', '' => '筐', '' => '筒', '' => '答', '' => '筍', '' => '筋', '' => '筏', '' => '筑', '' => '粟', '' => '粥', '' => '絞', '' => '結', '' => '絨', '' => '絕', '' => '紫', '' => '絮', '' => '絲', '' => '絡', '' => '給', '' => '絢', '' => '絰', '' => '絳', '' => '善', '' => '翔', '' => '翕', '' => '耋', '' => '聒', '' => '肅', '' => '腕', '' => '腔', '' => '腋', '' => '腑', '' => '腎', '' => '脹', '' => '腆', '' => '脾', '' => '腌', '' => '腓', '' => '腴', '' => '舒', '' => '舜', '' => '菩', '' => '萃', '' => '菸', '' => '萍', '' => '菠', '' => '菅', '' => '萋', '' => '菁', '' => '華', '' => '菱', '' => '菴', '' => '著', '' => '萊', '' => '菰', '' => '萌', '' => '菌', '' => '菽', '' => '菲', '' => '菊', '' => '萸', '' => '萎', '' => '萄', '' => '菜', '' => '萇', '' => '菔', '' => '菟', '' => '虛', '' => '蛟', '' => '蛙', '' => '蛭', '' => '蛔', '' => '蛛', '' => '蛤', '' => '蛐', '' => '蛞', '' => '街', '' => '裁', '' => '裂', '' => '袱', '' => '覃', '' => '視', '' => '註', '' => '詠', '' => '評', '' => '詞', '' => '証', '' => '詁', '@' => '詔', 'A' => '詛', 'B' => '詐', 'C' => '詆', 'D' => '訴', 'E' => '診', 'F' => '訶', 'G' => '詖', 'H' => '象', 'I' => '貂', 'J' => '貯', 'K' => '貼', 'L' => '貳', 'M' => '貽', 'N' => '賁', 'O' => '費', 'P' => '賀', 'Q' => '貴', 'R' => '買', 'S' => '貶', 'T' => '貿', 'U' => '貸', 'V' => '越', 'W' => '超', 'X' => '趁', 'Y' => '跎', 'Z' => '距', '[' => '跋', '\\' => '跚', ']' => '跑', '^' => '跌', '_' => '跛', '`' => '跆', 'a' => '軻', 'b' => '軸', 'c' => '軼', 'd' => '辜', 'e' => '逮', 'f' => '逵', 'g' => '週', 'h' => '逸', 'i' => '進', 'j' => '逶', 'k' => '鄂', 'l' => '郵', 'm' => '鄉', 'n' => '郾', 'o' => '酣', 'p' => '酥', 'q' => '量', 'r' => '鈔', 's' => '鈕', 't' => '鈣', 'u' => '鈉', 'v' => '鈞', 'w' => '鈍', 'x' => '鈐', 'y' => '鈇', 'z' => '鈑', '{' => '閔', '|' => '閏', '}' => '開', '~' => '閑', '' => '間', '' => '閒', '' => '閎', '' => '隊', '' => '階', '' => '隋', '' => '陽', '' => '隅', '' => '隆', '' => '隍', '' => '陲', '' => '隄', '' => '雁', '' => '雅', '' => '雄', '' => '集', '' => '雇', '' => '雯', '' => '雲', '' => '韌', '' => '項', '' => '順', '' => '須', '' => '飧', '' => '飪', '' => '飯', '' => '飩', '' => '飲', '' => '飭', '' => '馮', '' => '馭', '' => '黃', '' => '黍', '' => '黑', '' => '亂', '' => '傭', '' => '債', '' => '傲', '' => '傳', '' => '僅', '' => '傾', '' => '催', '' => '傷', '' => '傻', '' => '傯', '' => '僇', '' => '剿', '' => '剷', '' => '剽', '' => '募', '' => '勦', '' => '勤', '' => '勢', '' => '勣', '' => '匯', '' => '嗟', '' => '嗨', '' => '嗓', '' => '嗦', '' => '嗎', '' => '嗜', '' => '嗇', '' => '嗑', '' => '嗣', '' => '嗤', '' => '嗯', '' => '嗚', '' => '嗡', '' => '嗅', '' => '嗆', '' => '嗥', '' => '嗉', '' => '園', '' => '圓', '' => '塞', '' => '塑', '' => '塘', '' => '塗', '' => '塚', '' => '塔', '' => '填', '' => '塌', '' => '塭', '' => '塊', '' => '塢', '' => '塒', '' => '塋', '' => '奧', '' => '嫁', '' => '嫉', '' => '嫌', '' => '媾', '' => '媽', '' => '媼', '@' => '媳', 'A' => '嫂', 'B' => '媲', 'C' => '嵩', 'D' => '嵯', 'E' => '幌', 'F' => '幹', 'G' => '廉', 'H' => '廈', 'I' => '弒', 'J' => '彙', 'K' => '徬', 'L' => '微', 'M' => '愚', 'N' => '意', 'O' => '慈', 'P' => '感', 'Q' => '想', 'R' => '愛', 'S' => '惹', 'T' => '愁', 'U' => '愈', 'V' => '慎', 'W' => '慌', 'X' => '慄', 'Y' => '慍', 'Z' => '愾', '[' => '愴', '\\' => '愧', ']' => '愍', '^' => '愆', '_' => '愷', '`' => '戡', 'a' => '戢', 'b' => '搓', 'c' => '搾', 'd' => '搞', 'e' => '搪', 'f' => '搭', 'g' => '搽', 'h' => '搬', 'i' => '搏', 'j' => '搜', 'k' => '搔', 'l' => '損', 'm' => '搶', 'n' => '搖', 'o' => '搗', 'p' => '搆', 'q' => '敬', 'r' => '斟', 's' => '新', 't' => '暗', 'u' => '暉', 'v' => '暇', 'w' => '暈', 'x' => '暖', 'y' => '暄', 'z' => '暘', '{' => '暍', '|' => '會', '}' => '榔', '~' => '業', '' => '楚', '' => '楷', '' => '楠', '' => '楔', '' => '極', '' => '椰', '' => '概', '' => '楊', '' => '楨', '' => '楫', '' => '楞', '' => '楓', '' => '楹', '' => '榆', '' => '楝', '' => '楣', '' => '楛', '' => '歇', '' => '歲', '' => '毀', '' => '殿', '' => '毓', '' => '毽', '' => '溢', '' => '溯', '' => '滓', '' => '溶', '' => '滂', '' => '源', '' => '溝', '' => '滇', '' => '滅', '' => '溥', '' => '溘', '' => '溼', '' => '溺', '' => '溫', '' => '滑', '' => '準', '' => '溜', '' => '滄', '' => '滔', '' => '溪', '' => '溧', '' => '溴', '' => '煎', '' => '煙', '' => '煩', '' => '煤', '' => '煉', '' => '照', '' => '煜', '' => '煬', '' => '煦', '' => '煌', '' => '煥', '' => '煞', '' => '煆', '' => '煨', '' => '煖', '' => '爺', '' => '牒', '' => '猷', '' => '獅', '' => '猿', '' => '猾', '' => '瑯', '' => '瑚', '' => '瑕', '' => '瑟', '' => '瑞', '' => '瑁', '' => '琿', '' => '瑙', '' => '瑛', '' => '瑜', '' => '當', '' => '畸', '' => '瘀', '' => '痰', '' => '瘁', '' => '痲', '' => '痱', '' => '痺', '' => '痿', '' => '痴', '' => '痳', '' => '盞', '' => '盟', '' => '睛', '' => '睫', '' => '睦', '' => '睞', '' => '督', '@' => '睹', 'A' => '睪', 'B' => '睬', 'C' => '睜', 'D' => '睥', 'E' => '睨', 'F' => '睢', 'G' => '矮', 'H' => '碎', 'I' => '碰', 'J' => '碗', 'K' => '碘', 'L' => '碌', 'M' => '碉', 'N' => '硼', 'O' => '碑', 'P' => '碓', 'Q' => '硿', 'R' => '祺', 'S' => '祿', 'T' => '禁', 'U' => '萬', 'V' => '禽', 'W' => '稜', 'X' => '稚', 'Y' => '稠', 'Z' => '稔', '[' => '稟', '\\' => '稞', ']' => '窟', '^' => '窠', '_' => '筷', '`' => '節', 'a' => '筠', 'b' => '筮', 'c' => '筧', 'd' => '粱', 'e' => '粳', 'f' => '粵', 'g' => '經', 'h' => '絹', 'i' => '綑', 'j' => '綁', 'k' => '綏', 'l' => '絛', 'm' => '置', 'n' => '罩', 'o' => '罪', 'p' => '署', 'q' => '義', 'r' => '羨', 's' => '群', 't' => '聖', 'u' => '聘', 'v' => '肆', 'w' => '肄', 'x' => '腱', 'y' => '腰', 'z' => '腸', '{' => '腥', '|' => '腮', '}' => '腳', '~' => '腫', '' => '腹', '' => '腺', '' => '腦', '' => '舅', '' => '艇', '' => '蒂', '' => '葷', '' => '落', '' => '萱', '' => '葵', '' => '葦', '' => '葫', '' => '葉', '' => '葬', '' => '葛', '' => '萼', '' => '萵', '' => '葡', '' => '董', '' => '葩', '' => '葭', '' => '葆', '' => '虞', '' => '虜', '' => '號', '' => '蛹', '' => '蜓', '' => '蜈', '' => '蜇', '' => '蜀', '' => '蛾', '' => '蛻', '' => '蜂', '' => '蜃', '' => '蜆', '' => '蜊', '' => '衙', '' => '裟', '' => '裔', '' => '裙', '' => '補', '' => '裘', '' => '裝', '' => '裡', '' => '裊', '' => '裕', '' => '裒', '' => '覜', '' => '解', '' => '詫', '' => '該', '' => '詳', '' => '試', '' => '詩', '' => '詰', '' => '誇', '' => '詼', '' => '詣', '' => '誠', '' => '話', '' => '誅', '' => '詭', '' => '詢', '' => '詮', '' => '詬', '' => '詹', '' => '詻', '' => '訾', '' => '詨', '' => '豢', '' => '貊', '' => '貉', '' => '賊', '' => '資', '' => '賈', '' => '賄', '' => '貲', '' => '賃', '' => '賂', '' => '賅', '' => '跡', '' => '跟', '' => '跨', '' => '路', '' => '跳', '' => '跺', '' => '跪', '' => '跤', '' => '跦', '' => '躲', '' => '較', '' => '載', '' => '軾', '' => '輊', '@' => '辟', 'A' => '農', 'B' => '運', 'C' => '遊', 'D' => '道', 'E' => '遂', 'F' => '達', 'G' => '逼', 'H' => '違', 'I' => '遐', 'J' => '遇', 'K' => '遏', 'L' => '過', 'M' => '遍', 'N' => '遑', 'O' => '逾', 'P' => '遁', 'Q' => '鄒', 'R' => '鄗', 'S' => '酬', 'T' => '酪', 'U' => '酩', 'V' => '釉', 'W' => '鈷', 'X' => '鉗', 'Y' => '鈸', 'Z' => '鈽', '[' => '鉀', '\\' => '鈾', ']' => '鉛', '^' => '鉋', '_' => '鉤', '`' => '鉑', 'a' => '鈴', 'b' => '鉉', 'c' => '鉍', 'd' => '鉅', 'e' => '鈹', 'f' => '鈿', 'g' => '鉚', 'h' => '閘', 'i' => '隘', 'j' => '隔', 'k' => '隕', 'l' => '雍', 'm' => '雋', 'n' => '雉', 'o' => '雊', 'p' => '雷', 'q' => '電', 'r' => '雹', 's' => '零', 't' => '靖', 'u' => '靴', 'v' => '靶', 'w' => '預', 'x' => '頑', 'y' => '頓', 'z' => '頊', '{' => '頒', '|' => '頌', '}' => '飼', '~' => '飴', '' => '飽', '' => '飾', '' => '馳', '' => '馱', '' => '馴', '' => '髡', '' => '鳩', '' => '麂', '' => '鼎', '' => '鼓', '' => '鼠', '' => '僧', '' => '僮', '' => '僥', '' => '僖', '' => '僭', '' => '僚', '' => '僕', '' => '像', '' => '僑', '' => '僱', '' => '僎', '' => '僩', '' => '兢', '' => '凳', '' => '劃', '' => '劂', '' => '匱', '' => '厭', '' => '嗾', '' => '嘀', '' => '嘛', '' => '嘗', '' => '嗽', '' => '嘔', '' => '嘆', '' => '嘉', '' => '嘍', '' => '嘎', '' => '嗷', '' => '嘖', '' => '嘟', '' => '嘈', '' => '嘐', '' => '嗶', '' => '團', '' => '圖', '' => '塵', '' => '塾', '' => '境', '' => '墓', '' => '墊', '' => '塹', '' => '墅', '' => '塽', '' => '壽', '' => '夥', '' => '夢', '' => '夤', '' => '奪', '' => '奩', '' => '嫡', '' => '嫦', '' => '嫩', '' => '嫗', '' => '嫖', '' => '嫘', '' => '嫣', '' => '孵', '' => '寞', '' => '寧', '' => '寡', '' => '寥', '' => '實', '' => '寨', '' => '寢', '' => '寤', '' => '察', '' => '對', '' => '屢', '' => '嶄', '' => '嶇', '' => '幛', '' => '幣', '' => '幕', '' => '幗', '' => '幔', '' => '廓', '' => '廖', '' => '弊', '' => '彆', '' => '彰', '' => '徹', '' => '慇', '@' => '愿', 'A' => '態', 'B' => '慷', 'C' => '慢', 'D' => '慣', 'E' => '慟', 'F' => '慚', 'G' => '慘', 'H' => '慵', 'I' => '截', 'J' => '撇', 'K' => '摘', 'L' => '摔', 'M' => '撤', 'N' => '摸', 'O' => '摟', 'P' => '摺', 'Q' => '摑', 'R' => '摧', 'S' => '搴', 'T' => '摭', 'U' => '摻', 'V' => '敲', 'W' => '斡', 'X' => '旗', 'Y' => '旖', 'Z' => '暢', '[' => '暨', '\\' => '暝', ']' => '榜', '^' => '榨', '_' => '榕', '`' => '槁', 'a' => '榮', 'b' => '槓', 'c' => '構', 'd' => '榛', 'e' => '榷', 'f' => '榻', 'g' => '榫', 'h' => '榴', 'i' => '槐', 'j' => '槍', 'k' => '榭', 'l' => '槌', 'm' => '榦', 'n' => '槃', 'o' => '榣', 'p' => '歉', 'q' => '歌', 'r' => '氳', 's' => '漳', 't' => '演', 'u' => '滾', 'v' => '漓', 'w' => '滴', 'x' => '漩', 'y' => '漾', 'z' => '漠', '{' => '漬', '|' => '漏', '}' => '漂', '~' => '漢', '' => '滿', '' => '滯', '' => '漆', '' => '漱', '' => '漸', '' => '漲', '' => '漣', '' => '漕', '' => '漫', '' => '漯', '' => '澈', '' => '漪', '' => '滬', '' => '漁', '' => '滲', '' => '滌', '' => '滷', '' => '熔', '' => '熙', '' => '煽', '' => '熊', '' => '熄', '' => '熒', '' => '爾', '' => '犒', '' => '犖', '' => '獄', '' => '獐', '' => '瑤', '' => '瑣', '' => '瑪', '' => '瑰', '' => '瑭', '' => '甄', '' => '疑', '' => '瘧', '' => '瘍', '' => '瘋', '' => '瘉', '' => '瘓', '' => '盡', '' => '監', '' => '瞄', '' => '睽', '' => '睿', '' => '睡', '' => '磁', '' => '碟', '' => '碧', '' => '碳', '' => '碩', '' => '碣', '' => '禎', '' => '福', '' => '禍', '' => '種', '' => '稱', '' => '窪', '' => '窩', '' => '竭', '' => '端', '' => '管', '' => '箕', '' => '箋', '' => '筵', '' => '算', '' => '箝', '' => '箔', '' => '箏', '' => '箸', '' => '箇', '' => '箄', '' => '粹', '' => '粽', '' => '精', '' => '綻', '' => '綰', '' => '綜', '' => '綽', '' => '綾', '' => '綠', '' => '緊', '' => '綴', '' => '網', '' => '綱', '' => '綺', '' => '綢', '' => '綿', '' => '綵', '' => '綸', '' => '維', '' => '緒', '' => '緇', '' => '綬', '@' => '罰', 'A' => '翠', 'B' => '翡', 'C' => '翟', 'D' => '聞', 'E' => '聚', 'F' => '肇', 'G' => '腐', 'H' => '膀', 'I' => '膏', 'J' => '膈', 'K' => '膊', 'L' => '腿', 'M' => '膂', 'N' => '臧', 'O' => '臺', 'P' => '與', 'Q' => '舔', 'R' => '舞', 'S' => '艋', 'T' => '蓉', 'U' => '蒿', 'V' => '蓆', 'W' => '蓄', 'X' => '蒙', 'Y' => '蒞', 'Z' => '蒲', '[' => '蒜', '\\' => '蓋', ']' => '蒸', '^' => '蓀', '_' => '蓓', '`' => '蒐', 'a' => '蒼', 'b' => '蓑', 'c' => '蓊', 'd' => '蜿', 'e' => '蜜', 'f' => '蜻', 'g' => '蜢', 'h' => '蜥', 'i' => '蜴', 'j' => '蜘', 'k' => '蝕', 'l' => '蜷', 'm' => '蜩', 'n' => '裳', 'o' => '褂', 'p' => '裴', 'q' => '裹', 'r' => '裸', 's' => '製', 't' => '裨', 'u' => '褚', 'v' => '裯', 'w' => '誦', 'x' => '誌', 'y' => '語', 'z' => '誣', '{' => '認', '|' => '誡', '}' => '誓', '~' => '誤', '' => '說', '' => '誥', '' => '誨', '' => '誘', '' => '誑', '' => '誚', '' => '誧', '' => '豪', '' => '貍', '' => '貌', '' => '賓', '' => '賑', '' => '賒', '' => '赫', '' => '趙', '' => '趕', '' => '跼', '' => '輔', '' => '輒', '' => '輕', '' => '輓', '' => '辣', '' => '遠', '' => '遘', '' => '遜', '' => '遣', '' => '遙', '' => '遞', '' => '遢', '' => '遝', '' => '遛', '' => '鄙', '' => '鄘', '' => '鄞', '' => '酵', '' => '酸', '' => '酷', '' => '酴', '' => '鉸', '' => '銀', '' => '銅', '' => '銘', '' => '銖', '' => '鉻', '' => '銓', '' => '銜', '' => '銨', '' => '鉼', '' => '銑', '' => '閡', '' => '閨', '' => '閩', '' => '閣', '' => '閥', '' => '閤', '' => '隙', '' => '障', '' => '際', '' => '雌', '' => '雒', '' => '需', '' => '靼', '' => '鞅', '' => '韶', '' => '頗', '' => '領', '' => '颯', '' => '颱', '' => '餃', '' => '餅', '' => '餌', '' => '餉', '' => '駁', '' => '骯', '' => '骰', '' => '髦', '' => '魁', '' => '魂', '' => '鳴', '' => '鳶', '' => '鳳', '' => '麼', '' => '鼻', '' => '齊', '' => '億', '' => '儀', '' => '僻', '' => '僵', '' => '價', '' => '儂', '' => '儈', '' => '儉', '' => '儅', '' => '凜', '@' => '劇', 'A' => '劈', 'B' => '劉', 'C' => '劍', 'D' => '劊', 'E' => '勰', 'F' => '厲', 'G' => '嘮', 'H' => '嘻', 'I' => '嘹', 'J' => '嘲', 'K' => '嘿', 'L' => '嘴', 'M' => '嘩', 'N' => '噓', 'O' => '噎', 'P' => '噗', 'Q' => '噴', 'R' => '嘶', 'S' => '嘯', 'T' => '嘰', 'U' => '墀', 'V' => '墟', 'W' => '增', 'X' => '墳', 'Y' => '墜', 'Z' => '墮', '[' => '墩', '\\' => '墦', ']' => '奭', '^' => '嬉', '_' => '嫻', '`' => '嬋', 'a' => '嫵', 'b' => '嬌', 'c' => '嬈', 'd' => '寮', 'e' => '寬', 'f' => '審', 'g' => '寫', 'h' => '層', 'i' => '履', 'j' => '嶝', 'k' => '嶔', 'l' => '幢', 'm' => '幟', 'n' => '幡', 'o' => '廢', 'p' => '廚', 'q' => '廟', 'r' => '廝', 's' => '廣', 't' => '廠', 'u' => '彈', 'v' => '影', 'w' => '德', 'x' => '徵', 'y' => '慶', 'z' => '慧', '{' => '慮', '|' => '慝', '}' => '慕', '~' => '憂', '' => '慼', '' => '慰', '' => '慫', '' => '慾', '' => '憧', '' => '憐', '' => '憫', '' => '憎', '' => '憬', '' => '憚', '' => '憤', '' => '憔', '' => '憮', '' => '戮', '' => '摩', '' => '摯', '' => '摹', '' => '撞', '' => '撲', '' => '撈', '' => '撐', '' => '撰', '' => '撥', '' => '撓', '' => '撕', '' => '撩', '' => '撒', '' => '撮', '' => '播', '' => '撫', '' => '撚', '' => '撬', '' => '撙', '' => '撢', '' => '撳', '' => '敵', '' => '敷', '' => '數', '' => '暮', '' => '暫', '' => '暴', '' => '暱', '' => '樣', '' => '樟', '' => '槨', '' => '樁', '' => '樞', '' => '標', '' => '槽', '' => '模', '' => '樓', '' => '樊', '' => '槳', '' => '樂', '' => '樅', '' => '槭', '' => '樑', '' => '歐', '' => '歎', '' => '殤', '' => '毅', '' => '毆', '' => '漿', '' => '潼', '' => '澄', '' => '潑', '' => '潦', '' => '潔', '' => '澆', '' => '潭', '' => '潛', '' => '潸', '' => '潮', '' => '澎', '' => '潺', '' => '潰', '' => '潤', '' => '澗', '' => '潘', '' => '滕', '' => '潯', '' => '潠', '' => '潟', '' => '熟', '' => '熬', '' => '熱', '' => '熨', '' => '牖', '' => '犛', '' => '獎', '' => '獗', '' => '瑩', '' => '璋', '' => '璃', '@' => '瑾', 'A' => '璀', 'B' => '畿', 'C' => '瘠', 'D' => '瘩', 'E' => '瘟', 'F' => '瘤', 'G' => '瘦', 'H' => '瘡', 'I' => '瘢', 'J' => '皚', 'K' => '皺', 'L' => '盤', 'M' => '瞎', 'N' => '瞇', 'O' => '瞌', 'P' => '瞑', 'Q' => '瞋', 'R' => '磋', 'S' => '磅', 'T' => '確', 'U' => '磊', 'V' => '碾', 'W' => '磕', 'X' => '碼', 'Y' => '磐', 'Z' => '稿', '[' => '稼', '\\' => '穀', ']' => '稽', '^' => '稷', '_' => '稻', '`' => '窯', 'a' => '窮', 'b' => '箭', 'c' => '箱', 'd' => '範', 'e' => '箴', 'f' => '篆', 'g' => '篇', 'h' => '篁', 'i' => '箠', 'j' => '篌', 'k' => '糊', 'l' => '締', 'm' => '練', 'n' => '緯', 'o' => '緻', 'p' => '緘', 'q' => '緬', 'r' => '緝', 's' => '編', 't' => '緣', 'u' => '線', 'v' => '緞', 'w' => '緩', 'x' => '綞', 'y' => '緙', 'z' => '緲', '{' => '緹', '|' => '罵', '}' => '罷', '~' => '羯', '' => '翩', '' => '耦', '' => '膛', '' => '膜', '' => '膝', '' => '膠', '' => '膚', '' => '膘', '' => '蔗', '' => '蔽', '' => '蔚', '' => '蓮', '' => '蔬', '' => '蔭', '' => '蔓', '' => '蔑', '' => '蔣', '' => '蔡', '' => '蔔', '' => '蓬', '' => '蔥', '' => '蓿', '' => '蔆', '' => '螂', '' => '蝴', '' => '蝶', '' => '蝠', '' => '蝦', '' => '蝸', '' => '蝨', '' => '蝙', '' => '蝗', '' => '蝌', '' => '蝓', '' => '衛', '' => '衝', '' => '褐', '' => '複', '' => '褒', '' => '褓', '' => '褕', '' => '褊', '' => '誼', '' => '諒', '' => '談', '' => '諄', '' => '誕', '' => '請', '' => '諸', '' => '課', '' => '諉', '' => '諂', '' => '調', '' => '誰', '' => '論', '' => '諍', '' => '誶', '' => '誹', '' => '諛', '' => '豌', '' => '豎', '' => '豬', '' => '賠', '' => '賞', '' => '賦', '' => '賤', '' => '賬', '' => '賭', '' => '賢', '' => '賣', '' => '賜', '' => '質', '' => '賡', '' => '赭', '' => '趟', '' => '趣', '' => '踫', '' => '踐', '' => '踝', '' => '踢', '' => '踏', '' => '踩', '' => '踟', '' => '踡', '' => '踞', '' => '躺', '' => '輝', '' => '輛', '' => '輟', '' => '輩', '' => '輦', '' => '輪', '' => '輜', '' => '輞', '@' => '輥', 'A' => '適', 'B' => '遮', 'C' => '遨', 'D' => '遭', 'E' => '遷', 'F' => '鄰', 'G' => '鄭', 'H' => '鄧', 'I' => '鄱', 'J' => '醇', 'K' => '醉', 'L' => '醋', 'M' => '醃', 'N' => '鋅', 'O' => '銻', 'P' => '銷', 'Q' => '鋪', 'R' => '銬', 'S' => '鋤', 'T' => '鋁', 'U' => '銳', 'V' => '銼', 'W' => '鋒', 'X' => '鋇', 'Y' => '鋰', 'Z' => '銲', '[' => '閭', '\\' => '閱', ']' => '霄', '^' => '霆', '_' => '震', '`' => '霉', 'a' => '靠', 'b' => '鞍', 'c' => '鞋', 'd' => '鞏', 'e' => '頡', 'f' => '頫', 'g' => '頜', 'h' => '颳', 'i' => '養', 'j' => '餓', 'k' => '餒', 'l' => '餘', 'm' => '駝', 'n' => '駐', 'o' => '駟', 'p' => '駛', 'q' => '駑', 'r' => '駕', 's' => '駒', 't' => '駙', 'u' => '骷', 'v' => '髮', 'w' => '髯', 'x' => '鬧', 'y' => '魅', 'z' => '魄', '{' => '魷', '|' => '魯', '}' => '鴆', '~' => '鴉', '' => '鴃', '' => '麩', '' => '麾', '' => '黎', '' => '墨', '' => '齒', '' => '儒', '' => '儘', '' => '儔', '' => '儐', '' => '儕', '' => '冀', '' => '冪', '' => '凝', '' => '劑', '' => '劓', '' => '勳', '' => '噙', '' => '噫', '' => '噹', '' => '噩', '' => '噤', '' => '噸', '' => '噪', '' => '器', '' => '噥', '' => '噱', '' => '噯', '' => '噬', '' => '噢', '' => '噶', '' => '壁', '' => '墾', '' => '壇', '' => '壅', '' => '奮', '' => '嬝', '' => '嬴', '' => '學', '' => '寰', '' => '導', '' => '彊', '' => '憲', '' => '憑', '' => '憩', '' => '憊', '' => '懍', '' => '憶', '' => '憾', '' => '懊', '' => '懈', '' => '戰', '' => '擅', '' => '擁', '' => '擋', '' => '撻', '' => '撼', '' => '據', '' => '擄', '' => '擇', '' => '擂', '' => '操', '' => '撿', '' => '擒', '' => '擔', '' => '撾', '' => '整', '' => '曆', '' => '曉', '' => '暹', '' => '曄', '' => '曇', '' => '暸', '' => '樽', '' => '樸', '' => '樺', '' => '橙', '' => '橫', '' => '橘', '' => '樹', '' => '橄', '' => '橢', '' => '橡', '' => '橋', '' => '橇', '' => '樵', '' => '機', '' => '橈', '' => '歙', '' => '歷', '' => '氅', '' => '濂', '' => '澱', '' => '澡', '@' => '濃', 'A' => '澤', 'B' => '濁', 'C' => '澧', 'D' => '澳', 'E' => '激', 'F' => '澹', 'G' => '澶', 'H' => '澦', 'I' => '澠', 'J' => '澴', 'K' => '熾', 'L' => '燉', 'M' => '燐', 'N' => '燒', 'O' => '燈', 'P' => '燕', 'Q' => '熹', 'R' => '燎', 'S' => '燙', 'T' => '燜', 'U' => '燃', 'V' => '燄', 'W' => '獨', 'X' => '璜', 'Y' => '璣', 'Z' => '璘', '[' => '璟', '\\' => '璞', ']' => '瓢', '^' => '甌', '_' => '甍', '`' => '瘴', 'a' => '瘸', 'b' => '瘺', 'c' => '盧', 'd' => '盥', 'e' => '瞠', 'f' => '瞞', 'g' => '瞟', 'h' => '瞥', 'i' => '磨', 'j' => '磚', 'k' => '磬', 'l' => '磧', 'm' => '禦', 'n' => '積', 'o' => '穎', 'p' => '穆', 'q' => '穌', 'r' => '穋', 's' => '窺', 't' => '篙', 'u' => '簑', 'v' => '築', 'w' => '篤', 'x' => '篛', 'y' => '篡', 'z' => '篩', '{' => '篦', '|' => '糕', '}' => '糖', '~' => '縊', '' => '縑', '' => '縈', '' => '縛', '' => '縣', '' => '縞', '' => '縝', '' => '縉', '' => '縐', '' => '罹', '' => '羲', '' => '翰', '' => '翱', '' => '翮', '' => '耨', '' => '膳', '' => '膩', '' => '膨', '' => '臻', '' => '興', '' => '艘', '' => '艙', '' => '蕊', '' => '蕙', '' => '蕈', '' => '蕨', '' => '蕩', '' => '蕃', '' => '蕉', '' => '蕭', '' => '蕪', '' => '蕞', '' => '螃', '' => '螟', '' => '螞', '' => '螢', '' => '融', '' => '衡', '' => '褪', '' => '褲', '' => '褥', '' => '褫', '' => '褡', '' => '親', '' => '覦', '' => '諦', '' => '諺', '' => '諫', '' => '諱', '' => '謀', '' => '諜', '' => '諧', '' => '諮', '' => '諾', '' => '謁', '' => '謂', '' => '諷', '' => '諭', '' => '諳', '' => '諶', '' => '諼', '' => '豫', '' => '豭', '' => '貓', '' => '賴', '' => '蹄', '' => '踱', '' => '踴', '' => '蹂', '' => '踹', '' => '踵', '' => '輻', '' => '輯', '' => '輸', '' => '輳', '' => '辨', '' => '辦', '' => '遵', '' => '遴', '' => '選', '' => '遲', '' => '遼', '' => '遺', '' => '鄴', '' => '醒', '' => '錠', '' => '錶', '' => '鋸', '' => '錳', '' => '錯', '' => '錢', '' => '鋼', '' => '錫', '' => '錄', '' => '錚', '@' => '錐', 'A' => '錦', 'B' => '錡', 'C' => '錕', 'D' => '錮', 'E' => '錙', 'F' => '閻', 'G' => '隧', 'H' => '隨', 'I' => '險', 'J' => '雕', 'K' => '霎', 'L' => '霑', 'M' => '霖', 'N' => '霍', 'O' => '霓', 'P' => '霏', 'Q' => '靛', 'R' => '靜', 'S' => '靦', 'T' => '鞘', 'U' => '頰', 'V' => '頸', 'W' => '頻', 'X' => '頷', 'Y' => '頭', 'Z' => '頹', '[' => '頤', '\\' => '餐', ']' => '館', '^' => '餞', '_' => '餛', '`' => '餡', 'a' => '餚', 'b' => '駭', 'c' => '駢', 'd' => '駱', 'e' => '骸', 'f' => '骼', 'g' => '髻', 'h' => '髭', 'i' => '鬨', 'j' => '鮑', 'k' => '鴕', 'l' => '鴣', 'm' => '鴦', 'n' => '鴨', 'o' => '鴒', 'p' => '鴛', 'q' => '默', 'r' => '黔', 's' => '龍', 't' => '龜', 'u' => '優', 'v' => '償', 'w' => '儡', 'x' => '儲', 'y' => '勵', 'z' => '嚎', '{' => '嚀', '|' => '嚐', '}' => '嚅', '~' => '嚇', '' => '嚏', '' => '壕', '' => '壓', '' => '壑', '' => '壎', '' => '嬰', '' => '嬪', '' => '嬤', '' => '孺', '' => '尷', '' => '屨', '' => '嶼', '' => '嶺', '' => '嶽', '' => '嶸', '' => '幫', '' => '彌', '' => '徽', '' => '應', '' => '懂', '' => '懇', '' => '懦', '' => '懋', '' => '戲', '' => '戴', '' => '擎', '' => '擊', '' => '擘', '' => '擠', '' => '擰', '' => '擦', '' => '擬', '' => '擱', '' => '擢', '' => '擭', '' => '斂', '' => '斃', '' => '曙', '' => '曖', '' => '檀', '' => '檔', '' => '檄', '' => '檢', '' => '檜', '' => '櫛', '' => '檣', '' => '橾', '' => '檗', '' => '檐', '' => '檠', '' => '歜', '' => '殮', '' => '毚', '' => '氈', '' => '濘', '' => '濱', '' => '濟', '' => '濠', '' => '濛', '' => '濤', '' => '濫', '' => '濯', '' => '澀', '' => '濬', '' => '濡', '' => '濩', '' => '濕', '' => '濮', '' => '濰', '' => '燧', '' => '營', '' => '燮', '' => '燦', '' => '燥', '' => '燭', '' => '燬', '' => '燴', '' => '燠', '' => '爵', '' => '牆', '' => '獰', '' => '獲', '' => '璩', '' => '環', '' => '璦', '' => '璨', '' => '癆', '' => '療', '' => '癌', '' => '盪', '' => '瞳', '' => '瞪', '' => '瞰', '' => '瞬', '@' => '瞧', 'A' => '瞭', 'B' => '矯', 'C' => '磷', 'D' => '磺', 'E' => '磴', 'F' => '磯', 'G' => '礁', 'H' => '禧', 'I' => '禪', 'J' => '穗', 'K' => '窿', 'L' => '簇', 'M' => '簍', 'N' => '篾', 'O' => '篷', 'P' => '簌', 'Q' => '篠', 'R' => '糠', 'S' => '糜', 'T' => '糞', 'U' => '糢', 'V' => '糟', 'W' => '糙', 'X' => '糝', 'Y' => '縮', 'Z' => '績', '[' => '繆', '\\' => '縷', ']' => '縲', '^' => '繃', '_' => '縫', '`' => '總', 'a' => '縱', 'b' => '繅', 'c' => '繁', 'd' => '縴', 'e' => '縹', 'f' => '繈', 'g' => '縵', 'h' => '縿', 'i' => '縯', 'j' => '罄', 'k' => '翳', 'l' => '翼', 'm' => '聱', 'n' => '聲', 'o' => '聰', 'p' => '聯', 'q' => '聳', 'r' => '臆', 's' => '臃', 't' => '膺', 'u' => '臂', 'v' => '臀', 'w' => '膿', 'x' => '膽', 'y' => '臉', 'z' => '膾', '{' => '臨', '|' => '舉', '}' => '艱', '~' => '薪', '' => '薄', '' => '蕾', '' => '薜', '' => '薑', '' => '薔', '' => '薯', '' => '薛', '' => '薇', '' => '薨', '' => '薊', '' => '虧', '' => '蟀', '' => '蟑', '' => '螳', '' => '蟒', '' => '蟆', '' => '螫', '' => '螻', '' => '螺', '' => '蟈', '' => '蟋', '' => '褻', '' => '褶', '' => '襄', '' => '褸', '' => '褽', '' => '覬', '' => '謎', '' => '謗', '' => '謙', '' => '講', '' => '謊', '' => '謠', '' => '謝', '' => '謄', '' => '謐', '' => '豁', '' => '谿', '' => '豳', '' => '賺', '' => '賽', '' => '購', '' => '賸', '' => '賻', '' => '趨', '' => '蹉', '' => '蹋', '' => '蹈', '' => '蹊', '' => '轄', '' => '輾', '' => '轂', '' => '轅', '' => '輿', '' => '避', '' => '遽', '' => '還', '' => '邁', '' => '邂', '' => '邀', '' => '鄹', '' => '醣', '' => '醞', '' => '醜', '' => '鍍', '' => '鎂', '' => '錨', '' => '鍵', '' => '鍊', '' => '鍥', '' => '鍋', '' => '錘', '' => '鍾', '' => '鍬', '' => '鍛', '' => '鍰', '' => '鍚', '' => '鍔', '' => '闊', '' => '闋', '' => '闌', '' => '闈', '' => '闆', '' => '隱', '' => '隸', '' => '雖', '' => '霜', '' => '霞', '' => '鞠', '' => '韓', '' => '顆', '' => '颶', '' => '餵', '' => '騁', '@' => '駿', 'A' => '鮮', 'B' => '鮫', 'C' => '鮪', 'D' => '鮭', 'E' => '鴻', 'F' => '鴿', 'G' => '麋', 'H' => '黏', 'I' => '點', 'J' => '黜', 'K' => '黝', 'L' => '黛', 'M' => '鼾', 'N' => '齋', 'O' => '叢', 'P' => '嚕', 'Q' => '嚮', 'R' => '壙', 'S' => '壘', 'T' => '嬸', 'U' => '彝', 'V' => '懣', 'W' => '戳', 'X' => '擴', 'Y' => '擲', 'Z' => '擾', '[' => '攆', '\\' => '擺', ']' => '擻', '^' => '擷', '_' => '斷', '`' => '曜', 'a' => '朦', 'b' => '檳', 'c' => '檬', 'd' => '櫃', 'e' => '檻', 'f' => '檸', 'g' => '櫂', 'h' => '檮', 'i' => '檯', 'j' => '歟', 'k' => '歸', 'l' => '殯', 'm' => '瀉', 'n' => '瀋', 'o' => '濾', 'p' => '瀆', 'q' => '濺', 'r' => '瀑', 's' => '瀏', 't' => '燻', 'u' => '燼', 'v' => '燾', 'w' => '燸', 'x' => '獷', 'y' => '獵', 'z' => '璧', '{' => '璿', '|' => '甕', '}' => '癖', '~' => '癘', '¡' => '癒', '¢' => '瞽', '£' => '瞿', '¤' => '瞻', '¥' => '瞼', '¦' => '礎', '§' => '禮', '¨' => '穡', '©' => '穢', 'ª' => '穠', '«' => '竄', '¬' => '竅', '­' => '簫', '®' => '簧', '¯' => '簪', '°' => '簞', '±' => '簣', '²' => '簡', '³' => '糧', '´' => '織', 'µ' => '繕', '¶' => '繞', '·' => '繚', '¸' => '繡', '¹' => '繒', 'º' => '繙', '»' => '罈', '¼' => '翹', '½' => '翻', '¾' => '職', '¿' => '聶', '' => '臍', '' => '臏', '' => '舊', '' => '藏', '' => '薩', '' => '藍', '' => '藐', '' => '藉', '' => '薰', '' => '薺', '' => '薹', '' => '薦', '' => '蟯', '' => '蟬', '' => '蟲', '' => '蟠', '' => '覆', '' => '覲', '' => '觴', '' => '謨', '' => '謹', '' => '謬', '' => '謫', '' => '豐', '' => '贅', '' => '蹙', '' => '蹣', '' => '蹦', '' => '蹤', '' => '蹟', '' => '蹕', '' => '軀', '' => '轉', '' => '轍', '' => '邇', '' => '邃', '' => '邈', '' => '醫', '' => '醬', '' => '釐', '' => '鎔', '' => '鎊', '' => '鎖', '' => '鎢', '' => '鎳', '' => '鎮', '' => '鎬', '' => '鎰', '' => '鎘', '' => '鎚', '' => '鎗', '' => '闔', '' => '闖', '' => '闐', '' => '闕', '' => '離', '' => '雜', '' => '雙', '' => '雛', '' => '雞', '' => '霤', '' => '鞣', '' => '鞦', '@' => '鞭', 'A' => '韹', 'B' => '額', 'C' => '顏', 'D' => '題', 'E' => '顎', 'F' => '顓', 'G' => '颺', 'H' => '餾', 'I' => '餿', 'J' => '餽', 'K' => '餮', 'L' => '馥', 'M' => '騎', 'N' => '髁', 'O' => '鬃', 'P' => '鬆', 'Q' => '魏', 'R' => '魎', 'S' => '魍', 'T' => '鯊', 'U' => '鯉', 'V' => '鯽', 'W' => '鯈', 'X' => '鯀', 'Y' => '鵑', 'Z' => '鵝', '[' => '鵠', '\\' => '黠', ']' => '鼕', '^' => '鼬', '_' => '儳', '`' => '嚥', 'a' => '壞', 'b' => '壟', 'c' => '壢', 'd' => '寵', 'e' => '龐', 'f' => '廬', 'g' => '懲', 'h' => '懷', 'i' => '懶', 'j' => '懵', 'k' => '攀', 'l' => '攏', 'm' => '曠', 'n' => '曝', 'o' => '櫥', 'p' => '櫝', 'q' => '櫚', 'r' => '櫓', 's' => '瀛', 't' => '瀟', 'u' => '瀨', 'v' => '瀚', 'w' => '瀝', 'x' => '瀕', 'y' => '瀘', 'z' => '爆', '{' => '爍', '|' => '牘', '}' => '犢', '~' => '獸', 'á' => '獺', 'â' => '璽', 'ã' => '瓊', 'ä' => '瓣', 'å' => '疇', 'æ' => '疆', 'ç' => '癟', 'è' => '癡', 'é' => '矇', 'ê' => '礙', 'ë' => '禱', 'ì' => '穫', 'í' => '穩', 'î' => '簾', 'ï' => '簿', 'ð' => '簸', 'ñ' => '簽', 'ò' => '簷', 'ó' => '籀', 'ô' => '繫', 'õ' => '繭', 'ö' => '繹', '÷' => '繩', 'ø' => '繪', 'ù' => '羅', 'ú' => '繳', 'û' => '羶', 'ü' => '羹', 'ý' => '羸', 'þ' => '臘', 'ÿ' => '藩', '' => '藝', '' => '藪', '' => '藕', '' => '藤', '' => '藥', '' => '藷', '' => '蟻', '' => '蠅', '' => '蠍', '' => '蟹', '' => '蟾', '' => '襠', '' => '襟', '' => '襖', '' => '襞', '' => '譁', '' => '譜', '' => '識', '' => '證', '' => '譚', '' => '譎', '' => '譏', '' => '譆', '' => '譙', '' => '贈', '' => '贊', '' => '蹼', '' => '蹲', '' => '躇', '' => '蹶', '' => '蹬', '' => '蹺', '' => '蹴', '' => '轔', '' => '轎', '' => '辭', '' => '邊', '' => '邋', '' => '醱', '' => '醮', '' => '鏡', '' => '鏑', '' => '鏟', '' => '鏃', '' => '鏈', '' => '鏜', '' => '鏝', '' => '鏖', '' => '鏢', '' => '鏍', '' => '鏘', '' => '鏤', '' => '鏗', '' => '鏨', '' => '關', '' => '隴', '' => '難', '' => '霪', '' => '霧', '' => '靡', '' => '韜', '' => '韻', '' => '類', '@' => '願', 'A' => '顛', 'B' => '颼', 'C' => '饅', 'D' => '饉', 'E' => '騖', 'F' => '騙', 'G' => '鬍', 'H' => '鯨', 'I' => '鯧', 'J' => '鯖', 'K' => '鯛', 'L' => '鶉', 'M' => '鵡', 'N' => '鵲', 'O' => '鵪', 'P' => '鵬', 'Q' => '麒', 'R' => '麗', 'S' => '麓', 'T' => '麴', 'U' => '勸', 'V' => '嚨', 'W' => '嚷', 'X' => '嚶', 'Y' => '嚴', 'Z' => '嚼', '[' => '壤', '\\' => '孀', ']' => '孃', '^' => '孽', '_' => '寶', '`' => '巉', 'a' => '懸', 'b' => '懺', 'c' => '攘', 'd' => '攔', 'e' => '攙', 'f' => '曦', 'g' => '朧', 'h' => '櫬', 'i' => '瀾', 'j' => '瀰', 'k' => '瀲', 'l' => '爐', 'm' => '獻', 'n' => '瓏', 'o' => '癢', 'p' => '癥', 'q' => '礦', 'r' => '礪', 's' => '礬', 't' => '礫', 'u' => '竇', 'v' => '競', 'w' => '籌', 'x' => '籃', 'y' => '籍', 'z' => '糯', '{' => '糰', '|' => '辮', '}' => '繽', '~' => '繼', 'ġ' => '纂', 'Ģ' => '罌', 'ģ' => '耀', 'Ĥ' => '臚', 'ĥ' => '艦', 'Ħ' => '藻', 'ħ' => '藹', 'Ĩ' => '蘑', 'ĩ' => '藺', 'Ī' => '蘆', 'ī' => '蘋', 'Ĭ' => '蘇', 'ĭ' => '蘊', 'Į' => '蠔', 'į' => '蠕', 'İ' => '襤', 'ı' => '覺', 'IJ' => '觸', 'ij' => '議', 'Ĵ' => '譬', 'ĵ' => '警', 'Ķ' => '譯', 'ķ' => '譟', 'ĸ' => '譫', 'Ĺ' => '贏', 'ĺ' => '贍', 'Ļ' => '躉', 'ļ' => '躁', 'Ľ' => '躅', 'ľ' => '躂', 'Ŀ' => '醴', '' => '釋', '' => '鐘', '' => '鐃', '' => '鏽', '' => '闡', '' => '霰', '' => '飄', '' => '饒', '' => '饑', '' => '馨', '' => '騫', '' => '騰', '' => '騷', '' => '騵', '' => '鰓', '' => '鰍', '' => '鹹', '' => '麵', '' => '黨', '' => '鼯', '' => '齟', '' => '齣', '' => '齡', '' => '儷', '' => '儸', '' => '囁', '' => '囀', '' => '囂', '' => '夔', '' => '屬', '' => '巍', '' => '懼', '' => '懾', '' => '攝', '' => '攜', '' => '斕', '' => '曩', '' => '櫻', '' => '欄', '' => '櫺', '' => '殲', '' => '灌', '' => '爛', '' => '犧', '' => '瓖', '' => '瓔', '' => '癩', '' => '矓', '' => '籐', '' => '纏', '' => '續', '' => '羼', '' => '蘗', '' => '蘭', '' => '蘚', '' => '蠣', '' => '蠢', '' => '蠡', '' => '蠟', '' => '襪', '' => '襬', '' => '覽', '' => '譴', '@' => '護', 'A' => '譽', 'B' => '贓', 'C' => '躊', 'D' => '躍', 'E' => '躋', 'F' => '轟', 'G' => '辯', 'H' => '醺', 'I' => '鐮', 'J' => '鐳', 'K' => '鐵', 'L' => '鐺', 'M' => '鐸', 'N' => '鐲', 'O' => '鐫', 'P' => '闢', 'Q' => '霸', 'R' => '霹', 'S' => '露', 'T' => '響', 'U' => '顧', 'V' => '顥', 'W' => '饗', 'X' => '驅', 'Y' => '驃', 'Z' => '驀', '[' => '騾', '\\' => '髏', ']' => '魔', '^' => '魑', '_' => '鰭', '`' => '鰥', 'a' => '鶯', 'b' => '鶴', 'c' => '鷂', 'd' => '鶸', 'e' => '麝', 'f' => '黯', 'g' => '鼙', 'h' => '齜', 'i' => '齦', 'j' => '齧', 'k' => '儼', 'l' => '儻', 'm' => '囈', 'n' => '囊', 'o' => '囉', 'p' => '孿', 'q' => '巔', 'r' => '巒', 's' => '彎', 't' => '懿', 'u' => '攤', 'v' => '權', 'w' => '歡', 'x' => '灑', 'y' => '灘', 'z' => '玀', '{' => '瓤', '|' => '疊', '}' => '癮', '~' => '癬', 'š' => '禳', 'Ţ' => '籠', 'ţ' => '籟', 'Ť' => '聾', 'ť' => '聽', 'Ŧ' => '臟', 'ŧ' => '襲', 'Ũ' => '襯', 'ũ' => '觼', 'Ū' => '讀', 'ū' => '贖', 'Ŭ' => '贗', 'ŭ' => '躑', 'Ů' => '躓', 'ů' => '轡', 'Ű' => '酈', 'ű' => '鑄', 'Ų' => '鑑', 'ų' => '鑒', 'Ŵ' => '霽', 'ŵ' => '霾', 'Ŷ' => '韃', 'ŷ' => '韁', 'Ÿ' => '顫', 'Ź' => '饕', 'ź' => '驕', 'Ż' => '驍', 'ż' => '髒', 'Ž' => '鬚', 'ž' => '鱉', 'ſ' => '鰱', '' => '鰾', '' => '鰻', '' => '鷓', '' => '鷗', '' => '鼴', '' => '齬', '' => '齪', '' => '龔', '' => '囌', '' => '巖', '' => '戀', '' => '攣', '' => '攫', '' => '攪', '' => '曬', '' => '欐', '' => '瓚', '' => '竊', '' => '籤', '' => '籣', '' => '籥', '' => '纓', '' => '纖', '' => '纔', '' => '臢', '' => '蘸', '' => '蘿', '' => '蠱', '' => '變', '' => '邐', '' => '邏', '' => '鑣', '' => '鑠', '' => '鑤', '' => '靨', '' => '顯', '' => '饜', '' => '驚', '' => '驛', '' => '驗', '' => '髓', '' => '體', '' => '髑', '' => '鱔', '' => '鱗', '' => '鱖', '' => '鷥', '' => '麟', '' => '黴', '' => '囑', '' => '壩', '' => '攬', '' => '灞', '' => '癱', '' => '癲', '' => '矗', '' => '罐', '' => '羈', '' => '蠶', '' => '蠹', '' => '衢', '' => '讓', '' => '讒', '@' => '讖', 'A' => '艷', 'B' => '贛', 'C' => '釀', 'D' => '鑪', 'E' => '靂', 'F' => '靈', 'G' => '靄', 'H' => '韆', 'I' => '顰', 'J' => '驟', 'K' => '鬢', 'L' => '魘', 'M' => '鱟', 'N' => '鷹', 'O' => '鷺', 'P' => '鹼', 'Q' => '鹽', 'R' => '鼇', 'S' => '齷', 'T' => '齲', 'U' => '廳', 'V' => '欖', 'W' => '灣', 'X' => '籬', 'Y' => '籮', 'Z' => '蠻', '[' => '觀', '\\' => '躡', ']' => '釁', '^' => '鑲', '_' => '鑰', '`' => '顱', 'a' => '饞', 'b' => '髖', 'c' => '鬣', 'd' => '黌', 'e' => '灤', 'f' => '矚', 'g' => '讚', 'h' => '鑷', 'i' => '韉', 'j' => '驢', 'k' => '驥', 'l' => '纜', 'm' => '讜', 'n' => '躪', 'o' => '釅', 'p' => '鑽', 'q' => '鑾', 'r' => '鑼', 's' => '鱷', 't' => '鱸', 'u' => '黷', 'v' => '豔', 'w' => '鑿', 'x' => '鸚', 'y' => '爨', 'z' => '驪', '{' => '鬱', '|' => '鸛', '}' => '鸞', '~' => '籲', '@' => '乂', 'A' => '乜', 'B' => '凵', 'C' => '匚', 'D' => '厂', 'E' => '万', 'F' => '丌', 'G' => '乇', 'H' => '亍', 'I' => '囗', 'J' => '兀', 'K' => '屮', 'L' => '彳', 'M' => '丏', 'N' => '冇', 'O' => '与', 'P' => '丮', 'Q' => '亓', 'R' => '仂', 'S' => '仉', 'T' => '仈', 'U' => '冘', 'V' => '勼', 'W' => '卬', 'X' => '厹', 'Y' => '圠', 'Z' => '夃', '[' => '夬', '\\' => '尐', ']' => '巿', '^' => '旡', '_' => '殳', '`' => '毌', 'a' => '气', 'b' => '爿', 'c' => '丱', 'd' => '丼', 'e' => '仨', 'f' => '仜', 'g' => '仩', 'h' => '仡', 'i' => '仝', 'j' => '仚', 'k' => '刌', 'l' => '匜', 'm' => '卌', 'n' => '圢', 'o' => '圣', 'p' => '夗', 'q' => '夯', 'r' => '宁', 's' => '宄', 't' => '尒', 'u' => '尻', 'v' => '屴', 'w' => '屳', 'x' => '帄', 'y' => '庀', 'z' => '庂', '{' => '忉', '|' => '戉', '}' => '扐', '~' => '氕', 'ɡ' => '氶', 'ɢ' => '汃', 'ɣ' => '氿', 'ɤ' => '氻', 'ɥ' => '犮', 'ɦ' => '犰', 'ɧ' => '玊', 'ɨ' => '禸', 'ɩ' => '肊', 'ɪ' => '阞', 'ɫ' => '伎', 'ɬ' => '优', 'ɭ' => '伬', 'ɮ' => '仵', 'ɯ' => '伔', 'ɰ' => '仱', 'ɱ' => '伀', 'ɲ' => '价', 'ɳ' => '伈', 'ɴ' => '伝', 'ɵ' => '伂', 'ɶ' => '伅', 'ɷ' => '伢', 'ɸ' => '伓', 'ɹ' => '伄', 'ɺ' => '仴', 'ɻ' => '伒', 'ɼ' => '冱', 'ɽ' => '刓', 'ɾ' => '刉', 'ɿ' => '刐', '' => '劦', '' => '匢', '' => '匟', '' => '卍', '' => '厊', '' => '吇', '' => '囡', '' => '囟', '' => '圮', '' => '圪', '' => '圴', '' => '夼', '' => '妀', '' => '奼', '' => '妅', '' => '奻', '' => '奾', '' => '奷', '' => '奿', '' => '孖', '' => '尕', '' => '尥', '' => '屼', '' => '屺', '' => '屻', '' => '屾', '' => '巟', '' => '幵', '' => '庄', '' => '异', '' => '弚', '' => '彴', '' => '忕', '' => '忔', '' => '忏', '' => '扜', '' => '扞', '' => '扤', '' => '扡', '' => '扦', '' => '扢', '' => '扙', '' => '扠', '' => '扚', '' => '扥', '' => '旯', '' => '旮', '' => '朾', '' => '朹', '' => '朸', '' => '朻', '' => '机', '' => '朿', '' => '朼', '' => '朳', '' => '氘', '' => '汆', '' => '汒', '' => '汜', '' => '汏', '' => '汊', '' => '汔', '' => '汋', '@' => '汌', 'A' => '灱', 'B' => '牞', 'C' => '犴', 'D' => '犵', 'E' => '玎', 'F' => '甪', 'G' => '癿', 'H' => '穵', 'I' => '网', 'J' => '艸', 'K' => '艼', 'L' => '芀', 'M' => '艽', 'N' => '艿', 'O' => '虍', 'P' => '襾', 'Q' => '邙', 'R' => '邗', 'S' => '邘', 'T' => '邛', 'U' => '邔', 'V' => '阢', 'W' => '阤', 'X' => '阠', 'Y' => '阣', 'Z' => '佖', '[' => '伻', '\\' => '佢', ']' => '佉', '^' => '体', '_' => '佤', '`' => '伾', 'a' => '佧', 'b' => '佒', 'c' => '佟', 'd' => '佁', 'e' => '佘', 'f' => '伭', 'g' => '伳', 'h' => '伿', 'i' => '佡', 'j' => '冏', 'k' => '冹', 'l' => '刜', 'm' => '刞', 'n' => '刡', 'o' => '劭', 'p' => '劮', 'q' => '匉', 'r' => '卣', 's' => '卲', 't' => '厎', 'u' => '厏', 'v' => '吰', 'w' => '吷', 'x' => '吪', 'y' => '呔', 'z' => '呅', '{' => '吙', '|' => '吜', '}' => '吥', '~' => '吘', 'ʡ' => '吽', 'ʢ' => '呏', 'ʣ' => '呁', 'ʤ' => '吨', 'ʥ' => '吤', 'ʦ' => '呇', 'ʧ' => '囮', 'ʨ' => '囧', 'ʩ' => '囥', 'ʪ' => '坁', 'ʫ' => '坅', 'ʬ' => '坌', 'ʭ' => '坉', 'ʮ' => '坋', 'ʯ' => '坒', 'ʰ' => '夆', 'ʱ' => '奀', 'ʲ' => '妦', 'ʳ' => '妘', 'ʴ' => '妠', 'ʵ' => '妗', 'ʶ' => '妎', 'ʷ' => '妢', 'ʸ' => '妐', 'ʹ' => '妏', 'ʺ' => '妧', 'ʻ' => '妡', 'ʼ' => '宎', 'ʽ' => '宒', 'ʾ' => '尨', 'ʿ' => '尪', '' => '岍', '' => '岏', '' => '岈', '' => '岋', '' => '岉', '' => '岒', '' => '岊', '' => '岆', '' => '岓', '' => '岕', '' => '巠', '' => '帊', '' => '帎', '' => '庋', '' => '庉', '' => '庌', '' => '庈', '' => '庍', '' => '弅', '' => '弝', '' => '彸', '' => '彶', '' => '忒', '' => '忑', '' => '忐', '' => '忭', '' => '忨', '' => '忮', '' => '忳', '' => '忡', '' => '忤', '' => '忣', '' => '忺', '' => '忯', '' => '忷', '' => '忻', '' => '怀', '' => '忴', '' => '戺', '' => '抃', '' => '抌', '' => '抎', '' => '抏', '' => '抔', '' => '抇', '' => '扱', '' => '扻', '' => '扺', '' => '扰', '' => '抁', '' => '抈', '' => '扷', '' => '扽', '' => '扲', '' => '扴', '' => '攷', '' => '旰', '' => '旴', '' => '旳', '' => '旲', '' => '旵', '' => '杅', '' => '杇', '@' => '杙', 'A' => '杕', 'B' => '杌', 'C' => '杈', 'D' => '杝', 'E' => '杍', 'F' => '杚', 'G' => '杋', 'H' => '毐', 'I' => '氙', 'J' => '氚', 'K' => '汸', 'L' => '汧', 'M' => '汫', 'N' => '沄', 'O' => '沋', 'P' => '沏', 'Q' => '汱', 'R' => '汯', 'S' => '汩', 'T' => '沚', 'U' => '汭', 'V' => '沇', 'W' => '沕', 'X' => '沜', 'Y' => '汦', 'Z' => '汳', '[' => '汥', '\\' => '汻', ']' => '沎', '^' => '灴', '_' => '灺', '`' => '牣', 'a' => '犿', 'b' => '犽', 'c' => '狃', 'd' => '狆', 'e' => '狁', 'f' => '犺', 'g' => '狅', 'h' => '玕', 'i' => '玗', 'j' => '玓', 'k' => '玔', 'l' => '玒', 'm' => '町', 'n' => '甹', 'o' => '疔', 'p' => '疕', 'q' => '皁', 'r' => '礽', 's' => '耴', 't' => '肕', 'u' => '肙', 'v' => '肐', 'w' => '肒', 'x' => '肜', 'y' => '芐', 'z' => '芏', '{' => '芅', '|' => '芎', '}' => '芑', '~' => '芓', 'ˡ' => '芊', 'ˢ' => '芃', 'ˣ' => '芄', 'ˤ' => '豸', '˥' => '迉', '˦' => '辿', '˧' => '邟', '˨' => '邡', '˩' => '邥', '˪' => '邞', '˫' => '邧', 'ˬ' => '邠', '˭' => '阰', 'ˮ' => '阨', '˯' => '阯', '˰' => '阭', '˱' => '丳', '˲' => '侘', '˳' => '佼', '˴' => '侅', '˵' => '佽', '˶' => '侀', '˷' => '侇', '˸' => '佶', '˹' => '佴', '˺' => '侉', '˻' => '侄', '˼' => '佷', '˽' => '佌', '˾' => '侗', '˿' => '佪', '' => '侚', '' => '佹', '' => '侁', '' => '佸', '' => '侐', '' => '侜', '' => '侔', '' => '侞', '' => '侒', '' => '侂', '' => '侕', '' => '佫', '' => '佮', '' => '冞', '' => '冼', '' => '冾', '' => '刵', '' => '刲', '' => '刳', '' => '剆', '' => '刱', '' => '劼', '' => '匊', '' => '匋', '' => '匼', '' => '厒', '' => '厔', '' => '咇', '' => '呿', '' => '咁', '' => '咑', '' => '咂', '' => '咈', '' => '呫', '' => '呺', '' => '呾', '' => '呥', '' => '呬', '' => '呴', '' => '呦', '' => '咍', '' => '呯', '' => '呡', '' => '呠', '' => '咘', '' => '呣', '' => '呧', '' => '呤', '' => '囷', '' => '囹', '' => '坯', '' => '坲', '' => '坭', '' => '坫', '' => '坱', '' => '坰', '' => '坶', '' => '垀', '' => '坵', '' => '坻', '' => '坳', '' => '坴', '' => '坢', '@' => '坨', 'A' => '坽', 'B' => '夌', 'C' => '奅', 'D' => '妵', 'E' => '妺', 'F' => '姏', 'G' => '姎', 'H' => '妲', 'I' => '姌', 'J' => '姁', 'K' => '妶', 'L' => '妼', 'M' => '姃', 'N' => '姖', 'O' => '妱', 'P' => '妽', 'Q' => '姀', 'R' => '姈', 'S' => '妴', 'T' => '姇', 'U' => '孢', 'V' => '孥', 'W' => '宓', 'X' => '宕', 'Y' => '屄', 'Z' => '屇', '[' => '岮', '\\' => '岤', ']' => '岠', '^' => '岵', '_' => '岯', '`' => '岨', 'a' => '岬', 'b' => '岟', 'c' => '岣', 'd' => '岭', 'e' => '岢', 'f' => '岪', 'g' => '岧', 'h' => '岝', 'i' => '岥', 'j' => '岶', 'k' => '岰', 'l' => '岦', 'm' => '帗', 'n' => '帔', 'o' => '帙', 'p' => '弨', 'q' => '弢', 'r' => '弣', 's' => '弤', 't' => '彔', 'u' => '徂', 'v' => '彾', 'w' => '彽', 'x' => '忞', 'y' => '忥', 'z' => '怭', '{' => '怦', '|' => '怙', '}' => '怲', '~' => '怋', '̡' => '怴', '̢' => '怊', '̣' => '怗', '̤' => '怳', '̥' => '怚', '̦' => '怞', '̧' => '怬', '̨' => '怢', '̩' => '怍', '̪' => '怐', '̫' => '怮', '̬' => '怓', '̭' => '怑', '̮' => '怌', '̯' => '怉', '̰' => '怜', '̱' => '戔', '̲' => '戽', '̳' => '抭', '̴' => '抴', '̵' => '拑', '̶' => '抾', '̷' => '抪', '̸' => '抶', '̹' => '拊', '̺' => '抮', '̻' => '抳', '̼' => '抯', '̽' => '抻', '̾' => '抩', '̿' => '抰', '' => '抸', '' => '攽', '' => '斨', '' => '斻', '' => '昉', '' => '旼', '' => '昄', '' => '昒', '' => '昈', '' => '旻', '' => '昃', '' => '昋', '' => '昍', '' => '昅', '' => '旽', '' => '昑', '' => '昐', '' => '曶', '' => '朊', '' => '枅', '' => '杬', '' => '枎', '' => '枒', '' => '杶', '' => '杻', '' => '枘', '' => '枆', '' => '构', '' => '杴', '' => '枍', '' => '枌', '' => '杺', '' => '枟', '' => '枑', '' => '枙', '' => '枃', '' => '杽', '' => '极', '' => '杸', '' => '杹', '' => '枔', '' => '欥', '' => '殀', '' => '歾', '' => '毞', '' => '氝', '' => '沓', '' => '泬', '' => '泫', '' => '泮', '' => '泙', '' => '沶', '' => '泔', '' => '沭', '' => '泧', '' => '沷', '' => '泐', '' => '泂', '' => '沺', '' => '泃', '' => '泆', '' => '泭', '' => '泲', '@' => '泒', 'A' => '泝', 'B' => '沴', 'C' => '沊', 'D' => '沝', 'E' => '沀', 'F' => '泞', 'G' => '泀', 'H' => '洰', 'I' => '泍', 'J' => '泇', 'K' => '沰', 'L' => '泹', 'M' => '泏', 'N' => '泩', 'O' => '泑', 'P' => '炔', 'Q' => '炘', 'R' => '炅', 'S' => '炓', 'T' => '炆', 'U' => '炄', 'V' => '炑', 'W' => '炖', 'X' => '炂', 'Y' => '炚', 'Z' => '炃', '[' => '牪', '\\' => '狖', ']' => '狋', '^' => '狘', '_' => '狉', '`' => '狜', 'a' => '狒', 'b' => '狔', 'c' => '狚', 'd' => '狌', 'e' => '狑', 'f' => '玤', 'g' => '玡', 'h' => '玭', 'i' => '玦', 'j' => '玢', 'k' => '玠', 'l' => '玬', 'm' => '玝', 'n' => '瓝', 'o' => '瓨', 'p' => '甿', 'q' => '畀', 'r' => '甾', 's' => '疌', 't' => '疘', 'u' => '皯', 'v' => '盳', 'w' => '盱', 'x' => '盰', 'y' => '盵', 'z' => '矸', '{' => '矼', '|' => '矹', '}' => '矻', '~' => '矺', '͡' => '矷', '͢' => '祂', 'ͣ' => '礿', 'ͤ' => '秅', 'ͥ' => '穸', 'ͦ' => '穻', 'ͧ' => '竻', 'ͨ' => '籵', 'ͩ' => '糽', 'ͪ' => '耵', 'ͫ' => '肏', 'ͬ' => '肮', 'ͭ' => '肣', 'ͮ' => '肸', 'ͯ' => '肵', 'Ͱ' => '肭', 'ͱ' => '舠', 'Ͳ' => '芠', 'ͳ' => '苀', 'ʹ' => '芫', '͵' => '芚', 'Ͷ' => '芘', 'ͷ' => '芛', '͸' => '芵', '͹' => '芧', 'ͺ' => '芮', 'ͻ' => '芼', 'ͼ' => '芞', 'ͽ' => '芺', ';' => '芴', 'Ϳ' => '芨', '' => '芡', '' => '芩', '' => '苂', '' => '芤', '' => '苃', '' => '芶', '' => '芢', '' => '虰', '' => '虯', '' => '虭', '' => '虮', '' => '豖', '' => '迒', '' => '迋', '' => '迓', '' => '迍', '' => '迖', '' => '迕', '' => '迗', '' => '邲', '' => '邴', '' => '邯', '' => '邳', '' => '邰', '' => '阹', '' => '阽', '' => '阼', '' => '阺', '' => '陃', '' => '俍', '' => '俅', '' => '俓', '' => '侲', '' => '俉', '' => '俋', '' => '俁', '' => '俔', '' => '俜', '' => '俙', '' => '侻', '' => '侳', '' => '俛', '' => '俇', '' => '俖', '' => '侺', '' => '俀', '' => '侹', '' => '俬', '' => '剄', '' => '剉', '' => '勀', '' => '勂', '' => '匽', '' => '卼', '' => '厗', '' => '厖', '' => '厙', '' => '厘', '' => '咺', '' => '咡', '' => '咭', '' => '咥', '' => '哏', '@' => '哃', 'A' => '茍', 'B' => '咷', 'C' => '咮', 'D' => '哖', 'E' => '咶', 'F' => '哅', 'G' => '哆', 'H' => '咠', 'I' => '呰', 'J' => '咼', 'K' => '咢', 'L' => '咾', 'M' => '呲', 'N' => '哞', 'O' => '咰', 'P' => '垵', 'Q' => '垞', 'R' => '垟', 'S' => '垤', 'T' => '垌', 'U' => '垗', 'V' => '垝', 'W' => '垛', 'X' => '垔', 'Y' => '垘', 'Z' => '垏', '[' => '垙', '\\' => '垥', ']' => '垚', '^' => '垕', '_' => '壴', '`' => '复', 'a' => '奓', 'b' => '姡', 'c' => '姞', 'd' => '姮', 'e' => '娀', 'f' => '姱', 'g' => '姝', 'h' => '姺', 'i' => '姽', 'j' => '姼', 'k' => '姶', 'l' => '姤', 'm' => '姲', 'n' => '姷', 'o' => '姛', 'p' => '姩', 'q' => '姳', 'r' => '姵', 's' => '姠', 't' => '姾', 'u' => '姴', 'v' => '姭', 'w' => '宨', 'x' => '屌', 'y' => '峐', 'z' => '峘', '{' => '峌', '|' => '峗', '}' => '峋', '~' => '峛', 'Ρ' => '峞', '΢' => '峚', 'Σ' => '峉', 'Τ' => '峇', 'Υ' => '峊', 'Φ' => '峖', 'Χ' => '峓', 'Ψ' => '峔', 'Ω' => '峏', 'Ϊ' => '峈', 'Ϋ' => '峆', 'ά' => '峎', 'έ' => '峟', 'ή' => '峸', 'ί' => '巹', 'ΰ' => '帡', 'α' => '帢', 'β' => '帣', 'γ' => '帠', 'δ' => '帤', 'ε' => '庰', 'ζ' => '庤', 'η' => '庢', 'θ' => '庛', 'ι' => '庣', 'κ' => '庥', 'λ' => '弇', 'μ' => '弮', 'ν' => '彖', 'ξ' => '徆', 'ο' => '怷', '' => '怹', '' => '恔', '' => '恲', '' => '恞', '' => '恅', '' => '恓', '' => '恇', '' => '恉', '' => '恛', '' => '恌', '' => '恀', '' => '恂', '' => '恟', '' => '怤', '' => '恄', '' => '恘', '' => '恦', '' => '恮', '' => '扂', '' => '扃', '' => '拏', '' => '挍', '' => '挋', '' => '拵', '' => '挎', '' => '挃', '' => '拫', '' => '拹', '' => '挏', '' => '挌', '' => '拸', '' => '拶', '' => '挀', '' => '挓', '' => '挔', '' => '拺', '' => '挕', '' => '拻', '' => '拰', '' => '敁', '' => '敃', '' => '斪', '' => '斿', '' => '昶', '' => '昡', '' => '昲', '' => '昵', '' => '昜', '' => '昦', '' => '昢', '' => '昳', '' => '昫', '' => '昺', '' => '昝', '' => '昴', '' => '昹', '' => '昮', '' => '朏', '' => '朐', '' => '柁', '' => '柲', '' => '柈', '' => '枺', '@' => '柜', 'A' => '枻', 'B' => '柸', 'C' => '柘', 'D' => '柀', 'E' => '枷', 'F' => '柅', 'G' => '柫', 'H' => '柤', 'I' => '柟', 'J' => '枵', 'K' => '柍', 'L' => '枳', 'M' => '柷', 'N' => '柶', 'O' => '柮', 'P' => '柣', 'Q' => '柂', 'R' => '枹', 'S' => '柎', 'T' => '柧', 'U' => '柰', 'V' => '枲', 'W' => '柼', 'X' => '柆', 'Y' => '柭', 'Z' => '柌', '[' => '枮', '\\' => '柦', ']' => '柛', '^' => '柺', '_' => '柉', '`' => '柊', 'a' => '柃', 'b' => '柪', 'c' => '柋', 'd' => '欨', 'e' => '殂', 'f' => '殄', 'g' => '殶', 'h' => '毖', 'i' => '毘', 'j' => '毠', 'k' => '氠', 'l' => '氡', 'm' => '洨', 'n' => '洴', 'o' => '洭', 'p' => '洟', 'q' => '洼', 'r' => '洿', 's' => '洒', 't' => '洊', 'u' => '泚', 'v' => '洳', 'w' => '洄', 'x' => '洙', 'y' => '洺', 'z' => '洚', '{' => '洑', '|' => '洀', '}' => '洝', '~' => '浂', 'ϡ' => '洁', 'Ϣ' => '洘', 'ϣ' => '洷', 'Ϥ' => '洃', 'ϥ' => '洏', 'Ϧ' => '浀', 'ϧ' => '洇', 'Ϩ' => '洠', 'ϩ' => '洬', 'Ϫ' => '洈', 'ϫ' => '洢', 'Ϭ' => '洉', 'ϭ' => '洐', 'Ϯ' => '炷', 'ϯ' => '炟', 'ϰ' => '炾', 'ϱ' => '炱', 'ϲ' => '炰', 'ϳ' => '炡', 'ϴ' => '炴', 'ϵ' => '炵', '϶' => '炩', 'Ϸ' => '牁', 'ϸ' => '牉', 'Ϲ' => '牊', 'Ϻ' => '牬', 'ϻ' => '牰', 'ϼ' => '牳', 'Ͻ' => '牮', 'Ͼ' => '狊', 'Ͽ' => '狤', '' => '狨', '' => '狫', '' => '狟', '' => '狪', '' => '狦', '' => '狣', '' => '玅', '' => '珌', '' => '珂', '' => '珈', '' => '珅', '' => '玹', '' => '玶', '' => '玵', '' => '玴', '' => '珫', '' => '玿', '' => '珇', '' => '玾', '' => '珃', '' => '珆', '' => '玸', '' => '珋', '' => '瓬', '' => '瓮', '' => '甮', '' => '畇', '' => '畈', '' => '疧', '' => '疪', '' => '癹', '' => '盄', '' => '眈', '' => '眃', '' => '眄', '' => '眅', '' => '眊', '' => '盷', '' => '盻', '' => '盺', '' => '矧', '' => '矨', '' => '砆', '' => '砑', '' => '砒', '' => '砅', '' => '砐', '' => '砏', '' => '砎', '' => '砉', '' => '砃', '' => '砓', '' => '祊', '' => '祌', '' => '祋', '' => '祅', '' => '祄', '' => '秕', '' => '种', '' => '秏', '' => '秖', '' => '秎', '' => '窀', '@' => '穾', 'A' => '竑', 'B' => '笀', 'C' => '笁', 'D' => '籺', 'E' => '籸', 'F' => '籹', 'G' => '籿', 'H' => '粀', 'I' => '粁', 'J' => '紃', 'K' => '紈', 'L' => '紁', 'M' => '罘', 'N' => '羑', 'O' => '羍', 'P' => '羾', 'Q' => '耇', 'R' => '耎', 'S' => '耏', 'T' => '耔', 'U' => '耷', 'V' => '胘', 'W' => '胇', 'X' => '胠', 'Y' => '胑', 'Z' => '胈', '[' => '胂', '\\' => '胐', ']' => '胅', '^' => '胣', '_' => '胙', '`' => '胜', 'a' => '胊', 'b' => '胕', 'c' => '胉', 'd' => '胏', 'e' => '胗', 'f' => '胦', 'g' => '胍', 'h' => '臿', 'i' => '舡', 'j' => '芔', 'k' => '苙', 'l' => '苾', 'm' => '苹', 'n' => '茇', 'o' => '苨', 'p' => '茀', 'q' => '苕', 'r' => '茺', 's' => '苫', 't' => '苖', 'u' => '苴', 'v' => '苬', 'w' => '苡', 'x' => '苲', 'y' => '苵', 'z' => '茌', '{' => '苻', '|' => '苶', '}' => '苰', '~' => '苪', 'С' => '苤', 'Т' => '苠', 'У' => '苺', 'Ф' => '苳', 'Х' => '苭', 'Ц' => '虷', 'Ч' => '虴', 'Ш' => '虼', 'Щ' => '虳', 'Ъ' => '衁', 'Ы' => '衎', 'Ь' => '衧', 'Э' => '衪', 'Ю' => '衩', 'Я' => '觓', 'а' => '訄', 'б' => '訇', 'в' => '赲', 'г' => '迣', 'д' => '迡', 'е' => '迮', 'ж' => '迠', 'з' => '郱', 'и' => '邽', 'й' => '邿', 'к' => '郕', 'л' => '郅', 'м' => '邾', 'н' => '郇', 'о' => '郋', 'п' => '郈', '' => '釔', '' => '釓', '' => '陔', '' => '陏', '' => '陑', '' => '陓', '' => '陊', '' => '陎', '' => '倞', '' => '倅', '' => '倇', '' => '倓', '' => '倢', '' => '倰', '' => '倛', '' => '俵', '' => '俴', '' => '倳', '' => '倷', '' => '倬', '' => '俶', '' => '俷', '' => '倗', '' => '倜', '' => '倠', '' => '倧', '' => '倵', '' => '倯', '' => '倱', '' => '倎', '' => '党', '' => '冔', '' => '冓', '' => '凊', '' => '凄', '' => '凅', '' => '凈', '' => '凎', '' => '剡', '' => '剚', '' => '剒', '' => '剞', '' => '剟', '' => '剕', '' => '剢', '' => '勍', '' => '匎', '' => '厞', '' => '唦', '' => '哢', '' => '唗', '' => '唒', '' => '哧', '' => '哳', '' => '哤', '' => '唚', '' => '哿', '' => '唄', '' => '唈', '' => '哫', '' => '唑', '' => '唅', '' => '哱', '@' => '唊', 'A' => '哻', 'B' => '哷', 'C' => '哸', 'D' => '哠', 'E' => '唎', 'F' => '唃', 'G' => '唋', 'H' => '圁', 'I' => '圂', 'J' => '埌', 'K' => '堲', 'L' => '埕', 'M' => '埒', 'N' => '垺', 'O' => '埆', 'P' => '垽', 'Q' => '垼', 'R' => '垸', 'S' => '垶', 'T' => '垿', 'U' => '埇', 'V' => '埐', 'W' => '垹', 'X' => '埁', 'Y' => '夎', 'Z' => '奊', '[' => '娙', '\\' => '娖', ']' => '娭', '^' => '娮', '_' => '娕', '`' => '娏', 'a' => '娗', 'b' => '娊', 'c' => '娞', 'd' => '娳', 'e' => '孬', 'f' => '宧', 'g' => '宭', 'h' => '宬', 'i' => '尃', 'j' => '屖', 'k' => '屔', 'l' => '峬', 'm' => '峿', 'n' => '峮', 'o' => '峱', 'p' => '峷', 'q' => '崀', 'r' => '峹', 's' => '帩', 't' => '帨', 'u' => '庨', 'v' => '庮', 'w' => '庪', 'x' => '庬', 'y' => '弳', 'z' => '弰', '{' => '彧', '|' => '恝', '}' => '恚', '~' => '恧', 'ѡ' => '恁', 'Ѣ' => '悢', 'ѣ' => '悈', 'Ѥ' => '悀', 'ѥ' => '悒', 'Ѧ' => '悁', 'ѧ' => '悝', 'Ѩ' => '悃', 'ѩ' => '悕', 'Ѫ' => '悛', 'ѫ' => '悗', 'Ѭ' => '悇', 'ѭ' => '悜', 'Ѯ' => '悎', 'ѯ' => '戙', 'Ѱ' => '扆', 'ѱ' => '拲', 'Ѳ' => '挐', 'ѳ' => '捖', 'Ѵ' => '挬', 'ѵ' => '捄', 'Ѷ' => '捅', 'ѷ' => '挶', 'Ѹ' => '捃', 'ѹ' => '揤', 'Ѻ' => '挹', 'ѻ' => '捋', 'Ѽ' => '捊', 'ѽ' => '挼', 'Ѿ' => '挩', 'ѿ' => '捁', '' => '挴', '' => '捘', '' => '捔', '' => '捙', '' => '挭', '' => '捇', '' => '挳', '' => '捚', '' => '捑', '' => '挸', '' => '捗', '' => '捀', '' => '捈', '' => '敊', '' => '敆', '' => '旆', '' => '旃', '' => '旄', '' => '旂', '' => '晊', '' => '晟', '' => '晇', '' => '晑', '' => '朒', '' => '朓', '' => '栟', '' => '栚', '' => '桉', '' => '栲', '' => '栳', '' => '栻', '' => '桋', '' => '桏', '' => '栖', '' => '栱', '' => '栜', '' => '栵', '' => '栫', '' => '栭', '' => '栯', '' => '桎', '' => '桄', '' => '栴', '' => '栝', '' => '栒', '' => '栔', '' => '栦', '' => '栨', '' => '栮', '' => '桍', '' => '栺', '' => '栥', '' => '栠', '' => '欬', '' => '欯', '' => '欭', '' => '欱', '' => '欴', '' => '歭', '' => '肂', '' => '殈', '' => '毦', '' => '毤', '@' => '毨', 'A' => '毣', 'B' => '毢', 'C' => '毧', 'D' => '氥', 'E' => '浺', 'F' => '浣', 'G' => '浤', 'H' => '浶', 'I' => '洍', 'J' => '浡', 'K' => '涒', 'L' => '浘', 'M' => '浢', 'N' => '浭', 'O' => '浯', 'P' => '涑', 'Q' => '涍', 'R' => '淯', 'S' => '浿', 'T' => '涆', 'U' => '浞', 'V' => '浧', 'W' => '浠', 'X' => '涗', 'Y' => '浰', 'Z' => '浼', '[' => '浟', '\\' => '涂', ']' => '涘', '^' => '洯', '_' => '浨', '`' => '涋', 'a' => '浾', 'b' => '涀', 'c' => '涄', 'd' => '洖', 'e' => '涃', 'f' => '浻', 'g' => '浽', 'h' => '浵', 'i' => '涐', 'j' => '烜', 'k' => '烓', 'l' => '烑', 'm' => '烝', 'n' => '烋', 'o' => '缹', 'p' => '烢', 'q' => '烗', 'r' => '烒', 's' => '烞', 't' => '烠', 'u' => '烔', 'v' => '烍', 'w' => '烅', 'x' => '烆', 'y' => '烇', 'z' => '烚', '{' => '烎', '|' => '烡', '}' => '牂', '~' => '牸', 'ҡ' => '牷', 'Ң' => '牶', 'ң' => '猀', 'Ҥ' => '狺', 'ҥ' => '狴', 'Ҧ' => '狾', 'ҧ' => '狶', 'Ҩ' => '狳', 'ҩ' => '狻', 'Ҫ' => '猁', 'ҫ' => '珓', 'Ҭ' => '珙', 'ҭ' => '珥', 'Ү' => '珖', 'ү' => '玼', 'Ұ' => '珧', 'ұ' => '珣', 'Ҳ' => '珩', 'ҳ' => '珜', 'Ҵ' => '珒', 'ҵ' => '珛', 'Ҷ' => '珔', 'ҷ' => '珝', 'Ҹ' => '珚', 'ҹ' => '珗', 'Һ' => '珘', 'һ' => '珨', 'Ҽ' => '瓞', 'ҽ' => '瓟', 'Ҿ' => '瓴', 'ҿ' => '瓵', '' => '甡', '' => '畛', '' => '畟', '' => '疰', '' => '痁', '' => '疻', '' => '痄', '' => '痀', '' => '疿', '' => '疶', '' => '疺', '' => '皊', '' => '盉', '' => '眝', '' => '眛', '' => '眐', '' => '眓', '' => '眒', '' => '眣', '' => '眑', '' => '眕', '' => '眙', '' => '眚', '' => '眢', '' => '眧', '' => '砣', '' => '砬', '' => '砢', '' => '砵', '' => '砯', '' => '砨', '' => '砮', '' => '砫', '' => '砡', '' => '砩', '' => '砳', '' => '砪', '' => '砱', '' => '祔', '' => '祛', '' => '祏', '' => '祜', '' => '祓', '' => '祒', '' => '祑', '' => '秫', '' => '秬', '' => '秠', '' => '秮', '' => '秭', '' => '秪', '' => '秜', '' => '秞', '' => '秝', '' => '窆', '' => '窉', '' => '窅', '' => '窋', '' => '窌', '' => '窊', '' => '窇', '' => '竘', '' => '笐', '@' => '笄', 'A' => '笓', 'B' => '笅', 'C' => '笏', 'D' => '笈', 'E' => '笊', 'F' => '笎', 'G' => '笉', 'H' => '笒', 'I' => '粄', 'J' => '粑', 'K' => '粊', 'L' => '粌', 'M' => '粈', 'N' => '粍', 'O' => '粅', 'P' => '紞', 'Q' => '紝', 'R' => '紑', 'S' => '紎', 'T' => '紘', 'U' => '紖', 'V' => '紓', 'W' => '紟', 'X' => '紒', 'Y' => '紏', 'Z' => '紌', '[' => '罜', '\\' => '罡', ']' => '罞', '^' => '罠', '_' => '罝', '`' => '罛', 'a' => '羖', 'b' => '羒', 'c' => '翃', 'd' => '翂', 'e' => '翀', 'f' => '耖', 'g' => '耾', 'h' => '耹', 'i' => '胺', 'j' => '胲', 'k' => '胹', 'l' => '胵', 'm' => '脁', 'n' => '胻', 'o' => '脀', 'p' => '舁', 'q' => '舯', 'r' => '舥', 's' => '茳', 't' => '茭', 'u' => '荄', 'v' => '茙', 'w' => '荑', 'x' => '茥', 'y' => '荖', 'z' => '茿', '{' => '荁', '|' => '茦', '}' => '茜', '~' => '茢', 'ӡ' => '荂', 'Ӣ' => '荎', 'ӣ' => '茛', 'Ӥ' => '茪', 'ӥ' => '茈', 'Ӧ' => '茼', 'ӧ' => '荍', 'Ө' => '茖', 'ө' => '茤', 'Ӫ' => '茠', 'ӫ' => '茷', 'Ӭ' => '茯', 'ӭ' => '茩', 'Ӯ' => '荇', 'ӯ' => '荅', 'Ӱ' => '荌', 'ӱ' => '荓', 'Ӳ' => '茞', 'ӳ' => '茬', 'Ӵ' => '荋', 'ӵ' => '茧', 'Ӷ' => '荈', 'ӷ' => '虓', 'Ӹ' => '虒', 'ӹ' => '蚢', 'Ӻ' => '蚨', 'ӻ' => '蚖', 'Ӽ' => '蚍', 'ӽ' => '蚑', 'Ӿ' => '蚞', 'ӿ' => '蚇', '' => '蚗', '' => '蚆', '' => '蚋', '' => '蚚', '' => '蚅', '' => '蚥', '' => '蚙', '' => '蚡', '' => '蚧', '' => '蚕', '' => '蚘', '' => '蚎', '' => '蚝', '' => '蚐', '' => '蚔', '' => '衃', '' => '衄', '' => '衭', '' => '衵', '' => '衶', '' => '衲', '' => '袀', '' => '衱', '' => '衿', '' => '衯', '' => '袃', '' => '衾', '' => '衴', '' => '衼', '' => '訒', '' => '豇', '' => '豗', '' => '豻', '' => '貤', '' => '貣', '' => '赶', '' => '赸', '' => '趵', '' => '趷', '' => '趶', '' => '軑', '' => '軓', '' => '迾', '' => '迵', '' => '适', '' => '迿', '' => '迻', '' => '逄', '' => '迼', '' => '迶', '' => '郖', '' => '郠', '' => '郙', '' => '郚', '' => '郣', '' => '郟', '' => '郥', '' => '郘', '' => '郛', '' => '郗', '' => '郜', '' => '郤', '' => '酐', '@' => '酎', 'A' => '酏', 'B' => '釕', 'C' => '釢', 'D' => '釚', 'E' => '陜', 'F' => '陟', 'G' => '隼', 'H' => '飣', 'I' => '髟', 'J' => '鬯', 'K' => '乿', 'L' => '偰', 'M' => '偪', 'N' => '偡', 'O' => '偞', 'P' => '偠', 'Q' => '偓', 'R' => '偋', 'S' => '偝', 'T' => '偲', 'U' => '偈', 'V' => '偍', 'W' => '偁', 'X' => '偛', 'Y' => '偊', 'Z' => '偢', '[' => '倕', '\\' => '偅', ']' => '偟', '^' => '偩', '_' => '偫', '`' => '偣', 'a' => '偤', 'b' => '偆', 'c' => '偀', 'd' => '偮', 'e' => '偳', 'f' => '偗', 'g' => '偑', 'h' => '凐', 'i' => '剫', 'j' => '剭', 'k' => '剬', 'l' => '剮', 'm' => '勖', 'n' => '勓', 'o' => '匭', 'p' => '厜', 'q' => '啵', 'r' => '啶', 's' => '唼', 't' => '啍', 'u' => '啐', 'v' => '唴', 'w' => '唪', 'x' => '啑', 'y' => '啢', 'z' => '唶', '{' => '唵', '|' => '唰', '}' => '啒', '~' => '啅', 'ԡ' => '唌', 'Ԣ' => '唲', 'ԣ' => '啥', 'Ԥ' => '啎', 'ԥ' => '唹', 'Ԧ' => '啈', 'ԧ' => '唭', 'Ԩ' => '唻', 'ԩ' => '啀', 'Ԫ' => '啋', 'ԫ' => '圊', 'Ԭ' => '圇', 'ԭ' => '埻', 'Ԯ' => '堔', 'ԯ' => '埢', '԰' => '埶', 'Ա' => '埜', 'Բ' => '埴', 'Գ' => '堀', 'Դ' => '埭', 'Ե' => '埽', 'Զ' => '堈', 'Է' => '埸', 'Ը' => '堋', 'Թ' => '埳', 'Ժ' => '埏', 'Ի' => '堇', 'Լ' => '埮', 'Խ' => '埣', 'Ծ' => '埲', 'Կ' => '埥', '' => '埬', '' => '埡', '' => '堎', '' => '埼', '' => '堐', '' => '埧', '' => '堁', '' => '堌', '' => '埱', '' => '埩', '' => '埰', '' => '堍', '' => '堄', '' => '奜', '' => '婠', '' => '婘', '' => '婕', '' => '婧', '' => '婞', '' => '娸', '' => '娵', '' => '婭', '' => '婐', '' => '婟', '' => '婥', '' => '婬', '' => '婓', '' => '婤', '' => '婗', '' => '婃', '' => '婝', '' => '婒', '' => '婄', '' => '婛', '' => '婈', '' => '媎', '' => '娾', '' => '婍', '' => '娹', '' => '婌', '' => '婰', '' => '婩', '' => '婇', '' => '婑', '' => '婖', '' => '婂', '' => '婜', '' => '孲', '' => '孮', '' => '寁', '' => '寀', '' => '屙', '' => '崞', '' => '崋', '' => '崝', '' => '崚', '' => '崠', '' => '崌', '' => '崨', '' => '崍', '' => '崦', '' => '崥', '' => '崏', '@' => '崰', 'A' => '崒', 'B' => '崣', 'C' => '崟', 'D' => '崮', 'E' => '帾', 'F' => '帴', 'G' => '庱', 'H' => '庴', 'I' => '庹', 'J' => '庲', 'K' => '庳', 'L' => '弶', 'M' => '弸', 'N' => '徛', 'O' => '徖', 'P' => '徟', 'Q' => '悊', 'R' => '悐', 'S' => '悆', 'T' => '悾', 'U' => '悰', 'V' => '悺', 'W' => '惓', 'X' => '惔', 'Y' => '惏', 'Z' => '惤', '[' => '惙', '\\' => '惝', ']' => '惈', '^' => '悱', '_' => '惛', '`' => '悷', 'a' => '惊', 'b' => '悿', 'c' => '惃', 'd' => '惍', 'e' => '惀', 'f' => '挲', 'g' => '捥', 'h' => '掊', 'i' => '掂', 'j' => '捽', 'k' => '掽', 'l' => '掞', 'm' => '掭', 'n' => '掝', 'o' => '掗', 'p' => '掫', 'q' => '掎', 'r' => '捯', 's' => '掇', 't' => '掐', 'u' => '据', 'v' => '掯', 'w' => '捵', 'x' => '掜', 'y' => '捭', 'z' => '掮', '{' => '捼', '|' => '掤', '}' => '挻', '~' => '掟', 'ա' => '捸', 'բ' => '掅', 'գ' => '掁', 'դ' => '掑', 'ե' => '掍', 'զ' => '捰', 'է' => '敓', 'ը' => '旍', 'թ' => '晥', 'ժ' => '晡', 'ի' => '晛', 'լ' => '晙', 'խ' => '晜', 'ծ' => '晢', 'կ' => '朘', 'հ' => '桹', 'ձ' => '梇', 'ղ' => '梐', 'ճ' => '梜', 'մ' => '桭', 'յ' => '桮', 'ն' => '梮', 'շ' => '梫', 'ո' => '楖', 'չ' => '桯', 'պ' => '梣', 'ջ' => '梬', 'ռ' => '梩', 'ս' => '桵', 'վ' => '桴', 'տ' => '梲', '' => '梏', '' => '桷', '' => '梒', '' => '桼', '' => '桫', '' => '桲', '' => '梪', '' => '梀', '' => '桱', '' => '桾', '' => '梛', '' => '梖', '' => '梋', '' => '梠', '' => '梉', '' => '梤', '' => '桸', '' => '桻', '' => '梑', '' => '梌', '' => '梊', '' => '桽', '' => '欶', '' => '欳', '' => '欷', '' => '欸', '' => '殑', '' => '殏', '' => '殍', '' => '殎', '' => '殌', '' => '氪', '' => '淀', '' => '涫', '' => '涴', '' => '涳', '' => '湴', '' => '涬', '' => '淩', '' => '淢', '' => '涷', '' => '淶', '' => '淔', '' => '渀', '' => '淈', '' => '淠', '' => '淟', '' => '淖', '' => '涾', '' => '淥', '' => '淜', '' => '淝', '' => '淛', '' => '淴', '' => '淊', '' => '涽', '' => '淭', '' => '淰', '' => '涺', '' => '淕', '' => '淂', '' => '淏', '' => '淉', '@' => '淐', 'A' => '淲', 'B' => '淓', 'C' => '淽', 'D' => '淗', 'E' => '淍', 'F' => '淣', 'G' => '涻', 'H' => '烺', 'I' => '焍', 'J' => '烷', 'K' => '焗', 'L' => '烴', 'M' => '焌', 'N' => '烰', 'O' => '焄', 'P' => '烳', 'Q' => '焐', 'R' => '烼', 'S' => '烿', 'T' => '焆', 'U' => '焓', 'V' => '焀', 'W' => '烸', 'X' => '烶', 'Y' => '焋', 'Z' => '焂', '[' => '焎', '\\' => '牾', ']' => '牻', '^' => '牼', '_' => '牿', '`' => '猝', 'a' => '猗', 'b' => '猇', 'c' => '猑', 'd' => '猘', 'e' => '猊', 'f' => '猈', 'g' => '狿', 'h' => '猏', 'i' => '猞', 'j' => '玈', 'k' => '珶', 'l' => '珸', 'm' => '珵', 'n' => '琄', 'o' => '琁', 'p' => '珽', 'q' => '琇', 'r' => '琀', 's' => '珺', 't' => '珼', 'u' => '珿', 'v' => '琌', 'w' => '琋', 'x' => '珴', 'y' => '琈', 'z' => '畤', '{' => '畣', '|' => '痎', '}' => '痒', '~' => '痏', '֡' => '痋', '֢' => '痌', '֣' => '痑', '֤' => '痐', '֥' => '皏', '֦' => '皉', '֧' => '盓', '֨' => '眹', '֩' => '眯', '֪' => '眭', '֫' => '眱', '֬' => '眲', '֭' => '眴', '֮' => '眳', '֯' => '眽', 'ְ' => '眥', 'ֱ' => '眻', 'ֲ' => '眵', 'ֳ' => '硈', 'ִ' => '硒', 'ֵ' => '硉', 'ֶ' => '硍', 'ַ' => '硊', 'ָ' => '硌', 'ֹ' => '砦', 'ֺ' => '硅', 'ֻ' => '硐', 'ּ' => '祤', 'ֽ' => '祧', '־' => '祩', 'ֿ' => '祪', '' => '祣', '' => '祫', '' => '祡', '' => '离', '' => '秺', '' => '秸', '' => '秶', '' => '秷', '' => '窏', '' => '窔', '' => '窐', '' => '笵', '' => '筇', '' => '笴', '' => '笥', '' => '笰', '' => '笢', '' => '笤', '' => '笳', '' => '笘', '' => '笪', '' => '笝', '' => '笱', '' => '笫', '' => '笭', '' => '笯', '' => '笲', '' => '笸', '' => '笚', '' => '笣', '' => '粔', '' => '粘', '' => '粖', '' => '粣', '' => '紵', '' => '紽', '' => '紸', '' => '紶', '' => '紺', '' => '絅', '' => '紬', '' => '紩', '' => '絁', '' => '絇', '' => '紾', '' => '紿', '' => '絊', '' => '紻', '' => '紨', '' => '罣', '' => '羕', '' => '羜', '' => '羝', '' => '羛', '' => '翊', '' => '翋', '' => '翍', '' => '翐', '' => '翑', '' => '翇', '' => '翏', '' => '翉', '' => '耟', '@' => '耞', 'A' => '耛', 'B' => '聇', 'C' => '聃', 'D' => '聈', 'E' => '脘', 'F' => '脥', 'G' => '脙', 'H' => '脛', 'I' => '脭', 'J' => '脟', 'K' => '脬', 'L' => '脞', 'M' => '脡', 'N' => '脕', 'O' => '脧', 'P' => '脝', 'Q' => '脢', 'R' => '舑', 'S' => '舸', 'T' => '舳', 'U' => '舺', 'V' => '舴', 'W' => '舲', 'X' => '艴', 'Y' => '莐', 'Z' => '莣', '[' => '莨', '\\' => '莍', ']' => '荺', '^' => '荳', '_' => '莤', '`' => '荴', 'a' => '莏', 'b' => '莁', 'c' => '莕', 'd' => '莙', 'e' => '荵', 'f' => '莔', 'g' => '莩', 'h' => '荽', 'i' => '莃', 'j' => '莌', 'k' => '莝', 'l' => '莛', 'm' => '莪', 'n' => '莋', 'o' => '荾', 'p' => '莥', 'q' => '莯', 'r' => '莈', 's' => '莗', 't' => '莰', 'u' => '荿', 'v' => '莦', 'w' => '莇', 'x' => '莮', 'y' => '荶', 'z' => '莚', '{' => '虙', '|' => '虖', '}' => '蚿', '~' => '蚷', 'ס' => '蛂', 'ע' => '蛁', 'ף' => '蛅', 'פ' => '蚺', 'ץ' => '蚰', 'צ' => '蛈', 'ק' => '蚹', 'ר' => '蚳', 'ש' => '蚸', 'ת' => '蛌', '׫' => '蚴', '׬' => '蚻', '׭' => '蚼', '׮' => '蛃', 'ׯ' => '蚽', 'װ' => '蚾', 'ױ' => '衒', 'ײ' => '袉', '׳' => '袕', '״' => '袨', '׵' => '袢', '׶' => '袪', '׷' => '袚', '׸' => '袑', '׹' => '袡', '׺' => '袟', '׻' => '袘', '׼' => '袧', '׽' => '袙', '׾' => '袛', '׿' => '袗', '' => '袤', '' => '袬', '' => '袌', '' => '袓', '' => '袎', '' => '覂', '' => '觖', '' => '觙', '' => '觕', '' => '訰', '' => '訧', '' => '訬', '' => '訞', '' => '谹', '' => '谻', '' => '豜', '' => '豝', '' => '豽', '' => '貥', '' => '赽', '' => '赻', '' => '赹', '' => '趼', '' => '跂', '' => '趹', '' => '趿', '' => '跁', '' => '軘', '' => '軞', '' => '軝', '' => '軜', '' => '軗', '' => '軠', '' => '軡', '' => '逤', '' => '逋', '' => '逑', '' => '逜', '' => '逌', '' => '逡', '' => '郯', '' => '郪', '' => '郰', '' => '郴', '' => '郲', '' => '郳', '' => '郔', '' => '郫', '' => '郬', '' => '郩', '' => '酖', '' => '酘', '' => '酚', '' => '酓', '' => '酕', '' => '釬', '' => '釴', '' => '釱', '' => '釳', '' => '釸', '' => '釤', '' => '釹', '' => '釪', '@' => '釫', 'A' => '釷', 'B' => '釨', 'C' => '釮', 'D' => '镺', 'E' => '閆', 'F' => '閈', 'G' => '陼', 'H' => '陭', 'I' => '陫', 'J' => '陱', 'K' => '陯', 'L' => '隿', 'M' => '靪', 'N' => '頄', 'O' => '飥', 'P' => '馗', 'Q' => '傛', 'R' => '傕', 'S' => '傔', 'T' => '傞', 'U' => '傋', 'V' => '傣', 'W' => '傃', 'X' => '傌', 'Y' => '傎', 'Z' => '傝', '[' => '偨', '\\' => '傜', ']' => '傒', '^' => '傂', '_' => '傇', '`' => '兟', 'a' => '凔', 'b' => '匒', 'c' => '匑', 'd' => '厤', 'e' => '厧', 'f' => '喑', 'g' => '喨', 'h' => '喥', 'i' => '喭', 'j' => '啷', 'k' => '噅', 'l' => '喢', 'm' => '喓', 'n' => '喈', 'o' => '喏', 'p' => '喵', 'q' => '喁', 'r' => '喣', 's' => '喒', 't' => '喤', 'u' => '啽', 'v' => '喌', 'w' => '喦', 'x' => '啿', 'y' => '喕', 'z' => '喡', '{' => '喎', '|' => '圌', '}' => '堩', '~' => '堷', 'ء' => '堙', 'آ' => '堞', 'أ' => '堧', 'ؤ' => '堣', 'إ' => '堨', 'ئ' => '埵', 'ا' => '塈', 'ب' => '堥', 'ة' => '堜', 'ت' => '堛', 'ث' => '堳', 'ج' => '堿', 'ح' => '堶', 'خ' => '堮', 'د' => '堹', 'ذ' => '堸', 'ر' => '堭', 'ز' => '堬', 'س' => '堻', 'ش' => '奡', 'ص' => '媯', 'ض' => '媔', 'ط' => '媟', 'ظ' => '婺', 'ع' => '媢', 'غ' => '媞', 'ػ' => '婸', 'ؼ' => '媦', 'ؽ' => '婼', 'ؾ' => '媥', 'ؿ' => '媬', '' => '媕', '' => '媮', '' => '娷', '' => '媄', '' => '媊', '' => '媗', '' => '媃', '' => '媋', '' => '媩', '' => '婻', '' => '婽', '' => '媌', '' => '媜', '' => '媏', '' => '媓', '' => '媝', '' => '寪', '' => '寍', '' => '寋', '' => '寔', '' => '寑', '' => '寊', '' => '寎', '' => '尌', '' => '尰', '' => '崷', '' => '嵃', '' => '嵫', '' => '嵁', '' => '嵋', '' => '崿', '' => '崵', '' => '嵑', '' => '嵎', '' => '嵕', '' => '崳', '' => '崺', '' => '嵒', '' => '崽', '' => '崱', '' => '嵙', '' => '嵂', '' => '崹', '' => '嵉', '' => '崸', '' => '崼', '' => '崲', '' => '崶', '' => '嵀', '' => '嵅', '' => '幄', '' => '幁', '' => '彘', '' => '徦', '' => '徥', '' => '徫', '' => '惉', '' => '悹', '' => '惌', '' => '惢', '' => '惎', '' => '惄', '' => '愔', '@' => '惲', 'A' => '愊', 'B' => '愖', 'C' => '愅', 'D' => '惵', 'E' => '愓', 'F' => '惸', 'G' => '惼', 'H' => '惾', 'I' => '惁', 'J' => '愃', 'K' => '愘', 'L' => '愝', 'M' => '愐', 'N' => '惿', 'O' => '愄', 'P' => '愋', 'Q' => '扊', 'R' => '掔', 'S' => '掱', 'T' => '掰', 'U' => '揎', 'V' => '揥', 'W' => '揨', 'X' => '揯', 'Y' => '揃', 'Z' => '撝', '[' => '揳', '\\' => '揊', ']' => '揠', '^' => '揶', '_' => '揕', '`' => '揲', 'a' => '揵', 'b' => '摡', 'c' => '揟', 'd' => '掾', 'e' => '揝', 'f' => '揜', 'g' => '揄', 'h' => '揘', 'i' => '揓', 'j' => '揂', 'k' => '揇', 'l' => '揌', 'm' => '揋', 'n' => '揈', 'o' => '揰', 'p' => '揗', 'q' => '揙', 'r' => '攲', 's' => '敧', 't' => '敪', 'u' => '敤', 'v' => '敜', 'w' => '敨', 'x' => '敥', 'y' => '斌', 'z' => '斝', '{' => '斞', '|' => '斮', '}' => '旐', '~' => '旒', '١' => '晼', '٢' => '晬', '٣' => '晻', '٤' => '暀', '٥' => '晱', '٦' => '晹', '٧' => '晪', '٨' => '晲', '٩' => '朁', '٪' => '椌', '٫' => '棓', '٬' => '椄', '٭' => '棜', 'ٮ' => '椪', 'ٯ' => '棬', 'ٰ' => '棪', 'ٱ' => '棱', 'ٲ' => '椏', 'ٳ' => '棖', 'ٴ' => '棷', 'ٵ' => '棫', 'ٶ' => '棤', 'ٷ' => '棶', 'ٸ' => '椓', 'ٹ' => '椐', 'ٺ' => '棳', 'ٻ' => '棡', 'ټ' => '椇', 'ٽ' => '棌', 'پ' => '椈', 'ٿ' => '楰', '' => '梴', '' => '椑', '' => '棯', '' => '棆', '' => '椔', '' => '棸', '' => '棐', '' => '棽', '' => '棼', '' => '棨', '' => '椋', '' => '椊', '' => '椗', '' => '棎', '' => '棈', '' => '棝', '' => '棞', '' => '棦', '' => '棴', '' => '棑', '' => '椆', '' => '棔', '' => '棩', '' => '椕', '' => '椥', '' => '棇', '' => '欹', '' => '欻', '' => '欿', '' => '欼', '' => '殔', '' => '殗', '' => '殙', '' => '殕', '' => '殽', '' => '毰', '' => '毲', '' => '毳', '' => '氰', '' => '淼', '' => '湆', '' => '湇', '' => '渟', '' => '湉', '' => '溈', '' => '渼', '' => '渽', '' => '湅', '' => '湢', '' => '渫', '' => '渿', '' => '湁', '' => '湝', '' => '湳', '' => '渜', '' => '渳', '' => '湋', '' => '湀', '' => '湑', '' => '渻', '' => '渃', '' => '渮', '' => '湞', '@' => '湨', 'A' => '湜', 'B' => '湡', 'C' => '渱', 'D' => '渨', 'E' => '湠', 'F' => '湱', 'G' => '湫', 'H' => '渹', 'I' => '渢', 'J' => '渰', 'K' => '湓', 'L' => '湥', 'M' => '渧', 'N' => '湸', 'O' => '湤', 'P' => '湷', 'Q' => '湕', 'R' => '湹', 'S' => '湒', 'T' => '湦', 'U' => '渵', 'V' => '渶', 'W' => '湚', 'X' => '焠', 'Y' => '焞', 'Z' => '焯', '[' => '烻', '\\' => '焮', ']' => '焱', '^' => '焣', '_' => '焥', '`' => '焢', 'a' => '焲', 'b' => '焟', 'c' => '焨', 'd' => '焺', 'e' => '焛', 'f' => '牋', 'g' => '牚', 'h' => '犈', 'i' => '犉', 'j' => '犆', 'k' => '犅', 'l' => '犋', 'm' => '猒', 'n' => '猋', 'o' => '猰', 'p' => '猢', 'q' => '猱', 'r' => '猳', 's' => '猧', 't' => '猲', 'u' => '猭', 'v' => '猦', 'w' => '猣', 'x' => '猵', 'y' => '猌', 'z' => '琮', '{' => '琬', '|' => '琰', '}' => '琫', '~' => '琖', 'ڡ' => '琚', 'ڢ' => '琡', 'ڣ' => '琭', 'ڤ' => '琱', 'ڥ' => '琤', 'ڦ' => '琣', 'ڧ' => '琝', 'ڨ' => '琩', 'ک' => '琠', 'ڪ' => '琲', 'ګ' => '瓻', 'ڬ' => '甯', 'ڭ' => '畯', 'ڮ' => '畬', 'گ' => '痧', 'ڰ' => '痚', 'ڱ' => '痡', 'ڲ' => '痦', 'ڳ' => '痝', 'ڴ' => '痟', 'ڵ' => '痤', 'ڶ' => '痗', 'ڷ' => '皕', 'ڸ' => '皒', 'ڹ' => '盚', 'ں' => '睆', 'ڻ' => '睇', 'ڼ' => '睄', 'ڽ' => '睍', 'ھ' => '睅', 'ڿ' => '睊', '' => '睎', '' => '睋', '' => '睌', '' => '矞', '' => '矬', '' => '硠', '' => '硤', '' => '硥', '' => '硜', '' => '硭', '' => '硱', '' => '硪', '' => '确', '' => '硰', '' => '硩', '' => '硨', '' => '硞', '' => '硢', '' => '祴', '' => '祳', '' => '祲', '' => '祰', '' => '稂', '' => '稊', '' => '稃', '' => '稌', '' => '稄', '' => '窙', '' => '竦', '' => '竤', '' => '筊', '' => '笻', '' => '筄', '' => '筈', '' => '筌', '' => '筎', '' => '筀', '' => '筘', '' => '筅', '' => '粢', '' => '粞', '' => '粨', '' => '粡', '' => '絘', '' => '絯', '' => '絣', '' => '絓', '' => '絖', '' => '絧', '' => '絪', '' => '絏', '' => '絭', '' => '絜', '' => '絫', '' => '絒', '' => '絔', '' => '絩', '' => '絑', '' => '絟', '' => '絎', '' => '缾', '' => '缿', '' => '罥', '@' => '罦', 'A' => '羢', 'B' => '羠', 'C' => '羡', 'D' => '翗', 'E' => '聑', 'F' => '聏', 'G' => '聐', 'H' => '胾', 'I' => '胔', 'J' => '腃', 'K' => '腊', 'L' => '腒', 'M' => '腏', 'N' => '腇', 'O' => '脽', 'P' => '腍', 'Q' => '脺', 'R' => '臦', 'S' => '臮', 'T' => '臷', 'U' => '臸', 'V' => '臹', 'W' => '舄', 'X' => '舼', 'Y' => '舽', 'Z' => '舿', '[' => '艵', '\\' => '茻', ']' => '菏', '^' => '菹', '_' => '萣', '`' => '菀', 'a' => '菨', 'b' => '萒', 'c' => '菧', 'd' => '菤', 'e' => '菼', 'f' => '菶', 'g' => '萐', 'h' => '菆', 'i' => '菈', 'j' => '菫', 'k' => '菣', 'l' => '莿', 'm' => '萁', 'n' => '菝', 'o' => '菥', 'p' => '菘', 'q' => '菿', 'r' => '菡', 's' => '菋', 't' => '菎', 'u' => '菖', 'v' => '菵', 'w' => '菉', 'x' => '萉', 'y' => '萏', 'z' => '菞', '{' => '萑', '|' => '萆', '}' => '菂', '~' => '菳', 'ۡ' => '菕', 'ۢ' => '菺', 'ۣ' => '菇', 'ۤ' => '菑', 'ۥ' => '菪', 'ۦ' => '萓', 'ۧ' => '菃', 'ۨ' => '菬', '۩' => '菮', '۪' => '菄', '۫' => '菻', '۬' => '菗', 'ۭ' => '菢', 'ۮ' => '萛', 'ۯ' => '菛', '۰' => '菾', '۱' => '蛘', '۲' => '蛢', '۳' => '蛦', '۴' => '蛓', '۵' => '蛣', '۶' => '蛚', '۷' => '蛪', '۸' => '蛝', '۹' => '蛫', 'ۺ' => '蛜', 'ۻ' => '蛬', 'ۼ' => '蛩', '۽' => '蛗', '۾' => '蛨', 'ۿ' => '蛑', '' => '衈', '' => '衖', '' => '衕', '' => '袺', '' => '裗', '' => '袹', '' => '袸', '' => '裀', '' => '袾', '' => '袶', '' => '袼', '' => '袷', '' => '袽', '' => '袲', '' => '褁', '' => '裉', '' => '覕', '' => '覘', '' => '覗', '' => '觝', '' => '觚', '' => '觛', '' => '詎', '' => '詍', '' => '訹', '' => '詙', '' => '詀', '' => '詗', '' => '詘', '' => '詄', '' => '詅', '' => '詒', '' => '詈', '' => '詑', '' => '詊', '' => '詌', '' => '詏', '' => '豟', '' => '貁', '' => '貀', '' => '貺', '' => '貾', '' => '貰', '' => '貹', '' => '貵', '' => '趄', '' => '趀', '' => '趉', '' => '跘', '' => '跓', '' => '跍', '' => '跇', '' => '跖', '' => '跜', '' => '跏', '' => '跕', '' => '跙', '' => '跈', '' => '跗', '' => '跅', '' => '軯', '' => '軷', '' => '軺', '@' => '軹', 'A' => '軦', 'B' => '軮', 'C' => '軥', 'D' => '軵', 'E' => '軧', 'F' => '軨', 'G' => '軶', 'H' => '軫', 'I' => '軱', 'J' => '軬', 'K' => '軴', 'L' => '軩', 'M' => '逭', 'N' => '逴', 'O' => '逯', 'P' => '鄆', 'Q' => '鄬', 'R' => '鄄', 'S' => '郿', 'T' => '郼', 'U' => '鄈', 'V' => '郹', 'W' => '郻', 'X' => '鄁', 'Y' => '鄀', 'Z' => '鄇', '[' => '鄅', '\\' => '鄃', ']' => '酡', '^' => '酤', '_' => '酟', '`' => '酢', 'a' => '酠', 'b' => '鈁', 'c' => '鈊', 'd' => '鈥', 'e' => '鈃', 'f' => '鈚', 'g' => '鈦', 'h' => '鈏', 'i' => '鈌', 'j' => '鈀', 'k' => '鈒', 'l' => '釿', 'm' => '釽', 'n' => '鈆', 'o' => '鈄', 'p' => '鈧', 'q' => '鈂', 'r' => '鈜', 's' => '鈤', 't' => '鈙', 'u' => '鈗', 'v' => '鈅', 'w' => '鈖', 'x' => '镻', 'y' => '閍', 'z' => '閌', '{' => '閐', '|' => '隇', '}' => '陾', '~' => '隈', 'ܡ' => '隉', 'ܢ' => '隃', 'ܣ' => '隀', 'ܤ' => '雂', 'ܥ' => '雈', 'ܦ' => '雃', 'ܧ' => '雱', 'ܨ' => '雰', 'ܩ' => '靬', 'ܪ' => '靰', 'ܫ' => '靮', 'ܬ' => '頇', 'ܭ' => '颩', 'ܮ' => '飫', 'ܯ' => '鳦', 'ܰ' => '黹', 'ܱ' => '亃', 'ܲ' => '亄', 'ܳ' => '亶', 'ܴ' => '傽', 'ܵ' => '傿', 'ܶ' => '僆', 'ܷ' => '傮', 'ܸ' => '僄', 'ܹ' => '僊', 'ܺ' => '傴', 'ܻ' => '僈', 'ܼ' => '僂', 'ܽ' => '傰', 'ܾ' => '僁', 'ܿ' => '傺', '' => '傱', '' => '僋', '' => '僉', '' => '傶', '' => '傸', '' => '凗', '' => '剺', '' => '剸', '' => '剻', '' => '剼', '' => '嗃', '' => '嗛', '' => '嗌', '' => '嗐', '' => '嗋', '' => '嗊', '' => '嗝', '' => '嗀', '' => '嗔', '' => '嗄', '' => '嗩', '' => '喿', '' => '嗒', '' => '喍', '' => '嗏', '' => '嗕', '' => '嗢', '' => '嗖', '' => '嗈', '' => '嗲', '' => '嗍', '' => '嗙', '' => '嗂', '' => '圔', '' => '塓', '' => '塨', '' => '塤', '' => '塏', '' => '塍', '' => '塉', '' => '塯', '' => '塕', '' => '塎', '' => '塝', '' => '塙', '' => '塥', '' => '塛', '' => '堽', '' => '塣', '' => '塱', '' => '壼', '' => '嫇', '' => '嫄', '' => '嫋', '' => '媺', '' => '媸', '' => '媱', '' => '媵', '' => '媰', '' => '媿', '' => '嫈', '' => '媻', '' => '嫆', '@' => '媷', 'A' => '嫀', 'B' => '嫊', 'C' => '媴', 'D' => '媶', 'E' => '嫍', 'F' => '媹', 'G' => '媐', 'H' => '寖', 'I' => '寘', 'J' => '寙', 'K' => '尟', 'L' => '尳', 'M' => '嵱', 'N' => '嵣', 'O' => '嵊', 'P' => '嵥', 'Q' => '嵲', 'R' => '嵬', 'S' => '嵞', 'T' => '嵨', 'U' => '嵧', 'V' => '嵢', 'W' => '巰', 'X' => '幏', 'Y' => '幎', 'Z' => '幊', '[' => '幍', '\\' => '幋', ']' => '廅', '^' => '廌', '_' => '廆', '`' => '廋', 'a' => '廇', 'b' => '彀', 'c' => '徯', 'd' => '徭', 'e' => '惷', 'f' => '慉', 'g' => '慊', 'h' => '愫', 'i' => '慅', 'j' => '愶', 'k' => '愲', 'l' => '愮', 'm' => '慆', 'n' => '愯', 'o' => '慏', 'p' => '愩', 'q' => '慀', 'r' => '戠', 's' => '酨', 't' => '戣', 'u' => '戥', 'v' => '戤', 'w' => '揅', 'x' => '揱', 'y' => '揫', 'z' => '搐', '{' => '搒', '|' => '搉', '}' => '搠', '~' => '搤', 'ݡ' => '搳', 'ݢ' => '摃', 'ݣ' => '搟', 'ݤ' => '搕', 'ݥ' => '搘', 'ݦ' => '搹', 'ݧ' => '搷', 'ݨ' => '搢', 'ݩ' => '搣', 'ݪ' => '搌', 'ݫ' => '搦', 'ݬ' => '搰', 'ݭ' => '搨', 'ݮ' => '摁', 'ݯ' => '搵', 'ݰ' => '搯', 'ݱ' => '搊', 'ݲ' => '搚', 'ݳ' => '摀', 'ݴ' => '搥', 'ݵ' => '搧', 'ݶ' => '搋', 'ݷ' => '揧', 'ݸ' => '搛', 'ݹ' => '搮', 'ݺ' => '搡', 'ݻ' => '搎', 'ݼ' => '敯', 'ݽ' => '斒', 'ݾ' => '旓', 'ݿ' => '暆', '' => '暌', '' => '暕', '' => '暐', '' => '暋', '' => '暊', '' => '暙', '' => '暔', '' => '晸', '' => '朠', '' => '楦', '' => '楟', '' => '椸', '' => '楎', '' => '楢', '' => '楱', '' => '椿', '' => '楅', '' => '楪', '' => '椹', '' => '楂', '' => '楗', '' => '楙', '' => '楺', '' => '楈', '' => '楉', '' => '椵', '' => '楬', '' => '椳', '' => '椽', '' => '楥', '' => '棰', '' => '楸', '' => '椴', '' => '楩', '' => '楀', '' => '楯', '' => '楄', '' => '楶', '' => '楘', '' => '楁', '' => '楴', '' => '楌', '' => '椻', '' => '楋', '' => '椷', '' => '楜', '' => '楏', '' => '楑', '' => '椲', '' => '楒', '' => '椯', '' => '楻', '' => '椼', '' => '歆', '' => '歅', '' => '歃', '' => '歂', '' => '歈', '' => '歁', '' => '殛', '' => '嗀', '' => '毻', '' => '毼', '@' => '毹', 'A' => '毷', 'B' => '毸', 'C' => '溛', 'D' => '滖', 'E' => '滈', 'F' => '溏', 'G' => '滀', 'H' => '溟', 'I' => '溓', 'J' => '溔', 'K' => '溠', 'L' => '溱', 'M' => '溹', 'N' => '滆', 'O' => '滒', 'P' => '溽', 'Q' => '滁', 'R' => '溞', 'S' => '滉', 'T' => '溷', 'U' => '溰', 'V' => '滍', 'W' => '溦', 'X' => '滏', 'Y' => '溲', 'Z' => '溾', '[' => '滃', '\\' => '滜', ']' => '滘', '^' => '溙', '_' => '溒', '`' => '溎', 'a' => '溍', 'b' => '溤', 'c' => '溡', 'd' => '溿', 'e' => '溳', 'f' => '滐', 'g' => '滊', 'h' => '溗', 'i' => '溮', 'j' => '溣', 'k' => '煇', 'l' => '煔', 'm' => '煒', 'n' => '煣', 'o' => '煠', 'p' => '煁', 'q' => '煝', 'r' => '煢', 's' => '煲', 't' => '煸', 'u' => '煪', 'v' => '煡', 'w' => '煂', 'x' => '煘', 'y' => '煃', 'z' => '煋', '{' => '煰', '|' => '煟', '}' => '煐', '~' => '煓', 'ޡ' => '煄', 'ޢ' => '煍', 'ޣ' => '煚', 'ޤ' => '牏', 'ޥ' => '犍', 'ަ' => '犌', 'ާ' => '犑', 'ި' => '犐', 'ީ' => '犎', 'ު' => '猼', 'ޫ' => '獂', 'ެ' => '猻', 'ޭ' => '猺', 'ޮ' => '獀', 'ޯ' => '獊', 'ް' => '獉', 'ޱ' => '瑄', '޲' => '瑊', '޳' => '瑋', '޴' => '瑒', '޵' => '瑑', '޶' => '瑗', '޷' => '瑀', '޸' => '瑏', '޹' => '瑐', '޺' => '瑎', '޻' => '瑂', '޼' => '瑆', '޽' => '瑍', '޾' => '瑔', '޿' => '瓡', '' => '瓿', '' => '瓾', '' => '瓽', '' => '甝', '' => '畹', '' => '畷', '' => '榃', '' => '痯', '' => '瘏', '' => '瘃', '' => '痷', '' => '痾', '' => '痼', '' => '痹', '' => '痸', '' => '瘐', '' => '痻', '' => '痶', '' => '痭', '' => '痵', '' => '痽', '' => '皙', '' => '皵', '' => '盝', '' => '睕', '' => '睟', '' => '睠', '' => '睒', '' => '睖', '' => '睚', '' => '睩', '' => '睧', '' => '睔', '' => '睙', '' => '睭', '' => '矠', '' => '碇', '' => '碚', '' => '碔', '' => '碏', '' => '碄', '' => '碕', '' => '碅', '' => '碆', '' => '碡', '' => '碃', '' => '硹', '' => '碙', '' => '碀', '' => '碖', '' => '硻', '' => '祼', '' => '禂', '' => '祽', '' => '祹', '' => '稑', '' => '稘', '' => '稙', '' => '稒', '' => '稗', '' => '稕', '' => '稢', '' => '稓', '@' => '稛', 'A' => '稐', 'B' => '窣', 'C' => '窢', 'D' => '窞', 'E' => '竫', 'F' => '筦', 'G' => '筤', 'H' => '筭', 'I' => '筴', 'J' => '筩', 'K' => '筲', 'L' => '筥', 'M' => '筳', 'N' => '筱', 'O' => '筰', 'P' => '筡', 'Q' => '筸', 'R' => '筶', 'S' => '筣', 'T' => '粲', 'U' => '粴', 'V' => '粯', 'W' => '綈', 'X' => '綆', 'Y' => '綀', 'Z' => '綍', '[' => '絿', '\\' => '綅', ']' => '絺', '^' => '綎', '_' => '絻', '`' => '綃', 'a' => '絼', 'b' => '綌', 'c' => '綔', 'd' => '綄', 'e' => '絽', 'f' => '綒', 'g' => '罭', 'h' => '罫', 'i' => '罧', 'j' => '罨', 'k' => '罬', 'l' => '羦', 'm' => '羥', 'n' => '羧', 'o' => '翛', 'p' => '翜', 'q' => '耡', 'r' => '腤', 's' => '腠', 't' => '腷', 'u' => '腜', 'v' => '腩', 'w' => '腛', 'x' => '腢', 'y' => '腲', 'z' => '朡', '{' => '腞', '|' => '腶', '}' => '腧', '~' => '腯', 'ߡ' => '腄', 'ߢ' => '腡', 'ߣ' => '舝', 'ߤ' => '艉', 'ߥ' => '艄', 'ߦ' => '艀', 'ߧ' => '艂', 'ߨ' => '艅', 'ߩ' => '蓱', 'ߪ' => '萿', '߫' => '葖', '߬' => '葶', '߭' => '葹', '߮' => '蒏', '߯' => '蒍', '߰' => '葥', '߱' => '葑', '߲' => '葀', '߳' => '蒆', 'ߴ' => '葧', 'ߵ' => '萰', '߶' => '葍', '߷' => '葽', '߸' => '葚', '߹' => '葙', 'ߺ' => '葴', '߻' => '葳', '߼' => '葝', '߽' => '蔇', '߾' => '葞', '߿' => '萷', '' => '萺', '' => '萴', '' => '葺', '' => '葃', '' => '葸', '' => '萲', '' => '葅', '' => '萩', '' => '菙', '' => '葋', '' => '萯', '' => '葂', '' => '萭', '' => '葟', '' => '葰', '' => '萹', '' => '葎', '' => '葌', '' => '葒', '' => '葯', '' => '蓅', '' => '蒎', '' => '萻', '' => '葇', '' => '萶', '' => '萳', '' => '葨', '' => '葾', '' => '葄', '' => '萫', '' => '葠', '' => '葔', '' => '葮', '' => '葐', '' => '蜋', '' => '蜄', '' => '蛷', '' => '蜌', '' => '蛺', '' => '蛖', '' => '蛵', '' => '蝍', '' => '蛸', '' => '蜎', '' => '蜉', '' => '蜁', '' => '蛶', '' => '蜍', '' => '蜅', '' => '裖', '' => '裋', '' => '裍', '' => '裎', '' => '裞', '' => '裛', '' => '裚', '' => '裌', '' => '裐', '' => '覅', '' => '覛', '' => '觟', '' => '觥', '' => '觤', '@' => '觡', 'A' => '觠', 'B' => '觢', 'C' => '觜', 'D' => '触', 'E' => '詶', 'F' => '誆', 'G' => '詿', 'H' => '詡', 'I' => '訿', 'J' => '詷', 'K' => '誂', 'L' => '誄', 'M' => '詵', 'N' => '誃', 'O' => '誁', 'P' => '詴', 'Q' => '詺', 'R' => '谼', 'S' => '豋', 'T' => '豊', 'U' => '豥', 'V' => '豤', 'W' => '豦', 'X' => '貆', 'Y' => '貄', 'Z' => '貅', '[' => '賌', '\\' => '赨', ']' => '赩', '^' => '趑', '_' => '趌', '`' => '趎', 'a' => '趏', 'b' => '趍', 'c' => '趓', 'd' => '趔', 'e' => '趐', 'f' => '趒', 'g' => '跰', 'h' => '跠', 'i' => '跬', 'j' => '跱', 'k' => '跮', 'l' => '跐', 'm' => '跩', 'n' => '跣', 'o' => '跢', 'p' => '跧', 'q' => '跲', 'r' => '跫', 's' => '跴', 't' => '輆', 'u' => '軿', 'v' => '輁', 'w' => '輀', 'x' => '輅', 'y' => '輇', 'z' => '輈', '{' => '輂', '|' => '輋', '}' => '遒', '~' => '逿', '' => '遄', '' => '遉', '' => '逽', '' => '鄐', '' => '鄍', '' => '鄏', '' => '鄑', '' => '鄖', '' => '鄔', '' => '鄋', '' => '鄎', '' => '酮', '' => '酯', '' => '鉈', '' => '鉒', '' => '鈰', '' => '鈺', '' => '鉦', '' => '鈳', '' => '鉥', '' => '鉞', '' => '銃', '' => '鈮', '' => '鉊', '' => '鉆', '' => '鉭', '' => '鉬', '' => '鉏', '' => '鉠', '' => '鉧', '' => '鉯', '' => '鈶', '' => '鉡', '' => '鉰', '' => '鈱', '' => '鉔', '' => '鉣', '' => '鉐', '' => '鉲', '' => '鉎', '' => '鉓', '' => '鉌', '' => '鉖', '' => '鈲', '' => '閟', '' => '閜', '' => '閞', '' => '閛', '' => '隒', '' => '隓', '' => '隑', '' => '隗', '' => '雎', '' => '雺', '' => '雽', '' => '雸', '' => '雵', '' => '靳', '' => '靷', '' => '靸', '' => '靲', '' => '頏', '' => '頍', '' => '頎', '' => '颬', '' => '飶', '' => '飹', '' => '馯', '' => '馲', '' => '馰', '' => '馵', '' => '骭', '' => '骫', '' => '魛', '' => '鳪', '' => '鳭', '' => '鳧', '' => '麀', '' => '黽', '' => '僦', '' => '僔', '' => '僗', '' => '僨', '' => '僳', '' => '僛', '' => '僪', '' => '僝', '' => '僤', '' => '僓', '' => '僬', '' => '僰', '' => '僯', '' => '僣', '' => '僠', '@' => '凘', 'A' => '劀', 'B' => '劁', 'C' => '勩', 'D' => '勫', 'E' => '匰', 'F' => '厬', 'G' => '嘧', 'H' => '嘕', 'I' => '嘌', 'J' => '嘒', 'K' => '嗼', 'L' => '嘏', 'M' => '嘜', 'N' => '嘁', 'O' => '嘓', 'P' => '嘂', 'Q' => '嗺', 'R' => '嘝', 'S' => '嘄', 'T' => '嗿', 'U' => '嗹', 'V' => '墉', 'W' => '塼', 'X' => '墐', 'Y' => '墘', 'Z' => '墆', '[' => '墁', '\\' => '塿', ']' => '塴', '^' => '墋', '_' => '塺', '`' => '墇', 'a' => '墑', 'b' => '墎', 'c' => '塶', 'd' => '墂', 'e' => '墈', 'f' => '塻', 'g' => '墔', 'h' => '墏', 'i' => '壾', 'j' => '奫', 'k' => '嫜', 'l' => '嫮', 'm' => '嫥', 'n' => '嫕', 'o' => '嫪', 'p' => '嫚', 'q' => '嫭', 'r' => '嫫', 's' => '嫳', 't' => '嫢', 'u' => '嫠', 'v' => '嫛', 'w' => '嫬', 'x' => '嫞', 'y' => '嫝', 'z' => '嫙', '{' => '嫨', '|' => '嫟', '}' => '孷', '~' => '寠', '' => '寣', '' => '屣', '' => '嶂', '' => '嶀', '' => '嵽', '' => '嶆', '' => '嵺', '' => '嶁', '' => '嵷', '' => '嶊', '' => '嶉', '' => '嶈', '' => '嵾', '' => '嵼', '' => '嶍', '' => '嵹', '' => '嵿', '' => '幘', '' => '幙', '' => '幓', '' => '廘', '' => '廑', '' => '廗', '' => '廎', '' => '廜', '' => '廕', '' => '廙', '' => '廒', '' => '廔', '' => '彄', '' => '彃', '' => '彯', '' => '徶', '' => '愬', '' => '愨', '' => '慁', '' => '慞', '' => '慱', '' => '慳', '' => '慒', '' => '慓', '' => '慲', '' => '慬', '' => '憀', '' => '慴', '' => '慔', '' => '慺', '' => '慛', '' => '慥', '' => '愻', '' => '慪', '' => '慡', '' => '慖', '' => '戩', '' => '戧', '' => '戫', '' => '搫', '' => '摍', '' => '摛', '' => '摝', '' => '摴', '' => '摶', '' => '摲', '' => '摳', '' => '摽', '' => '摵', '' => '摦', '' => '撦', '' => '摎', '' => '撂', '' => '摞', '' => '摜', '' => '摋', '' => '摓', '' => '摠', '' => '摐', '' => '摿', '' => '搿', '' => '摬', '' => '摫', '' => '摙', '' => '摥', '' => '摷', '' => '敳', '' => '斠', '' => '暡', '' => '暠', '' => '暟', '' => '朅', '' => '朄', '' => '朢', '' => '榱', '' => '榶', '' => '槉', '@' => '榠', 'A' => '槎', 'B' => '榖', 'C' => '榰', 'D' => '榬', 'E' => '榼', 'F' => '榑', 'G' => '榙', 'H' => '榎', 'I' => '榧', 'J' => '榍', 'K' => '榩', 'L' => '榾', 'M' => '榯', 'N' => '榿', 'O' => '槄', 'P' => '榽', 'Q' => '榤', 'R' => '槔', 'S' => '榹', 'T' => '槊', 'U' => '榚', 'V' => '槏', 'W' => '榳', 'X' => '榓', 'Y' => '榪', 'Z' => '榡', '[' => '榞', '\\' => '槙', ']' => '榗', '^' => '榐', '_' => '槂', '`' => '榵', 'a' => '榥', 'b' => '槆', 'c' => '歊', 'd' => '歍', 'e' => '歋', 'f' => '殞', 'g' => '殟', 'h' => '殠', 'i' => '毃', 'j' => '毄', 'k' => '毾', 'l' => '滎', 'm' => '滵', 'n' => '滱', 'o' => '漃', 'p' => '漥', 'q' => '滸', 'r' => '漷', 's' => '滻', 't' => '漮', 'u' => '漉', 'v' => '潎', 'w' => '漙', 'x' => '漚', 'y' => '漧', 'z' => '漘', '{' => '漻', '|' => '漒', '}' => '滭', '~' => '漊', '' => '漶', '' => '潳', '' => '滹', '' => '滮', '' => '漭', '' => '潀', '' => '漰', '' => '漼', '' => '漵', '' => '滫', '' => '漇', '' => '漎', '' => '潃', '' => '漅', '' => '滽', '' => '滶', '' => '漹', '' => '漜', '' => '滼', '' => '漺', '' => '漟', '' => '漍', '' => '漞', '' => '漈', '' => '漡', '' => '熇', '' => '熐', '' => '熉', '' => '熀', '' => '熅', '' => '熂', '' => '熏', '' => '煻', '' => '熆', '' => '熁', '' => '熗', '' => '牄', '' => '牓', '' => '犗', '' => '犕', '' => '犓', '' => '獃', '' => '獍', '' => '獑', '' => '獌', '' => '瑢', '' => '瑳', '' => '瑱', '' => '瑵', '' => '瑲', '' => '瑧', '' => '瑮', '' => '甀', '' => '甂', '' => '甃', '' => '畽', '' => '疐', '' => '瘖', '' => '瘈', '' => '瘌', '' => '瘕', '' => '瘑', '' => '瘊', '' => '瘔', '' => '皸', '' => '瞁', '' => '睼', '' => '瞅', '' => '瞂', '' => '睮', '' => '瞀', '' => '睯', '' => '睾', '' => '瞃', '' => '碲', '' => '碪', '' => '碴', '' => '碭', '' => '碨', '' => '硾', '' => '碫', '' => '碞', '' => '碥', '' => '碠', '' => '碬', '' => '碢', '' => '碤', '' => '禘', '' => '禊', '' => '禋', '' => '禖', '' => '禕', '' => '禔', '' => '禓', '@' => '禗', 'A' => '禈', 'B' => '禒', 'C' => '禐', 'D' => '稫', 'E' => '穊', 'F' => '稰', 'G' => '稯', 'H' => '稨', 'I' => '稦', 'J' => '窨', 'K' => '窫', 'L' => '窬', 'M' => '竮', 'N' => '箈', 'O' => '箜', 'P' => '箊', 'Q' => '箑', 'R' => '箐', 'S' => '箖', 'T' => '箍', 'U' => '箌', 'V' => '箛', 'W' => '箎', 'X' => '箅', 'Y' => '箘', 'Z' => '劄', '[' => '箙', '\\' => '箤', ']' => '箂', '^' => '粻', '_' => '粿', '`' => '粼', 'a' => '粺', 'b' => '綧', 'c' => '綷', 'd' => '緂', 'e' => '綣', 'f' => '綪', 'g' => '緁', 'h' => '緀', 'i' => '緅', 'j' => '綝', 'k' => '緎', 'l' => '緄', 'm' => '緆', 'n' => '緋', 'o' => '緌', 'p' => '綯', 'q' => '綹', 'r' => '綖', 's' => '綼', 't' => '綟', 'u' => '綦', 'v' => '綮', 'w' => '綩', 'x' => '綡', 'y' => '緉', 'z' => '罳', '{' => '翢', '|' => '翣', '}' => '翥', '~' => '翞', '' => '耤', '' => '聝', '' => '聜', '' => '膉', '' => '膆', '' => '膃', '' => '膇', '' => '膍', '' => '膌', '' => '膋', '' => '舕', '' => '蒗', '' => '蒤', '' => '蒡', '' => '蒟', '' => '蒺', '' => '蓎', '' => '蓂', '' => '蒬', '' => '蒮', '' => '蒫', '' => '蒹', '' => '蒴', '' => '蓁', '' => '蓍', '' => '蒪', '' => '蒚', '' => '蒱', '' => '蓐', '' => '蒝', '' => '蒧', '' => '蒻', '' => '蒢', '' => '蒔', '' => '蓇', '' => '蓌', '' => '蒛', '' => '蒩', '' => '蒯', '' => '蒨', '' => '蓖', '' => '蒘', '' => '蒶', '' => '蓏', '' => '蒠', '' => '蓗', '' => '蓔', '' => '蓒', '' => '蓛', '' => '蒰', '' => '蒑', '' => '虡', '' => '蜳', '' => '蜣', '' => '蜨', '' => '蝫', '' => '蝀', '' => '蜮', '' => '蜞', '' => '蜡', '' => '蜙', '' => '蜛', '' => '蝃', '' => '蜬', '' => '蝁', '' => '蜾', '' => '蝆', '' => '蜠', '' => '蜲', '' => '蜪', '' => '蜭', '' => '蜼', '' => '蜒', '' => '蜺', '' => '蜱', '' => '蜵', '' => '蝂', '' => '蜦', '' => '蜧', '' => '蜸', '' => '蜤', '' => '蜚', '' => '蜰', '' => '蜑', '' => '裷', '' => '裧', '' => '裱', '' => '裲', '' => '裺', '' => '裾', '' => '裮', '' => '裼', '' => '裶', '' => '裻', '@' => '裰', 'A' => '裬', 'B' => '裫', 'C' => '覝', 'D' => '覡', 'E' => '覟', 'F' => '覞', 'G' => '觩', 'H' => '觫', 'I' => '觨', 'J' => '誫', 'K' => '誙', 'L' => '誋', 'M' => '誒', 'N' => '誏', 'O' => '誖', 'P' => '谽', 'Q' => '豨', 'R' => '豩', 'S' => '賕', 'T' => '賏', 'U' => '賗', 'V' => '趖', 'W' => '踉', 'X' => '踂', 'Y' => '跿', 'Z' => '踍', '[' => '跽', '\\' => '踊', ']' => '踃', '^' => '踇', '_' => '踆', '`' => '踅', 'a' => '跾', 'b' => '踀', 'c' => '踄', 'd' => '輐', 'e' => '輑', 'f' => '輎', 'g' => '輍', 'h' => '鄣', 'i' => '鄜', 'j' => '鄠', 'k' => '鄢', 'l' => '鄟', 'm' => '鄝', 'n' => '鄚', 'o' => '鄤', 'p' => '鄡', 'q' => '鄛', 'r' => '酺', 's' => '酲', 't' => '酹', 'u' => '酳', 'v' => '銥', 'w' => '銤', 'x' => '鉶', 'y' => '銛', 'z' => '鉺', '{' => '銠', '|' => '銔', '}' => '銪', '~' => '銍', '' => '銦', '' => '銚', '' => '銫', '' => '鉹', '' => '銗', '' => '鉿', '' => '銣', '' => '鋮', '' => '銎', '' => '銂', '' => '銕', '' => '銢', '' => '鉽', '' => '銈', '' => '銡', '' => '銊', '' => '銆', '' => '銌', '' => '銙', '' => '銧', '' => '鉾', '' => '銇', '' => '銩', '' => '銝', '' => '銋', '' => '鈭', '' => '隞', '' => '隡', '' => '雿', '' => '靘', '' => '靽', '' => '靺', '' => '靾', '' => '鞃', '' => '鞀', '' => '鞂', '' => '靻', '' => '鞄', '' => '鞁', '' => '靿', '' => '韎', '' => '韍', '' => '頖', '' => '颭', '' => '颮', '' => '餂', '' => '餀', '' => '餇', '' => '馝', '' => '馜', '' => '駃', '' => '馹', '' => '馻', '' => '馺', '' => '駂', '' => '馽', '' => '駇', '' => '骱', '' => '髣', '' => '髧', '' => '鬾', '' => '鬿', '' => '魠', '' => '魡', '' => '魟', '' => '鳱', '' => '鳲', '' => '鳵', '' => '麧', '' => '僿', '' => '儃', '' => '儰', '' => '僸', '' => '儆', '' => '儇', '' => '僶', '' => '僾', '' => '儋', '' => '儌', '' => '僽', '' => '儊', '' => '劋', '' => '劌', '' => '勱', '' => '勯', '' => '噈', '' => '噂', '' => '噌', '' => '嘵', '' => '噁', '' => '噊', '' => '噉', '' => '噆', '' => '噘', '@' => '噚', 'A' => '噀', 'B' => '嘳', 'C' => '嘽', 'D' => '嘬', 'E' => '嘾', 'F' => '嘸', 'G' => '嘪', 'H' => '嘺', 'I' => '圚', 'J' => '墫', 'K' => '墝', 'L' => '墱', 'M' => '墠', 'N' => '墣', 'O' => '墯', 'P' => '墬', 'Q' => '墥', 'R' => '墡', 'S' => '壿', 'T' => '嫿', 'U' => '嫴', 'V' => '嫽', 'W' => '嫷', 'X' => '嫶', 'Y' => '嬃', 'Z' => '嫸', '[' => '嬂', '\\' => '嫹', ']' => '嬁', '^' => '嬇', '_' => '嬅', '`' => '嬏', 'a' => '屧', 'b' => '嶙', 'c' => '嶗', 'd' => '嶟', 'e' => '嶒', 'f' => '嶢', 'g' => '嶓', 'h' => '嶕', 'i' => '嶠', 'j' => '嶜', 'k' => '嶡', 'l' => '嶚', 'm' => '嶞', 'n' => '幩', 'o' => '幝', 'p' => '幠', 'q' => '幜', 'r' => '緳', 's' => '廛', 't' => '廞', 'u' => '廡', 'v' => '彉', 'w' => '徲', 'x' => '憋', 'y' => '憃', 'z' => '慹', '{' => '憱', '|' => '憰', '}' => '憢', '~' => '憉', '' => '憛', '' => '憓', '' => '憯', '' => '憭', '' => '憟', '' => '憒', '' => '憪', '' => '憡', '' => '憍', '' => '慦', '' => '憳', '' => '戭', '' => '摮', '' => '摰', '' => '撖', '' => '撠', '' => '撅', '' => '撗', '' => '撜', '' => '撏', '' => '撋', '' => '撊', '' => '撌', '' => '撣', '' => '撟', '' => '摨', '' => '撱', '' => '撘', '' => '敶', '' => '敺', '' => '敹', '' => '敻', '' => '斲', '' => '斳', '' => '暵', '' => '暰', '' => '暩', '' => '暲', '' => '暷', '' => '暪', '' => '暯', '' => '樀', '' => '樆', '' => '樗', '' => '槥', '' => '槸', '' => '樕', '' => '槱', '' => '槤', '' => '樠', '' => '槿', '' => '槬', '' => '槢', '' => '樛', '' => '樝', '' => '槾', '' => '樧', '' => '槲', '' => '槮', '' => '樔', '' => '槷', '' => '槧', '' => '橀', '' => '樈', '' => '槦', '' => '槻', '' => '樍', '' => '槼', '' => '槫', '' => '樉', '' => '樄', '' => '樘', '' => '樥', '' => '樏', '' => '槶', '' => '樦', '' => '樇', '' => '槴', '' => '樖', '' => '歑', '' => '殥', '' => '殣', '' => '殢', '' => '殦', '' => '氁', '' => '氀', '' => '毿', '' => '氂', '' => '潁', '' => '漦', '' => '潾', '' => '澇', '' => '濆', '' => '澒', '@' => '澍', 'A' => '澉', 'B' => '澌', 'C' => '潢', 'D' => '潏', 'E' => '澅', 'F' => '潚', 'G' => '澖', 'H' => '潶', 'I' => '潬', 'J' => '澂', 'K' => '潕', 'L' => '潲', 'M' => '潒', 'N' => '潐', 'O' => '潗', 'P' => '澔', 'Q' => '澓', 'R' => '潝', 'S' => '漀', 'T' => '潡', 'U' => '潫', 'V' => '潽', 'W' => '潧', 'X' => '澐', 'Y' => '潓', 'Z' => '澋', '[' => '潩', '\\' => '潿', ']' => '澕', '^' => '潣', '_' => '潷', '`' => '潪', 'a' => '潻', 'b' => '熲', 'c' => '熯', 'd' => '熛', 'e' => '熰', 'f' => '熠', 'g' => '熚', 'h' => '熩', 'i' => '熵', 'j' => '熝', 'k' => '熥', 'l' => '熞', 'm' => '熤', 'n' => '熡', 'o' => '熪', 'p' => '熜', 'q' => '熧', 'r' => '熳', 's' => '犘', 't' => '犚', 'u' => '獘', 'v' => '獒', 'w' => '獞', 'x' => '獟', 'y' => '獠', 'z' => '獝', '{' => '獛', '|' => '獡', '}' => '獚', '~' => '獙', '' => '獢', '' => '璇', '' => '璉', '' => '璊', '' => '璆', '' => '璁', '' => '瑽', '' => '璅', '' => '璈', '' => '瑼', '' => '瑹', '' => '甈', '' => '甇', '' => '畾', '' => '瘥', '' => '瘞', '' => '瘙', '' => '瘝', '' => '瘜', '' => '瘣', '' => '瘚', '' => '瘨', '' => '瘛', '' => '皜', '' => '皝', '' => '皞', '' => '皛', '' => '瞍', '' => '瞏', '' => '瞉', '' => '瞈', '' => '磍', '' => '碻', '' => '磏', '' => '磌', '' => '磑', '' => '磎', '' => '磔', '' => '磈', '' => '磃', '' => '磄', '' => '磉', '' => '禚', '' => '禡', '' => '禠', '' => '禜', '' => '禢', '' => '禛', '' => '歶', '' => '稹', '' => '窲', '' => '窴', '' => '窳', '' => '箷', '' => '篋', '' => '箾', '' => '箬', '' => '篎', '' => '箯', '' => '箹', '' => '篊', '' => '箵', '' => '糅', '' => '糈', '' => '糌', '' => '糋', '' => '緷', '' => '緛', '' => '緪', '' => '緧', '' => '緗', '' => '緡', '' => '縃', '' => '緺', '' => '緦', '' => '緶', '' => '緱', '' => '緰', '' => '緮', '' => '緟', '' => '罶', '' => '羬', '' => '羰', '' => '羭', '' => '翭', '' => '翫', '' => '翪', '' => '翬', '' => '翦', '' => '翨', '' => '聤', '' => '聧', '' => '膣', '' => '膟', '@' => '膞', 'A' => '膕', 'B' => '膢', 'C' => '膙', 'D' => '膗', 'E' => '舖', 'F' => '艏', 'G' => '艓', 'H' => '艒', 'I' => '艐', 'J' => '艎', 'K' => '艑', 'L' => '蔤', 'M' => '蔻', 'N' => '蔏', 'O' => '蔀', 'P' => '蔩', 'Q' => '蔎', 'R' => '蔉', 'S' => '蔍', 'T' => '蔟', 'U' => '蔊', 'V' => '蔧', 'W' => '蔜', 'X' => '蓻', 'Y' => '蔫', 'Z' => '蓺', '[' => '蔈', '\\' => '蔌', ']' => '蓴', '^' => '蔪', '_' => '蓲', '`' => '蔕', 'a' => '蓷', 'b' => '蓫', 'c' => '蓳', 'd' => '蓼', 'e' => '蔒', 'f' => '蓪', 'g' => '蓩', 'h' => '蔖', 'i' => '蓾', 'j' => '蔨', 'k' => '蔝', 'l' => '蔮', 'm' => '蔂', 'n' => '蓽', 'o' => '蔞', 'p' => '蓶', 'q' => '蔱', 'r' => '蔦', 's' => '蓧', 't' => '蓨', 'u' => '蓰', 'v' => '蓯', 'w' => '蓹', 'x' => '蔘', 'y' => '蔠', 'z' => '蔰', '{' => '蔋', '|' => '蔙', '}' => '蔯', '~' => '虢', '' => '蝖', '' => '蝣', '' => '蝤', '' => '蝷', '' => '蟡', '' => '蝳', '' => '蝘', '' => '蝔', '' => '蝛', '' => '蝒', '' => '蝡', '' => '蝚', '' => '蝑', '' => '蝞', '' => '蝭', '' => '蝪', '' => '蝐', '' => '蝎', '' => '蝟', '' => '蝝', '' => '蝯', '' => '蝬', '' => '蝺', '' => '蝮', '' => '蝜', '' => '蝥', '' => '蝏', '' => '蝻', '' => '蝵', '' => '蝢', '' => '蝧', '' => '蝩', '' => '衚', '' => '褅', '' => '褌', '' => '褔', '' => '褋', '' => '褗', '' => '褘', '' => '褙', '' => '褆', '' => '褖', '' => '褑', '' => '褎', '' => '褉', '' => '覢', '' => '覤', '' => '覣', '' => '觭', '' => '觰', '' => '觬', '' => '諏', '' => '諆', '' => '誸', '' => '諓', '' => '諑', '' => '諔', '' => '諕', '' => '誻', '' => '諗', '' => '誾', '' => '諀', '' => '諅', '' => '諘', '' => '諃', '' => '誺', '' => '誽', '' => '諙', '' => '谾', '' => '豍', '' => '貏', '' => '賥', '' => '賟', '' => '賙', '' => '賨', '' => '賚', '' => '賝', '' => '賧', '' => '趠', '' => '趜', '' => '趡', '' => '趛', '' => '踠', '' => '踣', '' => '踥', '' => '踤', '' => '踮', '' => '踕', '' => '踛', '' => '踖', '' => '踑', '' => '踙', '' => '踦', '' => '踧', '@' => '踔', 'A' => '踒', 'B' => '踘', 'C' => '踓', 'D' => '踜', 'E' => '踗', 'F' => '踚', 'G' => '輬', 'H' => '輤', 'I' => '輘', 'J' => '輚', 'K' => '輠', 'L' => '輣', 'M' => '輖', 'N' => '輗', 'O' => '遳', 'P' => '遰', 'Q' => '遯', 'R' => '遧', 'S' => '遫', 'T' => '鄯', 'U' => '鄫', 'V' => '鄩', 'W' => '鄪', 'X' => '鄲', 'Y' => '鄦', 'Z' => '鄮', '[' => '醅', '\\' => '醆', ']' => '醊', '^' => '醁', '_' => '醂', '`' => '醄', 'a' => '醀', 'b' => '鋐', 'c' => '鋃', 'd' => '鋄', 'e' => '鋀', 'f' => '鋙', 'g' => '銶', 'h' => '鋏', 'i' => '鋱', 'j' => '鋟', 'k' => '鋘', 'l' => '鋩', 'm' => '鋗', 'n' => '鋝', 'o' => '鋌', 'p' => '鋯', 'q' => '鋂', 'r' => '鋨', 's' => '鋊', 't' => '鋈', 'u' => '鋎', 'v' => '鋦', 'w' => '鋍', 'x' => '鋕', 'y' => '鋉', 'z' => '鋠', '{' => '鋞', '|' => '鋧', '}' => '鋑', '~' => '鋓', '' => '銵', '' => '鋡', '' => '鋆', '' => '銴', '' => '镼', '' => '閬', '' => '閫', '' => '閮', '' => '閰', '' => '隤', '' => '隢', '' => '雓', '' => '霅', '' => '霈', '' => '霂', '' => '靚', '' => '鞊', '' => '鞎', '' => '鞈', '' => '韐', '' => '韏', '' => '頞', '' => '頝', '' => '頦', '' => '頩', '' => '頨', '' => '頠', '' => '頛', '' => '頧', '' => '颲', '' => '餈', '' => '飺', '' => '餑', '' => '餔', '' => '餖', '' => '餗', '' => '餕', '' => '駜', '' => '駍', '' => '駏', '' => '駓', '' => '駔', '' => '駎', '' => '駉', '' => '駖', '' => '駘', '' => '駋', '' => '駗', '' => '駌', '' => '骳', '' => '髬', '' => '髫', '' => '髳', '' => '髲', '' => '髱', '' => '魆', '' => '魃', '' => '魧', '' => '魴', '' => '魱', '' => '魦', '' => '魶', '' => '魵', '' => '魰', '' => '魨', '' => '魤', '' => '魬', '' => '鳼', '' => '鳺', '' => '鳽', '' => '鳿', '' => '鳷', '' => '鴇', '' => '鴀', '' => '鳹', '' => '鳻', '' => '鴈', '' => '鴅', '' => '鴄', '' => '麃', '' => '黓', '' => '鼏', '' => '鼐', '' => '儜', '' => '儓', '' => '儗', '' => '儚', '' => '儑', '' => '凞', '' => '匴', '' => '叡', '' => '噰', '' => '噠', '' => '噮', '@' => '噳', 'A' => '噦', 'B' => '噣', 'C' => '噭', 'D' => '噲', 'E' => '噞', 'F' => '噷', 'G' => '圜', 'H' => '圛', 'I' => '壈', 'J' => '墽', 'K' => '壉', 'L' => '墿', 'M' => '墺', 'N' => '壂', 'O' => '墼', 'P' => '壆', 'Q' => '嬗', 'R' => '嬙', 'S' => '嬛', 'T' => '嬡', 'U' => '嬔', 'V' => '嬓', 'W' => '嬐', 'X' => '嬖', 'Y' => '嬨', 'Z' => '嬚', '[' => '嬠', '\\' => '嬞', ']' => '寯', '^' => '嶬', '_' => '嶱', '`' => '嶩', 'a' => '嶧', 'b' => '嶵', 'c' => '嶰', 'd' => '嶮', 'e' => '嶪', 'f' => '嶨', 'g' => '嶲', 'h' => '嶭', 'i' => '嶯', 'j' => '嶴', 'k' => '幧', 'l' => '幨', 'm' => '幦', 'n' => '幯', 'o' => '廩', 'p' => '廧', 'q' => '廦', 'r' => '廨', 's' => '廥', 't' => '彋', 'u' => '徼', 'v' => '憝', 'w' => '憨', 'x' => '憖', 'y' => '懅', 'z' => '憴', '{' => '懆', '|' => '懁', '}' => '懌', '~' => '憺', '' => '憿', '' => '憸', '' => '憌', '' => '擗', '' => '擖', '' => '擐', '' => '擏', '' => '擉', '' => '撽', '' => '撉', '' => '擃', '' => '擛', '' => '擳', '' => '擙', '' => '攳', '' => '敿', '' => '敼', '' => '斢', '' => '曈', '' => '暾', '' => '曀', '' => '曊', '' => '曋', '' => '曏', '' => '暽', '' => '暻', '' => '暺', '' => '曌', '' => '朣', '' => '樴', '' => '橦', '' => '橉', '' => '橧', '' => '樲', '' => '橨', '' => '樾', '' => '橝', '' => '橭', '' => '橶', '' => '橛', '' => '橑', '' => '樨', '' => '橚', '' => '樻', '' => '樿', '' => '橁', '' => '橪', '' => '橤', '' => '橐', '' => '橏', '' => '橔', '' => '橯', '' => '橩', '' => '橠', '' => '樼', '' => '橞', '' => '橖', '' => '橕', '' => '橍', '' => '橎', '' => '橆', '' => '歕', '' => '歔', '' => '歖', '' => '殧', '' => '殪', '' => '殫', '' => '毈', '' => '毇', '' => '氄', '' => '氃', '' => '氆', '' => '澭', '' => '濋', '' => '澣', '' => '濇', '' => '澼', '' => '濎', '' => '濈', '' => '潞', '' => '濄', '' => '澽', '' => '澞', '' => '濊', '' => '澨', '' => '瀄', '' => '澥', '' => '澮', '' => '澺', '' => '澬', '' => '澪', '' => '濏', '' => '澿', '' => '澸', '@' => '澢', 'A' => '濉', 'B' => '澫', 'C' => '濍', 'D' => '澯', 'E' => '澲', 'F' => '澰', 'G' => '燅', 'H' => '燂', 'I' => '熿', 'J' => '熸', 'K' => '燖', 'L' => '燀', 'M' => '燁', 'N' => '燋', 'O' => '燔', 'P' => '燊', 'Q' => '燇', 'R' => '燏', 'S' => '熽', 'T' => '燘', 'U' => '熼', 'V' => '燆', 'W' => '燚', 'X' => '燛', 'Y' => '犝', 'Z' => '犞', '[' => '獩', '\\' => '獦', ']' => '獧', '^' => '獬', '_' => '獥', '`' => '獫', 'a' => '獪', 'b' => '瑿', 'c' => '璚', 'd' => '璠', 'e' => '璔', 'f' => '璒', 'g' => '璕', 'h' => '璡', 'i' => '甋', 'j' => '疀', 'k' => '瘯', 'l' => '瘭', 'm' => '瘱', 'n' => '瘽', 'o' => '瘳', 'p' => '瘼', 'q' => '瘵', 'r' => '瘲', 's' => '瘰', 't' => '皻', 'u' => '盦', 'v' => '瞚', 'w' => '瞝', 'x' => '瞡', 'y' => '瞜', 'z' => '瞛', '{' => '瞢', '|' => '瞣', '}' => '瞕', '~' => '瞙', '' => '瞗', '' => '磝', '' => '磩', '' => '磥', '' => '磪', '' => '磞', '' => '磣', '' => '磛', '' => '磡', '' => '磢', '' => '磭', '' => '磟', '' => '磠', '' => '禤', '' => '穄', '' => '穈', '' => '穇', '' => '窶', '' => '窸', '' => '窵', '' => '窱', '' => '窷', '' => '篞', '' => '篣', '' => '篧', '' => '篝', '' => '篕', '' => '篥', '' => '篚', '' => '篨', '' => '篹', '' => '篔', '' => '篪', '' => '篢', '' => '篜', '' => '篫', '' => '篘', '' => '篟', '' => '糒', '' => '糔', '' => '糗', '' => '糐', '' => '糑', '' => '縒', '' => '縡', '' => '縗', '' => '縌', '' => '縟', '' => '縠', '' => '縓', '' => '縎', '' => '縜', '' => '縕', '' => '縚', '' => '縢', '' => '縋', '' => '縏', '' => '縖', '' => '縍', '' => '縔', '' => '縥', '' => '縤', '' => '罃', '' => '罻', '' => '罼', '' => '罺', '' => '羱', '' => '翯', '' => '耪', '' => '耩', '' => '聬', '' => '膱', '' => '膦', '' => '膮', '' => '膹', '' => '膵', '' => '膫', '' => '膰', '' => '膬', '' => '膴', '' => '膲', '' => '膷', '' => '膧', '' => '臲', '' => '艕', '' => '艖', '' => '艗', '' => '蕖', '' => '蕅', '' => '蕫', '' => '蕍', '' => '蕓', '' => '蕡', '' => '蕘', '@' => '蕀', 'A' => '蕆', 'B' => '蕤', 'C' => '蕁', 'D' => '蕢', 'E' => '蕄', 'F' => '蕑', 'G' => '蕇', 'H' => '蕣', 'I' => '蔾', 'J' => '蕛', 'K' => '蕱', 'L' => '蕎', 'M' => '蕮', 'N' => '蕵', 'O' => '蕕', 'P' => '蕧', 'Q' => '蕠', 'R' => '薌', 'S' => '蕦', 'T' => '蕝', 'U' => '蕔', 'V' => '蕥', 'W' => '蕬', 'X' => '虣', 'Y' => '虥', 'Z' => '虤', '[' => '螛', '\\' => '螏', ']' => '螗', '^' => '螓', '_' => '螒', '`' => '螈', 'a' => '螁', 'b' => '螖', 'c' => '螘', 'd' => '蝹', 'e' => '螇', 'f' => '螣', 'g' => '螅', 'h' => '螐', 'i' => '螑', 'j' => '螝', 'k' => '螄', 'l' => '螔', 'm' => '螜', 'n' => '螚', 'o' => '螉', 'p' => '褞', 'q' => '褦', 'r' => '褰', 's' => '褭', 't' => '褮', 'u' => '褧', 'v' => '褱', 'w' => '褢', 'x' => '褩', 'y' => '褣', 'z' => '褯', '{' => '褬', '|' => '褟', '}' => '觱', '~' => '諠', '' => '諢', '' => '諲', '' => '諴', '' => '諵', '' => '諝', '' => '謔', '' => '諤', '' => '諟', '' => '諰', '' => '諈', '' => '諞', '' => '諡', '' => '諨', '' => '諿', '' => '諯', '' => '諻', '' => '貑', '' => '貒', '' => '貐', '' => '賵', '' => '賮', '' => '賱', '' => '賰', '' => '賳', '' => '赬', '' => '赮', '' => '趥', '' => '趧', '' => '踳', '' => '踾', '' => '踸', '' => '蹀', '' => '蹅', '' => '踶', '' => '踼', '' => '踽', '' => '蹁', '' => '踰', '' => '踿', '' => '躽', '' => '輶', '' => '輮', '' => '輵', '' => '輲', '' => '輹', '' => '輷', '' => '輴', '' => '遶', '' => '遹', '' => '遻', '' => '邆', '' => '郺', '' => '鄳', '' => '鄵', '' => '鄶', '' => '醓', '' => '醐', '' => '醑', '' => '醍', '' => '醏', '' => '錧', '' => '錞', '' => '錈', '' => '錟', '' => '錆', '' => '錏', '' => '鍺', '' => '錸', '' => '錼', '' => '錛', '' => '錣', '' => '錒', '' => '錁', '' => '鍆', '' => '錭', '' => '錎', '' => '錍', '' => '鋋', '' => '錝', '' => '鋺', '' => '錥', '' => '錓', '' => '鋹', '' => '鋷', '' => '錴', '' => '錂', '' => '錤', '' => '鋿', '' => '錩', '' => '錹', '' => '錵', '' => '錪', '' => '錔', '' => '錌', '@' => '錋', 'A' => '鋾', 'B' => '錉', 'C' => '錀', 'D' => '鋻', 'E' => '錖', 'F' => '閼', 'G' => '闍', 'H' => '閾', 'I' => '閹', 'J' => '閺', 'K' => '閶', 'L' => '閿', 'M' => '閵', 'N' => '閽', 'O' => '隩', 'P' => '雔', 'Q' => '霋', 'R' => '霒', 'S' => '霐', 'T' => '鞙', 'U' => '鞗', 'V' => '鞔', 'W' => '韰', 'X' => '韸', 'Y' => '頵', 'Z' => '頯', '[' => '頲', '\\' => '餤', ']' => '餟', '^' => '餧', '_' => '餩', '`' => '馞', 'a' => '駮', 'b' => '駬', 'c' => '駥', 'd' => '駤', 'e' => '駰', 'f' => '駣', 'g' => '駪', 'h' => '駩', 'i' => '駧', 'j' => '骹', 'k' => '骿', 'l' => '骴', 'm' => '骻', 'n' => '髶', 'o' => '髺', 'p' => '髹', 'q' => '髷', 'r' => '鬳', 's' => '鮀', 't' => '鮅', 'u' => '鮇', 'v' => '魼', 'w' => '魾', 'x' => '魻', 'y' => '鮂', 'z' => '鮓', '{' => '鮒', '|' => '鮐', '}' => '魺', '~' => '鮕', '' => '魽', '' => '鮈', '' => '鴥', '' => '鴗', '' => '鴠', '' => '鴞', '' => '鴔', '' => '鴩', '' => '鴝', '' => '鴘', '' => '鴢', '' => '鴐', '' => '鴙', '' => '鴟', '' => '麈', '' => '麆', '' => '麇', '' => '麮', '' => '麭', '' => '黕', '' => '黖', '' => '黺', '' => '鼒', '' => '鼽', '' => '儦', '' => '儥', '' => '儢', '' => '儤', '' => '儠', '' => '儩', '' => '勴', '' => '嚓', '' => '嚌', '' => '嚍', '' => '嚆', '' => '嚄', '' => '嚃', '' => '噾', '' => '嚂', '' => '噿', '' => '嚁', '' => '壖', '' => '壔', '' => '壏', '' => '壒', '' => '嬭', '' => '嬥', '' => '嬲', '' => '嬣', '' => '嬬', '' => '嬧', '' => '嬦', '' => '嬯', '' => '嬮', '' => '孻', '' => '寱', '' => '寲', '' => '嶷', '' => '幬', '' => '幪', '' => '徾', '' => '徻', '' => '懃', '' => '憵', '' => '憼', '' => '懧', '' => '懠', '' => '懥', '' => '懤', '' => '懨', '' => '懞', '' => '擯', '' => '擩', '' => '擣', '' => '擫', '' => '擤', '' => '擨', '' => '斁', '' => '斀', '' => '斶', '' => '旚', '' => '曒', '' => '檍', '' => '檖', '' => '檁', '' => '檥', '' => '檉', '' => '檟', '' => '檛', '' => '檡', '' => '檞', '' => '檇', '' => '檓', '' => '檎', '@' => '檕', 'A' => '檃', 'B' => '檨', 'C' => '檤', 'D' => '檑', 'E' => '橿', 'F' => '檦', 'G' => '檚', 'H' => '檅', 'I' => '檌', 'J' => '檒', 'K' => '歛', 'L' => '殭', 'M' => '氉', 'N' => '濌', 'O' => '澩', 'P' => '濴', 'Q' => '濔', 'R' => '濣', 'S' => '濜', 'T' => '濭', 'U' => '濧', 'V' => '濦', 'W' => '濞', 'X' => '濲', 'Y' => '濝', 'Z' => '濢', '[' => '濨', '\\' => '燡', ']' => '燱', '^' => '燨', '_' => '燲', '`' => '燤', 'a' => '燰', 'b' => '燢', 'c' => '獳', 'd' => '獮', 'e' => '獯', 'f' => '璗', 'g' => '璲', 'h' => '璫', 'i' => '璐', 'j' => '璪', 'k' => '璭', 'l' => '璱', 'm' => '璥', 'n' => '璯', 'o' => '甐', 'p' => '甑', 'q' => '甒', 'r' => '甏', 's' => '疄', 't' => '癃', 'u' => '癈', 'v' => '癉', 'w' => '癇', 'x' => '皤', 'y' => '盩', 'z' => '瞵', '{' => '瞫', '|' => '瞲', '}' => '瞷', '~' => '瞶', '' => '瞴', '' => '瞱', '' => '瞨', '' => '矰', '' => '磳', '' => '磽', '' => '礂', '' => '磻', '' => '磼', '' => '磲', '' => '礅', '' => '磹', '' => '磾', '' => '礄', '' => '禫', '' => '禨', '' => '穜', '' => '穛', '' => '穖', '' => '穘', '' => '穔', '' => '穚', '' => '窾', '' => '竀', '' => '竁', '' => '簅', '' => '簏', '' => '篲', '' => '簀', '' => '篿', '' => '篻', '' => '簎', '' => '篴', '' => '簋', '' => '篳', '' => '簂', '' => '簉', '' => '簃', '' => '簁', '' => '篸', '' => '篽', '' => '簆', '' => '篰', '' => '篱', '' => '簐', '' => '簊', '' => '糨', '' => '縭', '' => '縼', '' => '繂', '' => '縳', '' => '顈', '' => '縸', '' => '縪', '' => '繉', '' => '繀', '' => '繇', '' => '縩', '' => '繌', '' => '縰', '' => '縻', '' => '縶', '' => '繄', '' => '縺', '' => '罅', '' => '罿', '' => '罾', '' => '罽', '' => '翴', '' => '翲', '' => '耬', '' => '膻', '' => '臄', '' => '臌', '' => '臊', '' => '臅', '' => '臇', '' => '膼', '' => '臩', '' => '艛', '' => '艚', '' => '艜', '' => '薃', '' => '薀', '' => '薏', '' => '薧', '' => '薕', '' => '薠', '' => '薋', '' => '薣', '' => '蕻', '' => '薤', '' => '薚', '' => '薞', '@' => '蕷', 'A' => '蕼', 'B' => '薉', 'C' => '薡', 'D' => '蕺', 'E' => '蕸', 'F' => '蕗', 'G' => '薎', 'H' => '薖', 'I' => '薆', 'J' => '薍', 'K' => '薙', 'L' => '薝', 'M' => '薁', 'N' => '薢', 'O' => '薂', 'P' => '薈', 'Q' => '薅', 'R' => '蕹', 'S' => '蕶', 'T' => '薘', 'U' => '薐', 'V' => '薟', 'W' => '虨', 'X' => '螾', 'Y' => '螪', 'Z' => '螭', '[' => '蟅', '\\' => '螰', ']' => '螬', '^' => '螹', '_' => '螵', '`' => '螼', 'a' => '螮', 'b' => '蟉', 'c' => '蟃', 'd' => '蟂', 'e' => '蟌', 'f' => '螷', 'g' => '螯', 'h' => '蟄', 'i' => '蟊', 'j' => '螴', 'k' => '螶', 'l' => '螿', 'm' => '螸', 'n' => '螽', 'o' => '蟞', 'p' => '螲', 'q' => '褵', 'r' => '褳', 's' => '褼', 't' => '褾', 'u' => '襁', 'v' => '襒', 'w' => '褷', 'x' => '襂', 'y' => '覭', 'z' => '覯', '{' => '覮', '|' => '觲', '}' => '觳', '~' => '謞', '' => '謘', '' => '謖', '' => '謑', '' => '謅', '' => '謋', '' => '謢', '' => '謏', '' => '謒', '' => '謕', '' => '謇', '' => '謍', '' => '謈', '' => '謆', '' => '謜', '' => '謓', '' => '謚', '' => '豏', '' => '豰', '' => '豲', '' => '豱', '' => '豯', '' => '貕', '' => '貔', '' => '賹', '' => '赯', '' => '蹎', '' => '蹍', '' => '蹓', '' => '蹐', '' => '蹌', '' => '蹇', '' => '轃', '' => '轀', '' => '邅', '' => '遾', '' => '鄸', '' => '醚', '' => '醢', '' => '醛', '' => '醙', '' => '醟', '' => '醡', '' => '醝', '' => '醠', '' => '鎡', '' => '鎃', '' => '鎯', '' => '鍤', '' => '鍖', '' => '鍇', '' => '鍼', '' => '鍘', '' => '鍜', '' => '鍶', '' => '鍉', '' => '鍐', '' => '鍑', '' => '鍠', '' => '鍭', '' => '鎏', '' => '鍌', '' => '鍪', '' => '鍹', '' => '鍗', '' => '鍕', '' => '鍒', '' => '鍏', '' => '鍱', '' => '鍷', '' => '鍻', '' => '鍡', '' => '鍞', '' => '鍣', '' => '鍧', '' => '鎀', '' => '鍎', '' => '鍙', '' => '闇', '' => '闀', '' => '闉', '' => '闃', '' => '闅', '' => '閷', '' => '隮', '' => '隰', '' => '隬', '' => '霠', '' => '霟', '' => '霘', '' => '霝', '' => '霙', '' => '鞚', '' => '鞡', '' => '鞜', '@' => '鞞', 'A' => '鞝', 'B' => '韕', 'C' => '韔', 'D' => '韱', 'E' => '顁', 'F' => '顄', 'G' => '顊', 'H' => '顉', 'I' => '顅', 'J' => '顃', 'K' => '餥', 'L' => '餫', 'M' => '餬', 'N' => '餪', 'O' => '餳', 'P' => '餲', 'Q' => '餯', 'R' => '餭', 'S' => '餱', 'T' => '餰', 'U' => '馘', 'V' => '馣', 'W' => '馡', 'X' => '騂', 'Y' => '駺', 'Z' => '駴', '[' => '駷', '\\' => '駹', ']' => '駸', '^' => '駶', '_' => '駻', '`' => '駽', 'a' => '駾', 'b' => '駼', 'c' => '騃', 'd' => '骾', 'e' => '髾', 'f' => '髽', 'g' => '鬁', 'h' => '髼', 'i' => '魈', 'j' => '鮚', 'k' => '鮨', 'l' => '鮞', 'm' => '鮛', 'n' => '鮦', 'o' => '鮡', 'p' => '鮥', 'q' => '鮤', 'r' => '鮆', 's' => '鮢', 't' => '鮠', 'u' => '鮯', 'v' => '鴳', 'w' => '鵁', 'x' => '鵧', 'y' => '鴶', 'z' => '鴮', '{' => '鴯', '|' => '鴱', '}' => '鴸', '~' => '鴰', '' => '鵅', '' => '鵂', '' => '鵃', '' => '鴾', '' => '鴷', '' => '鵀', '' => '鴽', '' => '翵', '' => '鴭', '' => '麊', '' => '麉', '' => '麍', '' => '麰', '' => '黈', '' => '黚', '' => '黻', '' => '黿', '' => '鼤', '' => '鼣', '' => '鼢', '' => '齔', '' => '龠', '' => '儱', '' => '儭', '' => '儮', '' => '嚘', '' => '嚜', '' => '嚗', '' => '嚚', '' => '嚝', '' => '嚙', '' => '奰', '' => '嬼', '' => '屩', '' => '屪', '' => '巀', '' => '幭', '' => '幮', '' => '懘', '' => '懟', '' => '懭', '' => '懮', '' => '懱', '' => '懪', '' => '懰', '' => '懫', '' => '懖', '' => '懩', '' => '擿', '' => '攄', '' => '擽', '' => '擸', '' => '攁', '' => '攃', '' => '擼', '' => '斔', '' => '旛', '' => '曚', '' => '曛', '' => '曘', '' => '櫅', '' => '檹', '' => '檽', '' => '櫡', '' => '櫆', '' => '檺', '' => '檶', '' => '檷', '' => '櫇', '' => '檴', '' => '檭', '' => '歞', '' => '毉', '' => '氋', '' => '瀇', '' => '瀌', '' => '瀍', '' => '瀁', '' => '瀅', '' => '瀔', '' => '瀎', '' => '濿', '' => '瀀', '' => '濻', '' => '瀦', '' => '濼', '' => '濷', '' => '瀊', '' => '爁', '' => '燿', '' => '燹', '' => '爃', '' => '燽', '' => '獶', '@' => '璸', 'A' => '瓀', 'B' => '璵', 'C' => '瓁', 'D' => '璾', 'E' => '璶', 'F' => '璻', 'G' => '瓂', 'H' => '甔', 'I' => '甓', 'J' => '癜', 'K' => '癤', 'L' => '癙', 'M' => '癐', 'N' => '癓', 'O' => '癗', 'P' => '癚', 'Q' => '皦', 'R' => '皽', 'S' => '盬', 'T' => '矂', 'U' => '瞺', 'V' => '磿', 'W' => '礌', 'X' => '礓', 'Y' => '礔', 'Z' => '礉', '[' => '礐', '\\' => '礒', ']' => '礑', '^' => '禭', '_' => '禬', '`' => '穟', 'a' => '簜', 'b' => '簩', 'c' => '簙', 'd' => '簠', 'e' => '簟', 'f' => '簭', 'g' => '簝', 'h' => '簦', 'i' => '簨', 'j' => '簢', 'k' => '簥', 'l' => '簰', 'm' => '繜', 'n' => '繐', 'o' => '繖', 'p' => '繣', 'q' => '繘', 'r' => '繢', 's' => '繟', 't' => '繑', 'u' => '繠', 'v' => '繗', 'w' => '繓', 'x' => '羵', 'y' => '羳', 'z' => '翷', '{' => '翸', '|' => '聵', '}' => '臑', '~' => '臒', '' => '臐', '' => '艟', '' => '艞', '' => '薴', '' => '藆', '' => '藀', '' => '藃', '' => '藂', '' => '薳', '' => '薵', '' => '薽', '' => '藇', '' => '藄', '' => '薿', '' => '藋', '' => '藎', '' => '藈', '' => '藅', '' => '薱', '' => '薶', '' => '藒', '' => '蘤', '' => '薸', '' => '薷', '' => '薾', '' => '虩', '' => '蟧', '' => '蟦', '' => '蟢', '' => '蟛', '' => '蟫', '' => '蟪', '' => '蟥', '' => '蟟', '' => '蟳', '' => '蟤', '' => '蟔', '' => '蟜', '' => '蟓', '' => '蟭', '' => '蟘', '' => '蟣', '' => '螤', '' => '蟗', '' => '蟙', '' => '蠁', '' => '蟴', '' => '蟨', '' => '蟝', '' => '襓', '' => '襋', '' => '襏', '' => '襌', '' => '襆', '' => '襐', '' => '襑', '' => '襉', '' => '謪', '' => '謧', '' => '謣', '' => '謳', '' => '謰', '' => '謵', '' => '譇', '' => '謯', '' => '謼', '' => '謾', '' => '謱', '' => '謥', '' => '謷', '' => '謦', '' => '謶', '' => '謮', '' => '謤', '' => '謻', '' => '謽', '' => '謺', '' => '豂', '' => '豵', '' => '貙', '' => '貘', '' => '貗', '' => '賾', '' => '贄', '' => '贂', '' => '贀', '' => '蹜', '' => '蹢', '' => '蹠', '' => '蹗', '' => '蹖', '' => '蹞', '' => '蹥', '' => '蹧', '@' => '蹛', 'A' => '蹚', 'B' => '蹡', 'C' => '蹝', 'D' => '蹩', 'E' => '蹔', 'F' => '轆', 'G' => '轇', 'H' => '轈', 'I' => '轋', 'J' => '鄨', 'K' => '鄺', 'L' => '鄻', 'M' => '鄾', 'N' => '醨', 'O' => '醥', 'P' => '醧', 'Q' => '醯', 'R' => '醪', 'S' => '鎵', 'T' => '鎌', 'U' => '鎒', 'V' => '鎷', 'W' => '鎛', 'X' => '鎝', 'Y' => '鎉', 'Z' => '鎧', '[' => '鎎', '\\' => '鎪', ']' => '鎞', '^' => '鎦', '_' => '鎕', '`' => '鎈', 'a' => '鎙', 'b' => '鎟', 'c' => '鎍', 'd' => '鎱', 'e' => '鎑', 'f' => '鎲', 'g' => '鎤', 'h' => '鎨', 'i' => '鎴', 'j' => '鎣', 'k' => '鎥', 'l' => '闒', 'm' => '闓', 'n' => '闑', 'o' => '隳', 'p' => '雗', 'q' => '雚', 'r' => '巂', 's' => '雟', 't' => '雘', 'u' => '雝', 'v' => '霣', 'w' => '霢', 'x' => '霥', 'y' => '鞬', 'z' => '鞮', '{' => '鞨', '|' => '鞫', '}' => '鞤', '~' => '鞪', '' => '鞢', '' => '鞥', '' => '韗', '' => '韙', '' => '韖', '' => '韘', '' => '韺', '' => '顐', '' => '顑', '' => '顒', '' => '颸', '' => '饁', '' => '餼', '' => '餺', '' => '騏', '' => '騋', '' => '騉', '' => '騍', '' => '騄', '' => '騑', '' => '騊', '' => '騅', '' => '騇', '' => '騆', '' => '髀', '' => '髜', '' => '鬈', '' => '鬄', '' => '鬅', '' => '鬩', '' => '鬵', '' => '魊', '' => '魌', '' => '魋', '' => '鯇', '' => '鯆', '' => '鯃', '' => '鮿', '' => '鯁', '' => '鮵', '' => '鮸', '' => '鯓', '' => '鮶', '' => '鯄', '' => '鮹', '' => '鮽', '' => '鵜', '' => '鵓', '' => '鵏', '' => '鵊', '' => '鵛', '' => '鵋', '' => '鵙', '' => '鵖', '' => '鵌', '' => '鵗', '' => '鵒', '' => '鵔', '' => '鵟', '' => '鵘', '' => '鵚', '' => '麎', '' => '麌', '' => '黟', '' => '鼁', '' => '鼀', '' => '鼖', '' => '鼥', '' => '鼫', '' => '鼪', '' => '鼩', '' => '鼨', '' => '齌', '' => '齕', '' => '儴', '' => '儵', '' => '劖', '' => '勷', '' => '厴', '' => '嚫', '' => '嚭', '' => '嚦', '' => '嚧', '' => '嚪', '' => '嚬', '' => '壚', '' => '壝', '' => '壛', '' => '夒', '' => '嬽', '' => '嬾', '' => '嬿', '' => '巃', '' => '幰', '@' => '徿', 'A' => '懻', 'B' => '攇', 'C' => '攐', 'D' => '攍', 'E' => '攉', 'F' => '攌', 'G' => '攎', 'H' => '斄', 'I' => '旞', 'J' => '旝', 'K' => '曞', 'L' => '櫧', 'M' => '櫠', 'N' => '櫌', 'O' => '櫑', 'P' => '櫙', 'Q' => '櫋', 'R' => '櫟', 'S' => '櫜', 'T' => '櫐', 'U' => '櫫', 'V' => '櫏', 'W' => '櫍', 'X' => '櫞', 'Y' => '歠', 'Z' => '殰', '[' => '氌', '\\' => '瀙', ']' => '瀧', '^' => '瀠', '_' => '瀖', '`' => '瀫', 'a' => '瀡', 'b' => '瀢', 'c' => '瀣', 'd' => '瀩', 'e' => '瀗', 'f' => '瀤', 'g' => '瀜', 'h' => '瀪', 'i' => '爌', 'j' => '爊', 'k' => '爇', 'l' => '爂', 'm' => '爅', 'n' => '犥', 'o' => '犦', 'p' => '犤', 'q' => '犣', 'r' => '犡', 's' => '瓋', 't' => '瓅', 'u' => '璷', 'v' => '瓃', 'w' => '甖', 'x' => '癠', 'y' => '矉', 'z' => '矊', '{' => '矄', '|' => '矱', '}' => '礝', '~' => '礛', '' => '礡', '' => '礜', '' => '礗', '' => '礞', '' => '禰', '' => '穧', '' => '穨', '' => '簳', '' => '簼', '' => '簹', '' => '簬', '' => '簻', '' => '糬', '' => '糪', '' => '繶', '' => '繵', '' => '繸', '' => '繰', '' => '繷', '' => '繯', '' => '繺', '' => '繲', '' => '繴', '' => '繨', '' => '罋', '' => '罊', '' => '羃', '' => '羆', '' => '羷', '' => '翽', '' => '翾', '' => '聸', '' => '臗', '' => '臕', '' => '艤', '' => '艡', '' => '艣', '' => '藫', '' => '藱', '' => '藭', '' => '藙', '' => '藡', '' => '藨', '' => '藚', '' => '藗', '' => '藬', '' => '藲', '' => '藸', '' => '藘', '' => '藟', '' => '藣', '' => '藜', '' => '藑', '' => '藰', '' => '藦', '' => '藯', '' => '藞', '' => '藢', '' => '蠀', '' => '蟺', '' => '蠃', '' => '蟶', '' => '蟷', '' => '蠉', '' => '蠌', '' => '蠋', '' => '蠆', '' => '蟼', '' => '蠈', '' => '蟿', '' => '蠊', '' => '蠂', '' => '襢', '' => '襚', '' => '襛', '' => '襗', '' => '襡', '' => '襜', '' => '襘', '' => '襝', '' => '襙', '' => '覈', '' => '覷', '' => '覶', '' => '觶', '' => '譐', '' => '譈', '' => '譊', '' => '譀', '' => '譓', '' => '譖', '' => '譔', '' => '譋', '' => '譕', '@' => '譑', 'A' => '譂', 'B' => '譒', 'C' => '譗', 'D' => '豃', 'E' => '豷', 'F' => '豶', 'G' => '貚', 'H' => '贆', 'I' => '贇', 'J' => '贉', 'K' => '趬', 'L' => '趪', 'M' => '趭', 'N' => '趫', 'O' => '蹭', 'P' => '蹸', 'Q' => '蹳', 'R' => '蹪', 'S' => '蹯', 'T' => '蹻', 'U' => '軂', 'V' => '轒', 'W' => '轑', 'X' => '轏', 'Y' => '轐', 'Z' => '轓', '[' => '辴', '\\' => '酀', ']' => '鄿', '^' => '醰', '_' => '醭', '`' => '鏞', 'a' => '鏇', 'b' => '鏏', 'c' => '鏂', 'd' => '鏚', 'e' => '鏐', 'f' => '鏹', 'g' => '鏬', 'h' => '鏌', 'i' => '鏙', 'j' => '鎩', 'k' => '鏦', 'l' => '鏊', 'm' => '鏔', 'n' => '鏮', 'o' => '鏣', 'p' => '鏕', 'q' => '鏄', 'r' => '鏎', 's' => '鏀', 't' => '鏒', 'u' => '鏧', 'v' => '镽', 'w' => '闚', 'x' => '闛', 'y' => '雡', 'z' => '霩', '{' => '霫', '|' => '霬', '}' => '霨', '~' => '霦', '' => '鞳', '' => '鞷', '' => '鞶', '' => '韝', '' => '韞', '' => '韟', '' => '顜', '' => '顙', '' => '顝', '' => '顗', '' => '颿', '' => '颽', '' => '颻', '' => '颾', '' => '饈', '' => '饇', '' => '饃', '' => '馦', '' => '馧', '' => '騚', '' => '騕', '' => '騥', '' => '騝', '' => '騤', '' => '騛', '' => '騢', '' => '騠', '' => '騧', '' => '騣', '' => '騞', '' => '騜', '' => '騔', '' => '髂', '' => '鬋', '' => '鬊', '' => '鬎', '' => '鬌', '' => '鬷', '' => '鯪', '' => '鯫', '' => '鯠', '' => '鯞', '' => '鯤', '' => '鯦', '' => '鯢', '' => '鯰', '' => '鯔', '' => '鯗', '' => '鯬', '' => '鯜', '' => '鯙', '' => '鯥', '' => '鯕', '' => '鯡', '' => '鯚', '' => '鵷', '' => '鶁', '' => '鶊', '' => '鶄', '' => '鶈', '' => '鵱', '' => '鶀', '' => '鵸', '' => '鶆', '' => '鶋', '' => '鶌', '' => '鵽', '' => '鵫', '' => '鵴', '' => '鵵', '' => '鵰', '' => '鵩', '' => '鶅', '' => '鵳', '' => '鵻', '' => '鶂', '' => '鵯', '' => '鵹', '' => '鵿', '' => '鶇', '' => '鵨', '' => '麔', '' => '麑', '' => '黀', '' => '黼', '' => '鼭', '' => '齀', '' => '齁', '' => '齍', '' => '齖', '' => '齗', '' => '齘', '' => '匷', '' => '嚲', '@' => '嚵', 'A' => '嚳', 'B' => '壣', 'C' => '孅', 'D' => '巆', 'E' => '巇', 'F' => '廮', 'G' => '廯', 'H' => '忀', 'I' => '忁', 'J' => '懹', 'K' => '攗', 'L' => '攖', 'M' => '攕', 'N' => '攓', 'O' => '旟', 'P' => '曨', 'Q' => '曣', 'R' => '曤', 'S' => '櫳', 'T' => '櫰', 'U' => '櫪', 'V' => '櫨', 'W' => '櫹', 'X' => '櫱', 'Y' => '櫮', 'Z' => '櫯', '[' => '瀼', '\\' => '瀵', ']' => '瀯', '^' => '瀷', '_' => '瀴', '`' => '瀱', 'a' => '灂', 'b' => '瀸', 'c' => '瀿', 'd' => '瀺', 'e' => '瀹', 'f' => '灀', 'g' => '瀻', 'h' => '瀳', 'i' => '灁', 'j' => '爓', 'k' => '爔', 'l' => '犨', 'm' => '獽', 'n' => '獼', 'o' => '璺', 'p' => '皫', 'q' => '皪', 'r' => '皾', 's' => '盭', 't' => '矌', 'u' => '矎', 'v' => '矏', 'w' => '矍', 'x' => '矲', 'y' => '礥', 'z' => '礣', '{' => '礧', '|' => '礨', '}' => '礤', '~' => '礩', '' => '禲', '' => '穮', '' => '穬', '' => '穭', '' => '竷', '' => '籉', '' => '籈', '' => '籊', '' => '籇', '' => '籅', '' => '糮', '' => '繻', '' => '繾', '' => '纁', '' => '纀', '' => '羺', '' => '翿', '' => '聹', '' => '臛', '' => '臙', '' => '舋', '' => '艨', '' => '艩', '' => '蘢', '' => '藿', '' => '蘁', '' => '藾', '' => '蘛', '' => '蘀', '' => '藶', '' => '蘄', '' => '蘉', '' => '蘅', '' => '蘌', '' => '藽', '' => '蠙', '' => '蠐', '' => '蠑', '' => '蠗', '' => '蠓', '' => '蠖', '' => '襣', '' => '襦', '' => '覹', '' => '觷', '' => '譠', '' => '譪', '' => '譝', '' => '譨', '' => '譣', '' => '譥', '' => '譧', '' => '譭', '' => '趮', '' => '躆', '' => '躈', '' => '躄', '' => '轙', '' => '轖', '' => '轗', '' => '轕', '' => '轘', '' => '轚', '' => '邍', '' => '酃', '' => '酁', '' => '醷', '' => '醵', '' => '醲', '' => '醳', '' => '鐋', '' => '鐓', '' => '鏻', '' => '鐠', '' => '鐏', '' => '鐔', '' => '鏾', '' => '鐕', '' => '鐐', '' => '鐨', '' => '鐙', '' => '鐍', '' => '鏵', '' => '鐀', '' => '鏷', '' => '鐇', '' => '鐎', '' => '鐖', '' => '鐒', '' => '鏺', '' => '鐉', '' => '鏸', '' => '鐊', '' => '鏿', '@' => '鏼', 'A' => '鐌', 'B' => '鏶', 'C' => '鐑', 'D' => '鐆', 'E' => '闞', 'F' => '闠', 'G' => '闟', 'H' => '霮', 'I' => '霯', 'J' => '鞹', 'K' => '鞻', 'L' => '韽', 'M' => '韾', 'N' => '顠', 'O' => '顢', 'P' => '顣', 'Q' => '顟', 'R' => '飁', 'S' => '飂', 'T' => '饐', 'U' => '饎', 'V' => '饙', 'W' => '饌', 'X' => '饋', 'Y' => '饓', 'Z' => '騲', '[' => '騴', '\\' => '騱', ']' => '騬', '^' => '騪', '_' => '騶', '`' => '騩', 'a' => '騮', 'b' => '騸', 'c' => '騭', 'd' => '髇', 'e' => '髊', 'f' => '髆', 'g' => '鬐', 'h' => '鬒', 'i' => '鬑', 'j' => '鰋', 'k' => '鰈', 'l' => '鯷', 'm' => '鰅', 'n' => '鰒', 'o' => '鯸', 'p' => '鱀', 'q' => '鰇', 'r' => '鰎', 's' => '鰆', 't' => '鰗', 'u' => '鰔', 'v' => '鰉', 'w' => '鶟', 'x' => '鶙', 'y' => '鶤', 'z' => '鶝', '{' => '鶒', '|' => '鶘', '}' => '鶐', '~' => '鶛', '' => '鶠', '' => '鶔', '' => '鶜', '' => '鶪', '' => '鶗', '' => '鶡', '' => '鶚', '' => '鶢', '' => '鶨', '' => '鶞', '' => '鶣', '' => '鶿', '' => '鶩', '' => '鶖', '' => '鶦', '' => '鶧', '' => '麙', '' => '麛', '' => '麚', '' => '黥', '' => '黤', '' => '黧', '' => '黦', '' => '鼰', '' => '鼮', '' => '齛', '' => '齠', '' => '齞', '' => '齝', '' => '齙', '' => '龑', '' => '儺', '' => '儹', '' => '劘', '' => '劗', '' => '囃', '' => '嚽', '' => '嚾', '' => '孈', '' => '孇', '' => '巋', '' => '巏', '' => '廱', '' => '懽', '' => '攛', '' => '欂', '' => '櫼', '' => '欃', '' => '櫸', '' => '欀', '' => '灃', '' => '灄', '' => '灊', '' => '灈', '' => '灉', '' => '灅', '' => '灆', '' => '爝', '' => '爚', '' => '爙', '' => '獾', '' => '甗', '' => '癪', '' => '矐', '' => '礭', '' => '礱', '' => '礯', '' => '籔', '' => '籓', '' => '糲', '' => '纊', '' => '纇', '' => '纈', '' => '纋', '' => '纆', '' => '纍', '' => '罍', '' => '羻', '' => '耰', '' => '臝', '' => '蘘', '' => '蘪', '' => '蘦', '' => '蘟', '' => '蘣', '' => '蘜', '' => '蘙', '' => '蘧', '' => '蘮', '' => '蘡', '' => '蘠', '' => '蘩', '' => '蘞', '' => '蘥', '@' => '蠩', 'A' => '蠝', 'B' => '蠛', 'C' => '蠠', 'D' => '蠤', 'E' => '蠜', 'F' => '蠫', 'G' => '衊', 'H' => '襭', 'I' => '襩', 'J' => '襮', 'K' => '襫', 'L' => '觺', 'M' => '譹', 'N' => '譸', 'O' => '譅', 'P' => '譺', 'Q' => '譻', 'R' => '贐', 'S' => '贔', 'T' => '趯', 'U' => '躎', 'V' => '躌', 'W' => '轞', 'X' => '轛', 'Y' => '轝', 'Z' => '酆', '[' => '酄', '\\' => '酅', ']' => '醹', '^' => '鐿', '_' => '鐻', '`' => '鐶', 'a' => '鐩', 'b' => '鐽', 'c' => '鐼', 'd' => '鐰', 'e' => '鐹', 'f' => '鐪', 'g' => '鐷', 'h' => '鐬', 'i' => '鑀', 'j' => '鐱', 'k' => '闥', 'l' => '闤', 'm' => '闣', 'n' => '霵', 'o' => '霺', 'p' => '鞿', 'q' => '韡', 'r' => '顤', 's' => '飉', 't' => '飆', 'u' => '飀', 'v' => '饘', 'w' => '饖', 'x' => '騹', 'y' => '騽', 'z' => '驆', '{' => '驄', '|' => '驂', '}' => '驁', '~' => '騺', '' => '騿', '' => '髍', '' => '鬕', '' => '鬗', '' => '鬘', '' => '鬖', '' => '鬺', '' => '魒', '' => '鰫', '' => '鰝', '' => '鰜', '' => '鰬', '' => '鰣', '' => '鰨', '' => '鰩', '' => '鰤', '' => '鰡', '' => '鶷', '' => '鶶', '' => '鶼', '' => '鷁', '' => '鷇', '' => '鷊', '' => '鷏', '' => '鶾', '' => '鷅', '' => '鷃', '' => '鶻', '' => '鶵', '' => '鷎', '' => '鶹', '' => '鶺', '' => '鶬', '' => '鷈', '' => '鶱', '' => '鶭', '' => '鷌', '' => '鶳', '' => '鷍', '' => '鶲', '' => '鹺', '' => '麜', '' => '黫', '' => '黮', '' => '黭', '' => '鼛', '' => '鼘', '' => '鼚', '' => '鼱', '' => '齎', '' => '齥', '' => '齤', '' => '龒', '' => '亹', '' => '囆', '' => '囅', '' => '囋', '' => '奱', '' => '孋', '' => '孌', '' => '巕', '' => '巑', '' => '廲', '' => '攡', '' => '攠', '' => '攦', '' => '攢', '' => '欋', '' => '欈', '' => '欉', '' => '氍', '' => '灕', '' => '灖', '' => '灗', '' => '灒', '' => '爞', '' => '爟', '' => '犩', '' => '獿', '' => '瓘', '' => '瓕', '' => '瓙', '' => '瓗', '' => '癭', '' => '皭', '' => '礵', '' => '禴', '' => '穰', '' => '穱', '' => '籗', '' => '籜', '' => '籙', '' => '籛', '' => '籚', '@' => '糴', 'A' => '糱', 'B' => '纑', 'C' => '罏', 'D' => '羇', 'E' => '臞', 'F' => '艫', 'G' => '蘴', 'H' => '蘵', 'I' => '蘳', 'J' => '蘬', 'K' => '蘲', 'L' => '蘶', 'M' => '蠬', 'N' => '蠨', 'O' => '蠦', 'P' => '蠪', 'Q' => '蠥', 'R' => '襱', 'S' => '覿', 'T' => '覾', 'U' => '觻', 'V' => '譾', 'W' => '讄', 'X' => '讂', 'Y' => '讆', 'Z' => '讅', '[' => '譿', '\\' => '贕', ']' => '躕', '^' => '躔', '_' => '躚', '`' => '躒', 'a' => '躐', 'b' => '躖', 'c' => '躗', 'd' => '轠', 'e' => '轢', 'f' => '酇', 'g' => '鑌', 'h' => '鑐', 'i' => '鑊', 'j' => '鑋', 'k' => '鑏', 'l' => '鑇', 'm' => '鑅', 'n' => '鑈', 'o' => '鑉', 'p' => '鑆', 'q' => '霿', 'r' => '韣', 's' => '顪', 't' => '顩', 'u' => '飋', 'v' => '饔', 'w' => '饛', 'x' => '驎', 'y' => '驓', 'z' => '驔', '{' => '驌', '|' => '驏', '}' => '驈', '~' => '驊', '' => '驉', '' => '驒', '' => '驐', '' => '髐', '' => '鬙', '' => '鬫', '' => '鬻', '' => '魖', '' => '魕', '' => '鱆', '' => '鱈', '' => '鰿', '' => '鱄', '' => '鰹', '' => '鰳', '' => '鱁', '' => '鰼', '' => '鰷', '' => '鰴', '' => '鰲', '' => '鰽', '' => '鰶', '' => '鷛', '' => '鷒', '' => '鷞', '' => '鷚', '' => '鷋', '' => '鷐', '' => '鷜', '' => '鷑', '' => '鷟', '' => '鷩', '' => '鷙', '' => '鷘', '' => '鷖', '' => '鷵', '' => '鷕', '' => '鷝', '' => '麶', '' => '黰', '' => '鼵', '' => '鼳', '' => '鼲', '' => '齂', '' => '齫', '' => '龕', '' => '龢', '' => '儽', '' => '劙', '' => '壨', '' => '壧', '' => '奲', '' => '孍', '' => '巘', '' => '蠯', '' => '彏', '' => '戁', '' => '戃', '' => '戄', '' => '攩', '' => '攥', '' => '斖', '' => '曫', '' => '欑', '' => '欒', '' => '欏', '' => '毊', '' => '灛', '' => '灚', '' => '爢', '' => '玂', '' => '玁', '' => '玃', '' => '癰', '' => '矔', '' => '籧', '' => '籦', '' => '纕', '' => '艬', '' => '蘺', '' => '虀', '' => '蘹', '' => '蘼', '' => '蘱', '' => '蘻', '' => '蘾', '' => '蠰', '' => '蠲', '' => '蠮', '' => '蠳', '' => '襶', '' => '襴', '' => '襳', '' => '觾', '@' => '讌', 'A' => '讎', 'B' => '讋', 'C' => '讈', 'D' => '豅', 'E' => '贙', 'F' => '躘', 'G' => '轤', 'H' => '轣', 'I' => '醼', 'J' => '鑢', 'K' => '鑕', 'L' => '鑝', 'M' => '鑗', 'N' => '鑞', 'O' => '韄', 'P' => '韅', 'Q' => '頀', 'R' => '驖', 'S' => '驙', 'T' => '鬞', 'U' => '鬟', 'V' => '鬠', 'W' => '鱒', 'X' => '鱘', 'Y' => '鱐', 'Z' => '鱊', '[' => '鱍', '\\' => '鱋', ']' => '鱕', '^' => '鱙', '_' => '鱌', '`' => '鱎', 'a' => '鷻', 'b' => '鷷', 'c' => '鷯', 'd' => '鷣', 'e' => '鷫', 'f' => '鷸', 'g' => '鷤', 'h' => '鷶', 'i' => '鷡', 'j' => '鷮', 'k' => '鷦', 'l' => '鷲', 'm' => '鷰', 'n' => '鷢', 'o' => '鷬', 'p' => '鷴', 'q' => '鷳', 'r' => '鷨', 's' => '鷭', 't' => '黂', 'u' => '黐', 'v' => '黲', 'w' => '黳', 'x' => '鼆', 'y' => '鼜', 'z' => '鼸', '{' => '鼷', '|' => '鼶', '}' => '齃', '~' => '齏', '' => '齱', '' => '齰', '' => '齮', '' => '齯', '' => '囓', '' => '囍', '' => '孎', '' => '屭', '' => '攭', '' => '曭', '' => '曮', '' => '欓', '' => '灟', '' => '灡', '' => '灝', '' => '灠', '' => '爣', '' => '瓛', '' => '瓥', '' => '矕', '' => '礸', '' => '禷', '' => '禶', '' => '籪', '' => '纗', '' => '羉', '' => '艭', '' => '虃', '' => '蠸', '' => '蠷', '' => '蠵', '' => '衋', '' => '讔', '' => '讕', '' => '躞', '' => '躟', '' => '躠', '' => '躝', '' => '醾', '' => '醽', '' => '釂', '' => '鑫', '' => '鑨', '' => '鑩', '' => '雥', '' => '靆', '' => '靃', '' => '靇', '' => '韇', '' => '韥', '' => '驞', '' => '髕', '' => '魙', '' => '鱣', '' => '鱧', '' => '鱦', '' => '鱢', '' => '鱞', '' => '鱠', '' => '鸂', '' => '鷾', '' => '鸇', '' => '鸃', '' => '鸆', '' => '鸅', '' => '鸀', '' => '鸁', '' => '鸉', '' => '鷿', '' => '鷽', '' => '鸄', '' => '麠', '' => '鼞', '' => '齆', '' => '齴', '' => '齵', '' => '齶', '' => '囔', '' => '攮', '' => '斸', '' => '欘', '' => '欙', '' => '欗', '' => '欚', '' => '灢', '' => '爦', '' => '犪', '' => '矘', '' => '矙', '' => '礹', '' => '籩', '' => '籫', '' => '糶', '' => '纚', '@' => '纘', 'A' => '纛', 'B' => '纙', 'C' => '臠', 'D' => '臡', 'E' => '虆', 'F' => '虇', 'G' => '虈', 'H' => '襹', 'I' => '襺', 'J' => '襼', 'K' => '襻', 'L' => '觿', 'M' => '讘', 'N' => '讙', 'O' => '躥', 'P' => '躤', 'Q' => '躣', 'R' => '鑮', 'S' => '鑭', 'T' => '鑯', 'U' => '鑱', 'V' => '鑳', 'W' => '靉', 'X' => '顲', 'Y' => '饟', 'Z' => '鱨', '[' => '鱮', '\\' => '鱭', ']' => '鸋', '^' => '鸍', '_' => '鸐', '`' => '鸏', 'a' => '鸒', 'b' => '鸑', '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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', '' => '', ' ' => ' ', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', '\'' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', 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; 'μ', '¼' => ' 1⁄4 ', '½' => ' 1⁄2 ', '¾' => ' 3⁄4 ', 'IJ' => 'IJ', 'ij' => 'ij', 'Ŀ' => 'L·', 'ŀ' => 'l·', 'ʼn' => 'ʼn', 'ſ' => 's', 'DŽ' => 'DŽ', 'Dž' => 'Dž', 'dž' => 'dž', 'LJ' => 'LJ', 'Lj' => 'Lj', 'lj' => 'lj', 'NJ' => 'NJ', 'Nj' => 'Nj', 'nj' => 'nj', 'DZ' => 'DZ', 'Dz' => 'Dz', 'dz' => 'dz', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϒ' => 'Υ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϲ' => 'ς', 'ϴ' => 'Θ', 'ϵ' => 'ε', 'Ϲ' => 'Σ', 'և' => 'եւ', 'ٵ' => 'اٴ', 'ٶ' => 'وٴ', 'ٷ' => 'ۇٴ', 'ٸ' => 'يٴ', 'ำ' => 'ํา', 'ຳ' => 'ໍາ', 'ໜ' => 'ຫນ', 'ໝ' => 'ຫມ', 'ཷ' => 'ྲཱྀ', 'ཹ' => 'ླཱྀ', 'ẚ' => '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' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'ſt', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ', 'ﬠ' => 'ע', 'ﬡ' => 'א', 'ﬢ' => 'ד', 'ﬣ' => 'ה', 'ﬤ' => 'כ', 'ﬥ' => 'ל', 'ﬦ' => 'ם', 'ﬧ' => 'ר', 'ﬨ' => 'ת', '﬩' => '+', 'ﭏ' => 'אל', '﹉' => '‾', '﹊' => '‾', '﹋' => '‾', '﹌' => '‾', '﹍' => '_', '﹎' => '_', '﹏' => '_', '﹐' => ',', '﹑' => '、', '﹒' => '.', '﹔' => ';', '﹕' => ':', '﹖' => '?', '﹗' => '!', '﹘' => '—', '﹙' => '(', '﹚' => ')', '﹛' => '{', '﹜' => '}', '﹝' => '〔', '﹞' => '〕', '﹟' => '#', '﹠' => '&', '﹡' => '*', '﹢' => '+', '﹣' => '-', '﹤' => '<', '﹥' => '>', '﹦' => '=', '﹨' => '\\', '﹩' => '$', '﹪' => '%', '﹫' => '@', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', ''' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', '0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9', ':' => ':', ';' => ';', '<' => '<', '=' => '=', '>' => '>', '?' => '?', '@' => '@', 'A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D', 'E' => 'E', 'F' => 'F', 'G' => 'G', 'H' => 'H', 'I' => 'I', 'J' => 'J', 'K' => 'K', 'L' => 'L', 'M' => 'M', 'N' => 'N', 'O' => 'O', 'P' => 'P', 'Q' => 'Q', 'R' => 'R', 'S' => 'S', 'T' => 'T', 'U' => 'U', 'V' => 'V', 'W' => 'W', 'X' => 'X', 'Y' => 'Y', 'Z' => 'Z', '[' => '[', '\' => '\\', ']' => ']', '^' => '^', '_' => '_', '`' => '`', 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd', 'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'h', 'i' => 'i', 'j' => 'j', 'k' => 'k', 'l' => 'l', 'm' => 'm', 'n' => 'n', 'o' => 'o', 'p' => 'p', 'q' => 'q', 'r' => 'r', 's' => 's', 't' => 't', 'u' => 'u', 'v' => 'v', 'w' => 'w', 'x' => 'x', 'y' => 'y', 'z' => 'z', '{' => '{', '|' => '|', '}' => '}', '~' => '~', '⦅' => '⦅', '⦆' => '⦆', '。' => '。', '「' => '「', '」' => '」', '、' => '、', '・' => '・', 'ヲ' => 'ヲ', 'ァ' => 'ァ', 'ィ' => 'ィ', 'ゥ' => 'ゥ', 'ェ' => 'ェ', 'ォ' => 'ォ', 'ャ' => 'ャ', 'ュ' => 'ュ', 'ョ' => 'ョ', 'ッ' => 'ッ', 'ー' => 'ー', 'ア' => 'ア', 'イ' => 'イ', 'ウ' => 'ウ', 'エ' => 'エ', 'オ' => 'オ', 'カ' => 'カ', 'キ' => 'キ', 'ク' => 'ク', 'ケ' => 'ケ', 'コ' => 'コ', 'サ' => 'サ', 'シ' => 'シ', 'ス' => 'ス', 'セ' => 'セ', 'ソ' => 'ソ', 'タ' => 'タ', 'チ' => 'チ', 'ツ' => 'ツ', 'テ' => 'テ', 'ト' => 'ト', 'ナ' => 'ナ', 'ニ' => 'ニ', 'ヌ' => 'ヌ', 'ネ' => 'ネ', 'ノ' => 'ノ', 'ハ' => 'ハ', 'ヒ' => 'ヒ', 'フ' => 'フ', 'ヘ' => 'ヘ', 'ホ' => 'ホ', 'マ' => 'マ', 'ミ' => 'ミ', 'ム' => 'ム', 'メ' => 'メ', 'モ' => 'モ', 'ヤ' => 'ヤ', 'ユ' => 'ユ', 'ヨ' => 'ヨ', 'ラ' => 'ラ', 'リ' => 'リ', 'ル' => 'ル', 'レ' => 'レ', 'ロ' => 'ロ', 'ワ' => 'ワ', 'ン' => 'ン', '゙' => '゙', '゚' => '゚', 'ᅠ' => 'ㅤ', 'ᄀ' => 'ㄱ', 'ᄁ' => 'ㄲ', 'ᆪ' => 'ㄳ', 'ᄂ' => 'ㄴ', 'ᆬ' => 'ㄵ', 'ᆭ' => 'ㄶ', 'ᄃ' => 'ㄷ', 'ᄄ' => 'ㄸ', 'ᄅ' => 'ㄹ', 'ᆰ' => 'ㄺ', 'ᆱ' => 'ㄻ', 'ᆲ' => 'ㄼ', 'ᆳ' => 'ㄽ', 'ᆴ' => 'ㄾ', 'ᆵ' => 'ㄿ', 'ᄚ' => 'ㅀ', 'ᄆ' => 'ㅁ', 'ᄇ' => 'ㅂ', 'ᄈ' => 'ㅃ', 'ᄡ' => 'ㅄ', 'ᄉ' => 'ㅅ', 'ᄊ' => 'ㅆ', 'ᄋ' => 'ㅇ', 'ᄌ' => 'ㅈ', 'ᄍ' => 'ㅉ', 'ᄎ' => 'ㅊ', 'ᄏ' => 'ㅋ', 'ᄐ' => 'ㅌ', 'ᄑ' => 'ㅍ', 'ᄒ' => 'ㅎ', 'ᅡ' => 'ㅏ', 'ᅢ' => 'ㅐ', 'ᅣ' => 'ㅑ', 'ᅤ' => 'ㅒ', 'ᅥ' => 'ㅓ', 'ᅦ' => 'ㅔ', 'ᅧ' => 'ㅕ', 'ᅨ' => 'ㅖ', 'ᅩ' => 'ㅗ', 'ᅪ' => 'ㅘ', 'ᅫ' => 'ㅙ', 'ᅬ' => 'ㅚ', 'ᅭ' => 'ㅛ', 'ᅮ' => 'ㅜ', 'ᅯ' => 'ㅝ', 'ᅰ' => 'ㅞ', 'ᅱ' => 'ㅟ', 'ᅲ' => 'ㅠ', 'ᅳ' => 'ㅡ', 'ᅴ' => 'ㅢ', 'ᅵ' => 'ㅣ', '¢' => '¢', '£' => '£', '¬' => '¬', ' ̄' => '¯', '¦' => '¦', '¥' => '¥', '₩' => '₩', '│' => '│', '←' => '←', '↑' => '↑', '→' => '→', '↓' => '↓', '■' => '■', '○' => '○', '𝐀' => 'A', '𝐁' => 'B', '𝐂' => 'C', '𝐃' => 'D', '𝐄' => 'E', '𝐅' => 'F', '𝐆' => 'G', '𝐇' => 'H', '𝐈' => 'I', '𝐉' => 'J', '𝐊' => 'K', '𝐋' => 'L', '𝐌' => 'M', '𝐍' => 'N', '𝐎' => 'O', '𝐏' => 'P', '𝐐' => 'Q', '𝐑' => 'R', '𝐒' => 'S', '𝐓' => 'T', '𝐔' => 'U', '𝐕' => 'V', '𝐖' => 'W', '𝐗' => 'X', '𝐘' => 'Y', '𝐙' => 'Z', '𝐚' => 'a', '𝐛' => 'b', '𝐜' => 'c', '𝐝' => 'd', '𝐞' => 'e', '𝐟' => 'f', '𝐠' => 'g', '𝐡' => 'h', '𝐢' => 'i', '𝐣' => 'j', '𝐤' => 'k', '𝐥' => 'l', '𝐦' => 'm', '𝐧' => 'n', '𝐨' => 'o', '𝐩' => 'p', '𝐪' => 'q', '𝐫' => 'r', '𝐬' => 's', '𝐭' => 't', '𝐮' => 'u', '𝐯' => 'v', '𝐰' => 'w', '𝐱' => 'x', '𝐲' => 'y', '𝐳' => 'z', '𝐴' => 'A', '𝐵' => 'B', '𝐶' => 'C', '𝐷' => 'D', '𝐸' => 'E', '𝐹' => 'F', '𝐺' => 'G', '𝐻' => 'H', '𝐼' => 'I', '𝐽' => 'J', '𝐾' => 'K', '𝐿' => 'L', '𝑀' => 'M', '𝑁' => 'N', '𝑂' => 'O', '𝑃' => 'P', '𝑄' => 'Q', '𝑅' => 'R', '𝑆' => 'S', '𝑇' => 'T', '𝑈' => 'U', '𝑉' => 'V', '𝑊' => 'W', '𝑋' => 'X', '𝑌' => 'Y', '𝑍' => 'Z', '𝑎' => 'a', '𝑏' => 'b', '𝑐' => 'c', '𝑑' => 'd', '𝑒' => 'e', '𝑓' => 'f', '𝑔' => 'g', '𝑖' => 'i', '𝑗' => 'j', '𝑘' => 'k', '𝑙' => 'l', '𝑚' => 'm', '𝑛' => 'n', '𝑜' => 'o', '𝑝' => 'p', '𝑞' => 'q', '𝑟' => 'r', '𝑠' => 's', '𝑡' => 't', '𝑢' => 'u', '𝑣' => 'v', '𝑤' => 'w', '𝑥' => 'x', '𝑦' => 'y', '𝑧' => 'z', '𝑨' => 'A', '𝑩' => 'B', '𝑪' => 'C', '𝑫' => 'D', '𝑬' => 'E', '𝑭' => 'F', '𝑮' => 'G', '𝑯' => 'H', '𝑰' => 'I', '𝑱' => 'J', '𝑲' => 'K', '𝑳' => 'L', '𝑴' => 'M', '𝑵' => 'N', '𝑶' => 'O', '𝑷' => 'P', '𝑸' => 'Q', '𝑹' => 'R', '𝑺' => 'S', '𝑻' => 'T', '𝑼' => 'U', '𝑽' => 'V', '𝑾' => 'W', '𝑿' => 'X', '𝒀' => 'Y', '𝒁' => 'Z', '𝒂' => 'a', '𝒃' => 'b', '𝒄' => 'c', '𝒅' => 'd', '𝒆' => 'e', '𝒇' => 'f', '𝒈' => 'g', '𝒉' => 'h', '𝒊' => 'i', '𝒋' => 'j', '𝒌' => 'k', '𝒍' => 'l', '𝒎' => 'm', '𝒏' => 'n', '𝒐' => 'o', '𝒑' => 'p', '𝒒' => 'q', '𝒓' => 'r', '𝒔' => 's', '𝒕' => 't', '𝒖' => 'u', '𝒗' => 'v', '𝒘' => 'w', '𝒙' => 'x', '𝒚' => 'y', '𝒛' => 'z', '𝒜' => 'A', '𝒞' => 'C', '𝒟' => 'D', '𝒢' => 'G', '𝒥' => 'J', '𝒦' => 'K', '𝒩' => 'N', '𝒪' => 'O', '𝒫' => 'P', '𝒬' => 'Q', '𝒮' => 'S', '𝒯' => 'T', '𝒰' => 'U', '𝒱' => 'V', '𝒲' => 'W', '𝒳' => 'X', '𝒴' => 'Y', '𝒵' => 'Z', '𝒶' => 'a', '𝒷' => 'b', '𝒸' => 'c', '𝒹' => 'd', '𝒻' => 'f', '𝒽' => 'h', '𝒾' => 'i', '𝒿' => 'j', '𝓀' => 'k', '𝓁' => 'l', '𝓂' => 'm', '𝓃' => 'n', '𝓅' => 'p', '𝓆' => 'q', '𝓇' => 'r', '𝓈' => 's', '𝓉' => 't', '𝓊' => 'u', '𝓋' => 'v', '𝓌' => 'w', '𝓍' => 'x', '𝓎' => 'y', '𝓏' => 'z', '𝓐' => 'A', '𝓑' => 'B', '𝓒' => 'C', '𝓓' => 'D', '𝓔' => 'E', '𝓕' => 'F', '𝓖' => 'G', '𝓗' => 'H', '𝓘' => 'I', '𝓙' => 'J', '𝓚' => 'K', '𝓛' => 'L', '𝓜' => 'M', '𝓝' => 'N', '𝓞' => 'O', '𝓟' => 'P', '𝓠' => 'Q', '𝓡' => 'R', '𝓢' => 'S', '𝓣' => 'T', '𝓤' => 'U', '𝓥' => 'V', '𝓦' => 'W', '𝓧' => 'X', '𝓨' => 'Y', '𝓩' => 'Z', '𝓪' => 'a', '𝓫' => 'b', '𝓬' => 'c', '𝓭' => 'd', '𝓮' => 'e', '𝓯' => 'f', '𝓰' => 'g', '𝓱' => 'h', '𝓲' => 'i', '𝓳' => 'j', '𝓴' => 'k', '𝓵' => 'l', '𝓶' => 'm', '𝓷' => 'n', '𝓸' => 'o', '𝓹' => 'p', '𝓺' => 'q', '𝓻' => 'r', '𝓼' => 's', '𝓽' => 't', '𝓾' => 'u', '𝓿' => 'v', '𝔀' => 'w', '𝔁' => 'x', '𝔂' => 'y', '𝔃' => 'z', '𝔄' => 'A', '𝔅' => 'B', '𝔇' => 'D', '𝔈' => 'E', '𝔉' => 'F', '𝔊' => 'G', '𝔍' => 'J', '𝔎' => 'K', '𝔏' => 'L', '𝔐' => 'M', '𝔑' => 'N', '𝔒' => 'O', '𝔓' => 'P', '𝔔' => 'Q', '𝔖' => 'S', '𝔗' => 'T', '𝔘' => 'U', '𝔙' => 'V', '𝔚' => 'W', '𝔛' => 'X', '𝔜' => 'Y', '𝔞' => 'a', '𝔟' => 'b', '𝔠' => 'c', '𝔡' => 'd', '𝔢' => 'e', '𝔣' => 'f', '𝔤' => 'g', '𝔥' => 'h', '𝔦' => 'i', '𝔧' => 'j', '𝔨' => 'k', '𝔩' => 'l', '𝔪' => 'm', '𝔫' => 'n', '𝔬' => 'o', '𝔭' => 'p', '𝔮' => 'q', '𝔯' => 'r', '𝔰' => 's', '𝔱' => 't', '𝔲' => 'u', '𝔳' => 'v', '𝔴' => 'w', '𝔵' => 'x', '𝔶' => 'y', '𝔷' => 'z', '𝔸' => 'A', '𝔹' => 'B', '𝔻' => 'D', '𝔼' => 'E', '𝔽' => 'F', '𝔾' => 'G', '𝕀' => 'I', '𝕁' => 'J', '𝕂' => 'K', '𝕃' => 'L', '𝕄' => 'M', '𝕆' => 'O', '𝕊' => 'S', '𝕋' => 'T', '𝕌' => 'U', '𝕍' => 'V', '𝕎' => 'W', '𝕏' => 'X', '𝕐' => 'Y', '𝕒' => 'a', '𝕓' => 'b', '𝕔' => 'c', '𝕕' => 'd', '𝕖' => 'e', '𝕗' => 'f', '𝕘' => 'g', '𝕙' => 'h', '𝕚' => 'i', '𝕛' => 'j', '𝕜' => 'k', '𝕝' => 'l', '𝕞' => 'm', '𝕟' => 'n', '𝕠' => 'o', '𝕡' => 'p', '𝕢' => 'q', '𝕣' => 'r', '𝕤' => 's', '𝕥' => 't', '𝕦' => 'u', '𝕧' => 'v', '𝕨' => 'w', '𝕩' => 'x', '𝕪' => 'y', '𝕫' => 'z', '𝕬' => 'A', '𝕭' => 'B', '𝕮' => 'C', '𝕯' => 'D', '𝕰' => 'E', '𝕱' => 'F', '𝕲' => 'G', '𝕳' => 'H', '𝕴' => 'I', '𝕵' => 'J', '𝕶' => 'K', '𝕷' => 'L', '𝕸' => 'M', '𝕹' => 'N', '𝕺' => 'O', '𝕻' => 'P', '𝕼' => 'Q', '𝕽' => 'R', '𝕾' => 'S', '𝕿' => 'T', '𝖀' => 'U', '𝖁' => 'V', '𝖂' => 'W', '𝖃' => 'X', '𝖄' => 'Y', '𝖅' => 'Z', '𝖆' => 'a', '𝖇' => 'b', '𝖈' => 'c', '𝖉' => 'd', '𝖊' => 'e', '𝖋' => 'f', '𝖌' => 'g', '𝖍' => 'h', '𝖎' => 'i', '𝖏' => 'j', '𝖐' => 'k', '𝖑' => 'l', '𝖒' => 'm', '𝖓' => 'n', '𝖔' => 'o', '𝖕' => 'p', '𝖖' => 'q', '𝖗' => 'r', '𝖘' => 's', '𝖙' => 't', '𝖚' => 'u', '𝖛' => 'v', '𝖜' => 'w', '𝖝' => 'x', '𝖞' => 'y', '𝖟' => 'z', '𝖠' => 'A', '𝖡' => 'B', '𝖢' => 'C', '𝖣' => 'D', '𝖤' => 'E', '𝖥' => 'F', '𝖦' => 'G', '𝖧' => 'H', '𝖨' => 'I', '𝖩' => 'J', '𝖪' => 'K', '𝖫' => 'L', '𝖬' => 'M', '𝖭' => 'N', '𝖮' => 'O', '𝖯' => 'P', '𝖰' => 'Q', '𝖱' => 'R', '𝖲' => 'S', '𝖳' => 'T', '𝖴' => 'U', '𝖵' => 'V', '𝖶' => 'W', '𝖷' => 'X', '𝖸' => 'Y', '𝖹' => 'Z', '𝖺' => 'a', '𝖻' => 'b', '𝖼' => 'c', '𝖽' => 'd', '𝖾' => 'e', '𝖿' => 'f', '𝗀' => 'g', '𝗁' => 'h', '𝗂' => 'i', '𝗃' => 'j', '𝗄' => 'k', '𝗅' => 'l', '𝗆' => 'm', '𝗇' => 'n', '𝗈' => 'o', '𝗉' => 'p', '𝗊' => 'q', '𝗋' => 'r', '𝗌' => 's', '𝗍' => 't', '𝗎' => 'u', '𝗏' => 'v', '𝗐' => 'w', '𝗑' => 'x', '𝗒' => 'y', '𝗓' => 'z', '𝗔' => 'A', '𝗕' => 'B', '𝗖' => 'C', '𝗗' => 'D', '𝗘' => 'E', '𝗙' => 'F', '𝗚' => 'G', '𝗛' => 'H', '𝗜' => 'I', '𝗝' => 'J', '𝗞' => 'K', '𝗟' => 'L', '𝗠' => 'M', '𝗡' => 'N', '𝗢' => 'O', '𝗣' => 'P', '𝗤' => 'Q', '𝗥' => 'R', '𝗦' => 'S', '𝗧' => 'T', '𝗨' => 'U', '𝗩' => 'V', '𝗪' => 'W', '𝗫' => 'X', '𝗬' => 'Y', '𝗭' => 'Z', '𝗮' => 'a', '𝗯' => 'b', '𝗰' => 'c', '𝗱' => 'd', '𝗲' => 'e', '𝗳' => 'f', '𝗴' => 'g', '𝗵' => 'h', '𝗶' => 'i', '𝗷' => 'j', '𝗸' => 'k', '𝗹' => 'l', '𝗺' => 'm', '𝗻' => 'n', '𝗼' => 'o', '𝗽' => 'p', '𝗾' => 'q', '𝗿' => 'r', '𝘀' => 's', '𝘁' => 't', '𝘂' => 'u', '𝘃' => 'v', '𝘄' => 'w', '𝘅' => 'x', '𝘆' => 'y', '𝘇' => 'z', '𝘈' => 'A', '𝘉' => 'B', '𝘊' => 'C', '𝘋' => 'D', '𝘌' => 'E', '𝘍' => 'F', '𝘎' => 'G', '𝘏' => 'H', '𝘐' => 'I', '𝘑' => 'J', '𝘒' => 'K', '𝘓' => 'L', '𝘔' => 'M', '𝘕' => 'N', '𝘖' => 'O', '𝘗' => 'P', '𝘘' => 'Q', '𝘙' => 'R', '𝘚' => 'S', '𝘛' => 'T', '𝘜' => 'U', '𝘝' => 'V', '𝘞' => 'W', '𝘟' => 'X', '𝘠' => 'Y', '𝘡' => 'Z', '𝘢' => 'a', '𝘣' => 'b', '𝘤' => 'c', '𝘥' => 'd', '𝘦' => 'e', '𝘧' => 'f', '𝘨' => 'g', '𝘩' => 'h', '𝘪' => 'i', '𝘫' => 'j', '𝘬' => 'k', '𝘭' => 'l', '𝘮' => 'm', '𝘯' => 'n', '𝘰' => 'o', '𝘱' => 'p', '𝘲' => 'q', '𝘳' => 'r', '𝘴' => 's', '𝘵' => 't', '𝘶' => 'u', '𝘷' => 'v', '𝘸' => 'w', '𝘹' => 'x', '𝘺' => 'y', '𝘻' => 'z', '𝘼' => 'A', '𝘽' => 'B', '𝘾' => 'C', '𝘿' => 'D', '𝙀' => 'E', '𝙁' => 'F', '𝙂' => 'G', '𝙃' => 'H', '𝙄' => 'I', '𝙅' => 'J', '𝙆' => 'K', '𝙇' => 'L', '𝙈' => 'M', '𝙉' => 'N', '𝙊' => 'O', '𝙋' => 'P', '𝙌' => 'Q', '𝙍' => 'R', '𝙎' => 'S', '𝙏' => 'T', '𝙐' => 'U', '𝙑' => 'V', '𝙒' => 'W', '𝙓' => 'X', '𝙔' => 'Y', '𝙕' => 'Z', '𝙖' => 'a', '𝙗' => 'b', '𝙘' => 'c', '𝙙' => 'd', '𝙚' => 'e', '𝙛' => 'f', '𝙜' => 'g', '𝙝' => 'h', '𝙞' => 'i', '𝙟' => 'j', '𝙠' => 'k', '𝙡' => 'l', '𝙢' => 'm', '𝙣' => 'n', '𝙤' => 'o', '𝙥' => 'p', '𝙦' => 'q', '𝙧' => 'r', '𝙨' => 's', '𝙩' => 't', '𝙪' => 'u', '𝙫' => 'v', '𝙬' => 'w', '𝙭' => 'x', '𝙮' => 'y', '𝙯' => 'z', '𝙰' => 'A', '𝙱' => 'B', '𝙲' => 'C', '𝙳' => 'D', '𝙴' => 'E', '𝙵' => 'F', '𝙶' => 'G', '𝙷' => 'H', '𝙸' => 'I', '𝙹' => 'J', '𝙺' => 'K', '𝙻' => 'L', '𝙼' => 'M', '𝙽' => 'N', '𝙾' => 'O', '𝙿' => 'P', '𝚀' => 'Q', '𝚁' => 'R', '𝚂' => 'S', '𝚃' => 'T', '𝚄' => 'U', '𝚅' => 'V', '𝚆' => 'W', '𝚇' => 'X', '𝚈' => 'Y', '𝚉' => 'Z', '𝚊' => 'a', '𝚋' => 'b', '𝚌' => 'c', '𝚍' => 'd', '𝚎' => 'e', '𝚏' => 'f', '𝚐' => 'g', '𝚑' => 'h', '𝚒' => 'i', '𝚓' => 'j', '𝚔' => 'k', '𝚕' => 'l', '𝚖' => 'm', '𝚗' => 'n', '𝚘' => 'o', '𝚙' => 'p', '𝚚' => 'q', '𝚛' => 'r', '𝚜' => 's', '𝚝' => 't', '𝚞' => 'u', '𝚟' => 'v', '𝚠' => 'w', '𝚡' => 'x', '𝚢' => 'y', '𝚣' => 'z', '𝚤' => 'ı', '𝚥' => 'ȷ', '𝚨' => 'Α', '𝚩' => 'Β', '𝚪' => 'Γ', '𝚫' => 'Δ', '𝚬' => 'Ε', '𝚭' => 'Ζ', '𝚮' => 'Η', '𝚯' => 'Θ', '𝚰' => 'Ι', '𝚱' => 'Κ', '𝚲' => 'Λ', '𝚳' => 'Μ', '𝚴' => 'Ν', '𝚵' => 'Ξ', '𝚶' => 'Ο', '𝚷' => 'Π', '𝚸' => 'Ρ', '𝚹' => 'ϴ', '𝚺' => 'Σ', '𝚻' => 'Τ', '𝚼' => 'Υ', '𝚽' => 'Φ', '𝚾' => 'Χ', '𝚿' => 'Ψ', '𝛀' => 'Ω', '𝛁' => '∇', '𝛂' => 'α', '𝛃' => 'β', '𝛄' => 'γ', '𝛅' => 'δ', '𝛆' => 'ε', '𝛇' => 'ζ', '𝛈' => 'η', '𝛉' => 'θ', '𝛊' => 'ι', '𝛋' => 'κ', '𝛌' => 'λ', '𝛍' => 'μ', '𝛎' => 'ν', '𝛏' => 'ξ', '𝛐' => 'ο', '𝛑' => 'π', '𝛒' => 'ρ', '𝛓' => 'ς', '𝛔' => 'σ', '𝛕' => 'τ', '𝛖' => 'υ', '𝛗' => 'φ', '𝛘' => 'χ', '𝛙' => 'ψ', '𝛚' => 'ω', '𝛛' => '∂', '𝛜' => 'ϵ', '𝛝' => 'ϑ', '𝛞' => 'ϰ', '𝛟' => 'ϕ', '𝛠' => 'ϱ', '𝛡' => 'ϖ', '𝛢' => 'Α', '𝛣' => 'Β', '𝛤' => 'Γ', '𝛥' => 'Δ', '𝛦' => 'Ε', '𝛧' => 'Ζ', '𝛨' => 'Η', '𝛩' => 'Θ', '𝛪' => 'Ι', '𝛫' => 'Κ', '𝛬' => 'Λ', '𝛭' => 'Μ', '𝛮' => 'Ν', '𝛯' => 'Ξ', '𝛰' => 'Ο', '𝛱' => 'Π', '𝛲' => 'Ρ', '𝛳' => 'ϴ', '𝛴' => 'Σ', '𝛵' => 'Τ', '𝛶' => 'Υ', '𝛷' => 'Φ', '𝛸' => 'Χ', '𝛹' => 'Ψ', '𝛺' => 'Ω', '𝛻' => '∇', '𝛼' => 'α', '𝛽' => 'β', '𝛾' => 'γ', '𝛿' => 'δ', '𝜀' => 'ε', '𝜁' => 'ζ', '𝜂' => 'η', '𝜃' => 'θ', '𝜄' => 'ι', '𝜅' => 'κ', '𝜆' => 'λ', '𝜇' => 'μ', '𝜈' => 'ν', '𝜉' => 'ξ', '𝜊' => 'ο', '𝜋' => 'π', '𝜌' => 'ρ', '𝜍' => 'ς', '𝜎' => 'σ', '𝜏' => 'τ', '𝜐' => 'υ', '𝜑' => 'φ', '𝜒' => 'χ', '𝜓' => 'ψ', '𝜔' => 'ω', '𝜕' => '∂', '𝜖' => 'ϵ', '𝜗' => 'ϑ', '𝜘' => 'ϰ', '𝜙' => 'ϕ', '𝜚' => 'ϱ', '𝜛' => 'ϖ', '𝜜' => 'Α', '𝜝' => 'Β', '𝜞' => 'Γ', '𝜟' => 'Δ', '𝜠' => 'Ε', '𝜡' => 'Ζ', '𝜢' => 'Η', '𝜣' => 'Θ', '𝜤' => 'Ι', '𝜥' => 'Κ', '𝜦' => 'Λ', '𝜧' => 'Μ', '𝜨' => 'Ν', '𝜩' => 'Ξ', '𝜪' => 'Ο', '𝜫' => 'Π', '𝜬' => 'Ρ', '𝜭' => 'ϴ', '𝜮' => 'Σ', '𝜯' => 'Τ', '𝜰' => 'Υ', '𝜱' => 'Φ', '𝜲' => 'Χ', '𝜳' => 'Ψ', '𝜴' => 'Ω', '𝜵' => '∇', '𝜶' => 'α', '𝜷' => 'β', '𝜸' => 'γ', '𝜹' => 'δ', '𝜺' => 'ε', '𝜻' => 'ζ', '𝜼' => 'η', '𝜽' => 'θ', '𝜾' => 'ι', '𝜿' => 'κ', '𝝀' => 'λ', '𝝁' => 'μ', '𝝂' => 'ν', '𝝃' => 'ξ', '𝝄' => 'ο', '𝝅' => 'π', '𝝆' => 'ρ', '𝝇' => 'ς', '𝝈' => 'σ', '𝝉' => 'τ', '𝝊' => 'υ', '𝝋' => 'φ', '𝝌' => 'χ', '𝝍' => 'ψ', '𝝎' => 'ω', '𝝏' => '∂', '𝝐' => 'ϵ', '𝝑' => 'ϑ', '𝝒' => 'ϰ', '𝝓' => 'ϕ', '𝝔' => 'ϱ', '𝝕' => 'ϖ', '𝝖' => 'Α', '𝝗' => 'Β', '𝝘' => 'Γ', '𝝙' => 'Δ', '𝝚' => 'Ε', '𝝛' => 'Ζ', '𝝜' => 'Η', '𝝝' => 'Θ', '𝝞' => 'Ι', '𝝟' => 'Κ', '𝝠' => 'Λ', '𝝡' => 'Μ', '𝝢' => 'Ν', '𝝣' => 'Ξ', '𝝤' => 'Ο', '𝝥' => 'Π', '𝝦' => 'Ρ', '𝝧' => 'ϴ', '𝝨' => 'Σ', '𝝩' => 'Τ', '𝝪' => 'Υ', '𝝫' => 'Φ', '𝝬' => 'Χ', '𝝭' => 'Ψ', '𝝮' => 'Ω', '𝝯' => '∇', '𝝰' => 'α', '𝝱' => 'β', '𝝲' => 'γ', '𝝳' => 'δ', '𝝴' => 'ε', '𝝵' => 'ζ', '𝝶' => 'η', '𝝷' => 'θ', '𝝸' => 'ι', '𝝹' => 'κ', '𝝺' => 'λ', '𝝻' => 'μ', '𝝼' => 'ν', '𝝽' => 'ξ', '𝝾' => 'ο', '𝝿' => 'π', '𝞀' => 'ρ', '𝞁' => 'ς', '𝞂' => 'σ', '𝞃' => 'τ', '𝞄' => 'υ', '𝞅' => 'φ', '𝞆' => 'χ', '𝞇' => 'ψ', '𝞈' => 'ω', '𝞉' => '∂', '𝞊' => 'ϵ', '𝞋' => 'ϑ', '𝞌' => 'ϰ', '𝞍' => 'ϕ', '𝞎' => 'ϱ', '𝞏' => 'ϖ', '𝞐' => 'Α', '𝞑' => 'Β', '𝞒' => 'Γ', '𝞓' => 'Δ', '𝞔' => 'Ε', '𝞕' => 'Ζ', '𝞖' => 'Η', '𝞗' => 'Θ', '𝞘' => 'Ι', '𝞙' => 'Κ', '𝞚' => 'Λ', '𝞛' => 'Μ', '𝞜' => 'Ν', '𝞝' => 'Ξ', '𝞞' => 'Ο', '𝞟' => 'Π', '𝞠' => 'Ρ', '𝞡' => 'ϴ', '𝞢' => 'Σ', '𝞣' => 'Τ', '𝞤' => 'Υ', '𝞥' => 'Φ', '𝞦' => 'Χ', '𝞧' => 'Ψ', '𝞨' => 'Ω', '𝞩' => '∇', '𝞪' => 'α', '𝞫' => 'β', '𝞬' => 'γ', '𝞭' => 'δ', '𝞮' => 'ε', '𝞯' => 'ζ', '𝞰' => 'η', '𝞱' => 'θ', '𝞲' => 'ι', '𝞳' => 'κ', '𝞴' => 'λ', '𝞵' => 'μ', '𝞶' => 'ν', '𝞷' => 'ξ', '𝞸' => 'ο', '𝞹' => 'π', '𝞺' => 'ρ', '𝞻' => 'ς', '𝞼' => 'σ', '𝞽' => 'τ', '𝞾' => 'υ', '𝞿' => 'φ', '𝟀' => 'χ', '𝟁' => 'ψ', '𝟂' => 'ω', '𝟃' => '∂', '𝟄' => 'ϵ', '𝟅' => 'ϑ', '𝟆' => 'ϰ', '𝟇' => 'ϕ', '𝟈' => 'ϱ', '𝟉' => 'ϖ', '𝟊' => 'Ϝ', '𝟋' => 'ϝ', '𝟎' => '0', '𝟏' => '1', '𝟐' => '2', '𝟑' => '3', '𝟒' => '4', '𝟓' => '5', '𝟔' => '6', '𝟕' => '7', '𝟖' => '8', '𝟗' => '9', '𝟘' => '0', '𝟙' => '1', '𝟚' => '2', '𝟛' => '3', '𝟜' => '4', '𝟝' => '5', '𝟞' => '6', '𝟟' => '7', '𝟠' => '8', '𝟡' => '9', '𝟢' => '0', '𝟣' => '1', '𝟤' => '2', '𝟥' => '3', '𝟦' => '4', '𝟧' => '5', '𝟨' => '6', '𝟩' => '7', '𝟪' => '8', '𝟫' => '9', '𝟬' => '0', '𝟭' => '1', '𝟮' => '2', '𝟯' => '3', '𝟰' => '4', '𝟱' => '5', '𝟲' => '6', '𝟳' => '7', '𝟴' => '8', '𝟵' => '9', '𝟶' => '0', '𝟷' => '1', '𝟸' => '2', '𝟹' => '3', '𝟺' => '4', '𝟻' => '5', '𝟼' => '6', '𝟽' => '7', '𝟾' => '8', '𝟿' => '9', '𞸀' => 'ا', '𞸁' => 'ب', '𞸂' => 'ج', '𞸃' => 'د', '𞸅' => 'و', '𞸆' => 'ز', '𞸇' => 'ح', '𞸈' => 'ط', '𞸉' => 'ي', '𞸊' => 'ك', '𞸋' => 'ل', '𞸌' => 'م', '𞸍' => 'ن', '𞸎' => 'س', '𞸏' => 'ع', '𞸐' => 'ف', '𞸑' => 'ص', '𞸒' => 'ق', '𞸓' => 'ر', '𞸔' => 'ش', '𞸕' => 'ت', '𞸖' => 'ث', '𞸗' => 'خ', '𞸘' => 'ذ', '𞸙' => 'ض', '𞸚' => 'ظ', '𞸛' => 'غ', '𞸜' => 'ٮ', '𞸝' => 'ں', '𞸞' => 'ڡ', '𞸟' => 'ٯ', '𞸡' => 'ب', '𞸢' => 'ج', '𞸤' => 'ه', '𞸧' => 'ح', '𞸩' => 'ي', '𞸪' => 'ك', '𞸫' => 'ل', '𞸬' => 'م', '𞸭' => 'ن', '𞸮' => 'س', '𞸯' => 'ع', '𞸰' => 'ف', '𞸱' => 'ص', '𞸲' => 'ق', '𞸴' => 'ش', '𞸵' => 'ت', '𞸶' => 'ث', '𞸷' => 'خ', '𞸹' => 'ض', '𞸻' => 'غ', '𞹂' => 'ج', '𞹇' => 'ح', '𞹉' => 'ي', '𞹋' => 'ل', '𞹍' => 'ن', '𞹎' => 'س', '𞹏' => 'ع', '𞹑' => 'ص', '𞹒' => 'ق', '𞹔' => 'ش', '𞹗' => 'خ', '𞹙' => 'ض', '𞹛' => 'غ', '𞹝' => 'ں', '𞹟' => 'ٯ', '𞹡' => 'ب', '𞹢' => 'ج', '𞹤' => 'ه', '𞹧' => 'ح', '𞹨' => 'ط', '𞹩' => 'ي', '𞹪' => 'ك', '𞹬' => 'م', '𞹭' => 'ن', '𞹮' => 'س', '𞹯' => 'ع', '𞹰' => 'ف', '𞹱' => 'ص', '𞹲' => 'ق', '𞹴' => 'ش', '𞹵' => 'ت', '𞹶' => 'ث', '𞹷' => 'خ', '𞹹' => 'ض', '𞹺' => 'ظ', '𞹻' => 'غ', '𞹼' => 'ٮ', '𞹾' => 'ڡ', '𞺀' => 'ا', '𞺁' => 'ب', '𞺂' => 'ج', '𞺃' => 'د', '𞺄' => 'ه', '𞺅' => 'و', '𞺆' => 'ز', '𞺇' => 'ح', '𞺈' => 'ط', '𞺉' => 'ي', '𞺋' => 'ل', '𞺌' => 'م', '𞺍' => 'ن', '𞺎' => 'س', '𞺏' => 'ع', '𞺐' => 'ف', '𞺑' => 'ص', '𞺒' => 'ق', '𞺓' => 'ر', '𞺔' => 'ش', '𞺕' => 'ت', '𞺖' => 'ث', '𞺗' => 'خ', '𞺘' => 'ذ', '𞺙' => 'ض', '𞺚' => 'ظ', '𞺛' => 'غ', '𞺡' => 'ب', '𞺢' => 'ج', '𞺣' => 'د', '𞺥' => 'و', '𞺦' => 'ز', '𞺧' => 'ح', '𞺨' => 'ط', '𞺩' => 'ي', '𞺫' => 'ل', '𞺬' => 'م', '𞺭' => 'ن', '𞺮' => 'س', '𞺯' => 'ع', '𞺰' => 'ف', '𞺱' => 'ص', '𞺲' => 'ق', '𞺳' => 'ر', '𞺴' => 'ش', '𞺵' => 'ت', '𞺶' => 'ث', '𞺷' => 'خ', '𞺸' => 'ذ', '𞺹' => 'ض', '𞺺' => 'ظ', '𞺻' => 'غ', '🄀' => '0.', '🄁' => '0,', '🄂' => '1,', '🄃' => '2,', '🄄' => '3,', '🄅' => '4,', '🄆' => '5,', '🄇' => '6,', '🄈' => '7,', '🄉' => '8,', '🄊' => '9,', '🄐' => '(A)', '🄑' => '(B)', '🄒' => '(C)', '🄓' => '(D)', '🄔' => '(E)', '🄕' => '(F)', '🄖' => '(G)', '🄗' => '(H)', '🄘' => '(I)', '🄙' => '(J)', '🄚' => '(K)', '🄛' => '(L)', '🄜' => '(M)', '🄝' => '(N)', '🄞' => '(O)', '🄟' => '(P)', '🄠' => '(Q)', '🄡' => '(R)', '🄢' => '(S)', '🄣' => '(T)', '🄤' => '(U)', '🄥' => '(V)', '🄦' => '(W)', '🄧' => '(X)', '🄨' => '(Y)', '🄩' => '(Z)', '🄪' => '〔S〕', '🄫' => '(C)', '🄬' => '(R)', '🄭' => '(CD)', '🄮' => '(WZ)', '🄰' => 'A', '🄱' => 'B', '🄲' => 'C', '🄳' => 'D', '🄴' => 'E', '🄵' => 'F', '🄶' => 'G', '🄷' => 'H', '🄸' => 'I', '🄹' => 'J', '🄺' => 'K', '🄻' => 'L', '🄼' => 'M', '🄽' => 'N', '🄾' => 'O', '🄿' => 'P', '🅀' => 'Q', '🅁' => 'R', '🅂' => 'S', '🅃' => 'T', '🅄' => 'U', '🅅' => 'V', '🅆' => 'W', '🅇' => 'X', '🅈' => 'Y', '🅉' => 'Z', '🅊' => 'HV', '🅋' => 'MV', '🅌' => 'SD', '🅍' => 'SS', '🅎' => 'PPV', '🅏' => 'WC', '🆐' => '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', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', 'ʹ' => '\'', 'ʺ' => '"', 'ʻ' => '\'', 'ʼ' => '\'', 'ʽ' => '\'', 'ˈ' => '\'', 'ˋ' => '`', '‘' => '\'', '’' => '\'', '‚' => ',', '‛' => '\'', '“' => '"', '”' => '"', '„' => ',,', '‟' => '"', '′' => '\'', '〝' => '"', '〞' => '"', '«' => '<<', '»' => '>>', '‹' => '<', '›' => '>', '­' => '-', '‐' => '-', '‑' => '-', '‒' => '-', '–' => '-', '—' => '-', '―' => '-', '︱' => '-', '︲' => '-', '¡' => '!', '¿' => '?', '˂' => '<', '˃' => '>', '˄' => '^', 'ˆ' => '^', 'ː' => ':', '˜' => '~', '‖' => '||', '⁄' => '/', '⁅' => '[', '⁆' => ']', '⁎' => '*', '、' => ',', '。' => '.', '〈' => '<', '〉' => '>', '《' => '<<', '》' => '>>', '〔' => '[', '〕' => ']', '〘' => '[', '〙' => ']', '〚' => '[', '〛' => ']', '︐' => ',', '︑' => ',', '︒' => '.', '︓' => ':', '︔' => ';', '︕' => '!', '︖' => '?', '︙' => '...', '︰' => '..', '︵' => '(', '︶' => ')', '︷' => '{', '︸' => '}', '︹' => '[', '︺' => ']', '︽' => '<<', '︾' => '>>', '︿' => '<', '﹀' => '>', '﹇' => '[', '﹈' => ']', '±' => '+/-', '×' => '*', '÷' => '/', '˖' => '+', '˗' => '-', '−' => '-', '∕' => '/', '∖' => '\\', '∣' => '|', '∥' => '||', '≪' => '<<', '≫' => '>>', '⦅' => '((', '⦆' => '))', ); * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Intl\Grapheme as p; if (extension_loaded('intl')) { return; } if (\PHP_VERSION_ID >= 80000) { return require __DIR__.'/bootstrap80.php'; } if (!defined('GRAPHEME_EXTR_COUNT')) { define('GRAPHEME_EXTR_COUNT', 0); } if (!defined('GRAPHEME_EXTR_MAXBYTES')) { define('GRAPHEME_EXTR_MAXBYTES', 1); } if (!defined('GRAPHEME_EXTR_MAXCHARS')) { define('GRAPHEME_EXTR_MAXCHARS', 2); } if (!function_exists('grapheme_extract')) { function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); } } if (!function_exists('grapheme_stripos')) { function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); } } if (!function_exists('grapheme_stristr')) { function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); } } if (!function_exists('grapheme_strlen')) { function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); } } if (!function_exists('grapheme_strpos')) { function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); } } if (!function_exists('grapheme_strripos')) { function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); } } if (!function_exists('grapheme_strrpos')) { function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); } } if (!function_exists('grapheme_strstr')) { function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); } } if (!function_exists('grapheme_substr')) { function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Intl\Grapheme as p; if (!defined('GRAPHEME_EXTR_COUNT')) { define('GRAPHEME_EXTR_COUNT', 0); } if (!defined('GRAPHEME_EXTR_MAXBYTES')) { define('GRAPHEME_EXTR_MAXBYTES', 1); } if (!defined('GRAPHEME_EXTR_MAXCHARS')) { define('GRAPHEME_EXTR_MAXCHARS', 2); } if (!function_exists('grapheme_extract')) { function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); } } if (!function_exists('grapheme_stripos')) { function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); } } if (!function_exists('grapheme_stristr')) { function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } } if (!function_exists('grapheme_strlen')) { function grapheme_strlen(?string $string): int|false|null { return p\Grapheme::grapheme_strlen((string) $string); } } if (!function_exists('grapheme_strpos')) { function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); } } if (!function_exists('grapheme_strripos')) { function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); } } if (!function_exists('grapheme_strrpos')) { function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); } } if (!function_exists('grapheme_strstr')) { function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); } } if (!function_exists('grapheme_substr')) { function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Intl\Grapheme; \define('SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39) ? '\X' : Grapheme::GRAPHEME_CLUSTER_RX); /** * Partial intl implementation in pure PHP. * * Implemented: * - grapheme_extract - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8 * - grapheme_stripos - Find position (in grapheme units) of first occurrence of a case-insensitive string * - grapheme_stristr - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack * - grapheme_strlen - Get string length in grapheme units * - grapheme_strpos - Find position (in grapheme units) of first occurrence of a string * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack * - grapheme_substr - Return part of a string * * @author Nicolas Grekas * * @internal */ final class Grapheme { // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) // This regular expression is a work around for http://bugs.exim.org/1279 public const GRAPHEME_CLUSTER_RX = '(?:\r\n|(?:[ -~\x{200C}\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}])[\p{Mn}\p{Me}\x{09BE}\x{09D7}\x{0B3E}\x{0B57}\x{0BBE}\x{0BD7}\x{0CC2}\x{0CD5}\x{0CD6}\x{0D3E}\x{0D57}\x{0DCF}\x{0DDF}\x{200C}\x{200D}\x{1D165}\x{1D16E}-\x{1D172}]*|[\p{Cc}\p{Cf}\p{Zl}\p{Zp}])'; private const CASE_FOLD = [ ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ]; public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) { if (0 > $start) { $start = \strlen($s) + $start; } if (!\is_scalar($s)) { $hasError = false; set_error_handler(function () use (&$hasError) { $hasError = true; }); $next = substr($s, $start); restore_error_handler(); if ($hasError) { substr($s, $start); $s = ''; } else { $s = $next; } } else { $s = substr($s, $start); } $size = (int) $size; $type = (int) $type; $start = (int) $start; if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { if (80000 > \PHP_VERSION_ID) { return false; } throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); } if (!isset($s[0]) || 0 > $size || 0 > $start) { return false; } if (0 === $size) { return ''; } $next = $start; $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', "\r\n".$s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); if (!isset($s[1])) { return false; } $i = 1; $ret = ''; do { if (\GRAPHEME_EXTR_COUNT === $type) { --$size; } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { $size -= \strlen($s[$i]); } else { $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE'); } if ($size >= 0) { $ret .= $s[$i]; } } while (isset($s[++$i]) && $size > 0); $next += \strlen($ret); return $ret; } public static function grapheme_strlen($s) { preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len); return 0 === $len && '' !== $s ? null : $len; } public static function grapheme_substr($s, $start, $len = null) { if (null === $len) { $len = 2147483647; } preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s); $slen = \count($s[0]); $start = (int) $start; if (0 > $start) { $start += $slen; } if (0 > $start) { if (\PHP_VERSION_ID < 80000) { return false; } $start = 0; } if ($start >= $slen) { return \PHP_VERSION_ID >= 80000 ? '' : false; } $rem = $slen - $start; if (0 > $len) { $len += $rem; } if (0 === $len) { return ''; } if (0 > $len) { return \PHP_VERSION_ID >= 80000 ? '' : false; } if ($len > $rem) { $len = $rem; } return implode('', \array_slice($s[0], $start, $len)); } public static function grapheme_strpos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 0); } public static function grapheme_stripos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 1); } public static function grapheme_strrpos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 2); } public static function grapheme_strripos($s, $needle, $offset = 0) { return self::grapheme_position($s, $needle, $offset, 3); } public static function grapheme_stristr($s, $needle, $beforeNeedle = false) { return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); } public static function grapheme_strstr($s, $needle, $beforeNeedle = false) { return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); } private static function grapheme_position($s, $needle, $offset, $mode) { $needle = (string) $needle; if (80000 > \PHP_VERSION_ID && !preg_match('/./us', $needle)) { return false; } $s = (string) $s; if (!preg_match('/./us', $s)) { return false; } if ($offset > 0) { $s = self::grapheme_substr($s, $offset); } elseif ($offset < 0) { if (2 > $mode) { $offset += self::grapheme_strlen($s); $s = self::grapheme_substr($s, $offset); if (0 > $offset) { $offset = 0; } } elseif (0 > $offset += self::grapheme_strlen($needle)) { $s = self::grapheme_substr($s, 0, $offset); $offset = 0; } else { $offset = 0; } } // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, // we can use normal binary string functions here. For case-insensitive searches, // case fold the strings first. $caseInsensitive = $mode & 1; $reverse = $mode & 2; if ($caseInsensitive) { // Use the same case folding mode as mbstring does for mb_stripos(). // Stick to SIMPLE case folding to avoid changing the length of the string, which // might result in offsets being shifted. $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; $s = mb_convert_case($s, $mode, 'UTF-8'); $needle = mb_convert_case($needle, $mode, 'UTF-8'); if (!\defined('MB_CASE_FOLD_SIMPLE')) { $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); } } if ($reverse) { $needlePos = strrpos($s, $needle); } else { $needlePos = strpos($s, $needle); } return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false; } } * * 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); } } } * * 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); } } and Trevor Rowbotham * * 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 */ 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 */ private static $virama; /** * @var array */ private static $mapped; /** * @var array */ private static $ignored; /** * @var array */ private static $deviation; /** * @var array */ private static $disallowed; /** * @var array */ private static $disallowed_STD3_mapped; /** * @var array */ 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 >= 70200 && 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 >= 70200 && 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 $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': $info->errors |= self::ERROR_DISALLOWED; // no break. case 'valid': $str .= mb_chr($codePoint, 'utf-8'); break; case 'ignored': // Do nothing. break; case 'mapped': $str .= $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 $options * * @return array */ 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)) { 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 $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 $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; } } // 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 */ 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']; } } and Trevor Rowbotham * * 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; } 'ss', 962 => 'σ', 8204 => '', 8205 => '', ); 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, ); * * 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; } } ' ', 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)', ); 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, ); 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, ); '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 => '𪘀', ); * * 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'; } 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, ); * * 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); } } * * 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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Intl\Normalizer; /** * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. * * It has been validated with Unicode 6.3 Normalization Conformance Test. * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. * * @author Nicolas Grekas * * @internal */ class Normalizer { public const FORM_D = \Normalizer::FORM_D; public const FORM_KD = \Normalizer::FORM_KD; public const FORM_C = \Normalizer::FORM_C; public const FORM_KC = \Normalizer::FORM_KC; public const NFD = \Normalizer::NFD; public const NFKD = \Normalizer::NFKD; public const NFC = \Normalizer::NFC; public const NFKC = \Normalizer::NFKC; private static $C; private static $D; private static $KD; private static $cC; private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; public static function isNormalized(string $s, int $form = self::FORM_C) { if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) { return false; } if (!isset($s[strspn($s, self::$ASCII)])) { return true; } if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { return true; } return self::normalize($s, $form) === $s; } public static function normalize(string $s, int $form = self::FORM_C) { if (!preg_match('//u', $s)) { return false; } switch ($form) { case self::NFC: $C = true; $K = false; break; case self::NFD: $C = false; $K = false; break; case self::NFKC: $C = true; $K = true; break; case self::NFKD: $C = false; $K = true; break; default: if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { return $s; } if (80000 > \PHP_VERSION_ID) { return false; } throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); } if ('' === $s) { return ''; } if ($K && null === self::$KD) { self::$KD = self::getData('compatibilityDecomposition'); } if (null === self::$D) { self::$D = self::getData('canonicalDecomposition'); self::$cC = self::getData('combiningClass'); } if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { mb_internal_encoding('8bit'); } $r = self::decompose($s, $K); if ($C) { if (null === self::$C) { self::$C = self::getData('canonicalComposition'); } $r = self::recompose($r); } if (null !== $mbEncoding) { mb_internal_encoding($mbEncoding); } return $r; } private static function recompose($s) { $ASCII = self::$ASCII; $compMap = self::$C; $combClass = self::$cC; $ulenMask = self::$ulenMask; $result = $tail = ''; $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; $len = \strlen($s); $lastUchr = substr($s, 0, $i); $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; while ($i < $len) { if ($s[$i] < "\x80") { // ASCII chars if ($tail) { $lastUchr .= $tail; $tail = ''; } if ($j = strspn($s, $ASCII, $i + 1)) { $lastUchr .= substr($s, $i, $j); $i += $j; } $result .= $lastUchr; $lastUchr = $s[$i]; $lastUcls = 0; ++$i; continue; } $ulen = $ulenMask[$s[$i] & "\xF0"]; $uchr = substr($s, $i, $ulen); if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr || $lastUcls) { // Table lookup and combining chars composition $ucls = $combClass[$uchr] ?? 0; if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { $lastUchr = $compMap[$lastUchr.$uchr]; } elseif ($lastUcls = $ucls) { $tail .= $uchr; } else { if ($tail) { $lastUchr .= $tail; $tail = ''; } $result .= $lastUchr; $lastUchr = $uchr; } } else { // Hangul chars $L = \ord($lastUchr[2]) - 0x80; $V = \ord($uchr[2]) - 0xA1; $T = 0; $uchr = substr($s, $i + $ulen, 3); if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { $T = \ord($uchr[2]) - 0xA7; 0 > $T && $T += 0x40; $ulen += 3; } $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); } $i += $ulen; } return $result.$lastUchr.$tail; } private static function decompose($s, $c) { $result = ''; $ASCII = self::$ASCII; $decompMap = self::$D; $combClass = self::$cC; $ulenMask = self::$ulenMask; if ($c) { $compatMap = self::$KD; } $c = []; $i = 0; $len = \strlen($s); while ($i < $len) { if ($s[$i] < "\x80") { // ASCII chars if ($c) { ksort($c); $result .= implode('', $c); $c = []; } $j = 1 + strspn($s, $ASCII, $i + 1); $result .= substr($s, $i, $j); $i += $j; continue; } $ulen = $ulenMask[$s[$i] & "\xF0"]; $uchr = substr($s, $i, $ulen); $i += $ulen; if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { // Table lookup if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) { $uchr = $j; $j = \strlen($uchr); $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; if ($ulen != $j) { // Put trailing chars in $s $j -= $ulen; $i -= $j; if (0 > $i) { $s = str_repeat(' ', -$i).$s; $len -= $i; $i = 0; } while ($j--) { $s[$i + $j] = $uchr[$ulen + $j]; } $uchr = substr($uchr, 0, $ulen); } } if (isset($combClass[$uchr])) { // Combining chars, for sorting if (!isset($c[$combClass[$uchr]])) { $c[$combClass[$uchr]] = ''; } $c[$combClass[$uchr]] .= $uchr; continue; } } else { // Hangul chars $uchr = unpack('C*', $uchr); $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); if ($j %= 28) { $uchr .= $j < 25 ? ("\xE1\x86".\chr(0xA7 + $j)) : ("\xE1\x87".\chr(0x67 + $j)); } } if ($c) { ksort($c); $result .= implode('', $c); $c = []; } $result .= $uchr; } if ($c) { ksort($c); $result .= implode('', $c); } return $result; } private static function getData($file) { if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { return require $file; } return false; } } 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', 'Ā' => 'Ā', 'ā' => 'ā', 'Ă' => 'Ă', 'ă' => 'ă', 'Ą' => 'Ą', 'ą' => 'ą', 'Ć' => 'Ć', 'ć' => 'ć', 'Ĉ' => 'Ĉ', 'ĉ' => 'ĉ', 'Ċ' => 'Ċ', 'ċ' => 'ċ', 'Č' => 'Č', 'č' => 'č', 'Ď' => 'Ď', 'ď' => 'ď', 'Ē' => 'Ē', 'ē' => 'ē', 'Ĕ' => 'Ĕ', 'ĕ' => 'ĕ', 'Ė' => 'Ė', 'ė' => 'ė', 'Ę' => 'Ę', 'ę' => 'ę', 'Ě' => 'Ě', 'ě' => 'ě', 'Ĝ' => 'Ĝ', 'ĝ' => 'ĝ', 'Ğ' => 'Ğ', 'ğ' => 'ğ', 'Ġ' => 'Ġ', 'ġ' => 'ġ', 'Ģ' => 'Ģ', 'ģ' => 'ģ', 'Ĥ' => 'Ĥ', 'ĥ' => 'ĥ', 'Ĩ' => 'Ĩ', 'ĩ' => 'ĩ', 'Ī' => 'Ī', 'ī' => 'ī', 'Ĭ' => 'Ĭ', 'ĭ' => 'ĭ', 'Į' => 'Į', 'į' => 'į', 'İ' => 'İ', 'Ĵ' => 'Ĵ', 'ĵ' => 'ĵ', 'Ķ' => 'Ķ', 'ķ' => 'ķ', 'Ĺ' => 'Ĺ', 'ĺ' => 'ĺ', 'Ļ' => 'Ļ', 'ļ' => 'ļ', 'Ľ' => 'Ľ', 'ľ' => 'ľ', 'Ń' => 'Ń', 'ń' => 'ń', 'Ņ' => 'Ņ', 'ņ' => 'ņ', 'Ň' => 'Ň', 'ň' => 'ň', 'Ō' => 'Ō', 'ō' => 'ō', 'Ŏ' => 'Ŏ', 'ŏ' => 'ŏ', 'Ő' => 'Ő', 'ő' => 'ő', 'Ŕ' => 'Ŕ', 'ŕ' => 'ŕ', 'Ŗ' => 'Ŗ', 'ŗ' => 'ŗ', 'Ř' => 'Ř', 'ř' => 'ř', 'Ś' => 'Ś', 'ś' => 'ś', 'Ŝ' => 'Ŝ', 'ŝ' => 'ŝ', 'Ş' => 'Ş', 'ş' => 'ş', 'Š' => 'Š', 'š' => 'š', 'Ţ' => 'Ţ', 'ţ' => 'ţ', 'Ť' => 'Ť', 'ť' => 'ť', 'Ũ' => 'Ũ', 'ũ' => 'ũ', 'Ū' => 'Ū', 'ū' => 'ū', 'Ŭ' => 'Ŭ', 'ŭ' => 'ŭ', 'Ů' => 'Ů', 'ů' => 'ů', 'Ű' => 'Ű', 'ű' => 'ű', 'Ų' => 'Ų', 'ų' => 'ų', 'Ŵ' => 'Ŵ', 'ŵ' => 'ŵ', 'Ŷ' => 'Ŷ', 'ŷ' => 'ŷ', 'Ÿ' => 'Ÿ', 'Ź' => 'Ź', 'ź' => 'ź', 'Ż' => 'Ż', 'ż' => 'ż', 'Ž' => 'Ž', 'ž' => 'ž', 'Ơ' => 'Ơ', 'ơ' => 'ơ', 'Ư' => 'Ư', 'ư' => 'ư', 'Ǎ' => 'Ǎ', 'ǎ' => 'ǎ', 'Ǐ' => 'Ǐ', 'ǐ' => 'ǐ', 'Ǒ' => 'Ǒ', 'ǒ' => 'ǒ', 'Ǔ' => 'Ǔ', 'ǔ' => 'ǔ', 'Ǖ' => 'Ǖ', 'ǖ' => 'ǖ', 'Ǘ' => 'Ǘ', 'ǘ' => 'ǘ', 'Ǚ' => 'Ǚ', 'ǚ' => 'ǚ', 'Ǜ' => 'Ǜ', 'ǜ' => 'ǜ', 'Ǟ' => 'Ǟ', 'ǟ' => 'ǟ', 'Ǡ' => 'Ǡ', 'ǡ' => 'ǡ', 'Ǣ' => 'Ǣ', 'ǣ' => 'ǣ', 'Ǧ' => 'Ǧ', 'ǧ' => 'ǧ', 'Ǩ' => 'Ǩ', 'ǩ' => 'ǩ', 'Ǫ' => 'Ǫ', 'ǫ' => 'ǫ', 'Ǭ' => 'Ǭ', 'ǭ' => 'ǭ', 'Ǯ' => 'Ǯ', 'ǯ' => 'ǯ', 'ǰ' => 'ǰ', 'Ǵ' => 'Ǵ', 'ǵ' => 'ǵ', 'Ǹ' => 'Ǹ', 'ǹ' => 'ǹ', 'Ǻ' => 'Ǻ', 'ǻ' => 'ǻ', 'Ǽ' => 'Ǽ', 'ǽ' => 'ǽ', 'Ǿ' => 'Ǿ', 'ǿ' => 'ǿ', 'Ȁ' => 'Ȁ', 'ȁ' => 'ȁ', 'Ȃ' => 'Ȃ', 'ȃ' => 'ȃ', 'Ȅ' => 'Ȅ', 'ȅ' => 'ȅ', 'Ȇ' => 'Ȇ', 'ȇ' => 'ȇ', 'Ȉ' => 'Ȉ', 'ȉ' => 'ȉ', 'Ȋ' => 'Ȋ', 'ȋ' => 'ȋ', 'Ȍ' => 'Ȍ', 'ȍ' => 'ȍ', 'Ȏ' => 'Ȏ', 'ȏ' => 'ȏ', 'Ȑ' => 'Ȑ', 'ȑ' => 'ȑ', 'Ȓ' => 'Ȓ', 'ȓ' => 'ȓ', 'Ȕ' => 'Ȕ', 'ȕ' => 'ȕ', 'Ȗ' => 'Ȗ', 'ȗ' => 'ȗ', 'Ș' => 'Ș', 'ș' => 'ș', 'Ț' => 'Ț', 'ț' => 'ț', 'Ȟ' => 'Ȟ', 'ȟ' => 'ȟ', 'Ȧ' => 'Ȧ', 'ȧ' => 'ȧ', 'Ȩ' => 'Ȩ', 'ȩ' => 'ȩ', 'Ȫ' => 'Ȫ', 'ȫ' => 'ȫ', 'Ȭ' => 'Ȭ', 'ȭ' => 'ȭ', 'Ȯ' => 'Ȯ', 'ȯ' => 'ȯ', 'Ȱ' => 'Ȱ', 'ȱ' => 'ȱ', 'Ȳ' => 'Ȳ', 'ȳ' => 'ȳ', '΅' => '΅', 'Ά' => 'Ά', 'Έ' => 'Έ', 'Ή' => 'Ή', 'Ί' => 'Ί', 'Ό' => 'Ό', 'Ύ' => 'Ύ', 'Ώ' => 'Ώ', 'ΐ' => 'ΐ', 'Ϊ' => 'Ϊ', 'Ϋ' => 'Ϋ', 'ά' => 'ά', 'έ' => 'έ', 'ή' => 'ή', 'ί' => 'ί', 'ΰ' => 'ΰ', 'ϊ' => 'ϊ', 'ϋ' => 'ϋ', 'ό' => 'ό', 'ύ' => 'ύ', 'ώ' => 'ώ', 'ϓ' => 'ϓ', 'ϔ' => 'ϔ', 'Ѐ' => 'Ѐ', 'Ё' => 'Ё', 'Ѓ' => 'Ѓ', 'Ї' => 'Ї', 'Ќ' => 'Ќ', 'Ѝ' => 'Ѝ', 'Ў' => 'Ў', 'Й' => 'Й', 'й' => 'й', 'ѐ' => 'ѐ', 'ё' => 'ё', 'ѓ' => 'ѓ', 'ї' => 'ї', 'ќ' => 'ќ', 'ѝ' => 'ѝ', 'ў' => 'ў', 'Ѷ' => 'Ѷ', 'ѷ' => 'ѷ', 'Ӂ' => 'Ӂ', 'ӂ' => 'ӂ', 'Ӑ' => 'Ӑ', 'ӑ' => 'ӑ', 'Ӓ' => 'Ӓ', 'ӓ' => 'ӓ', 'Ӗ' => 'Ӗ', 'ӗ' => 'ӗ', 'Ӛ' => 'Ӛ', 'ӛ' => 'ӛ', 'Ӝ' => 'Ӝ', 'ӝ' => 'ӝ', 'Ӟ' => 'Ӟ', 'ӟ' => 'ӟ', 'Ӣ' => 'Ӣ', 'ӣ' => 'ӣ', 'Ӥ' => 'Ӥ', 'ӥ' => 'ӥ', 'Ӧ' => 'Ӧ', 'ӧ' => 'ӧ', 'Ӫ' => 'Ӫ', 'ӫ' => 'ӫ', 'Ӭ' => 'Ӭ', 'ӭ' => 'ӭ', 'Ӯ' => 'Ӯ', 'ӯ' => 'ӯ', 'Ӱ' => 'Ӱ', 'ӱ' => 'ӱ', 'Ӳ' => 'Ӳ', 'ӳ' => 'ӳ', 'Ӵ' => 'Ӵ', 'ӵ' => 'ӵ', 'Ӹ' => 'Ӹ', 'ӹ' => 'ӹ', 'آ' => 'آ', 'أ' => 'أ', 'ؤ' => 'ؤ', 'إ' => 'إ', 'ئ' => 'ئ', 'ۀ' => 'ۀ', 'ۂ' => 'ۂ', 'ۓ' => 'ۓ', 'ऩ' => 'ऩ', 'ऱ' => 'ऱ', 'ऴ' => 'ऴ', 'ো' => 'ো', 'ৌ' => 'ৌ', 'ୈ' => 'ୈ', 'ୋ' => 'ୋ', 'ୌ' => 'ୌ', 'ஔ' => 'ஔ', 'ொ' => 'ொ', 'ோ' => 'ோ', 'ௌ' => 'ௌ', 'ై' => 'ై', 'ೀ' => 'ೀ', 'ೇ' => 'ೇ', 'ೈ' => 'ೈ', 'ೊ' => 'ೊ', 'ೋ' => 'ೋ', 'ൊ' => 'ൊ', 'ോ' => 'ോ', 'ൌ' => 'ൌ', 'ේ' => 'ේ', 'ො' => 'ො', 'ෝ' => 'ෝ', 'ෞ' => 'ෞ', 'ဦ' => 'ဦ', 'ᬆ' => 'ᬆ', 'ᬈ' => 'ᬈ', 'ᬊ' => 'ᬊ', 'ᬌ' => 'ᬌ', 'ᬎ' => 'ᬎ', 'ᬒ' => 'ᬒ', 'ᬻ' => 'ᬻ', 'ᬽ' => 'ᬽ', 'ᭀ' => 'ᭀ', 'ᭁ' => 'ᭁ', 'ᭃ' => 'ᭃ', 'Ḁ' => 'Ḁ', 'ḁ' => 'ḁ', 'Ḃ' => 'Ḃ', 'ḃ' => 'ḃ', 'Ḅ' => 'Ḅ', 'ḅ' => 'ḅ', 'Ḇ' => 'Ḇ', 'ḇ' => 'ḇ', 'Ḉ' => 'Ḉ', 'ḉ' => 'ḉ', 'Ḋ' => 'Ḋ', 'ḋ' => 'ḋ', 'Ḍ' => 'Ḍ', 'ḍ' => 'ḍ', 'Ḏ' => 'Ḏ', 'ḏ' => 'ḏ', 'Ḑ' => 'Ḑ', 'ḑ' => 'ḑ', 'Ḓ' => 'Ḓ', 'ḓ' => 'ḓ', 'Ḕ' => 'Ḕ', 'ḕ' => 'ḕ', 'Ḗ' => 'Ḗ', 'ḗ' => 'ḗ', 'Ḙ' => 'Ḙ', 'ḙ' => 'ḙ', 'Ḛ' => 'Ḛ', 'ḛ' => 'ḛ', 'Ḝ' => 'Ḝ', 'ḝ' => 'ḝ', 'Ḟ' => 'Ḟ', 'ḟ' => 'ḟ', 'Ḡ' => 'Ḡ', 'ḡ' => 'ḡ', 'Ḣ' => 'Ḣ', 'ḣ' => 'ḣ', 'Ḥ' => 'Ḥ', 'ḥ' => 'ḥ', 'Ḧ' => 'Ḧ', 'ḧ' => 'ḧ', 'Ḩ' => 'Ḩ', 'ḩ' => 'ḩ', 'Ḫ' => 'Ḫ', 'ḫ' => 'ḫ', 'Ḭ' => 'Ḭ', 'ḭ' => 'ḭ', 'Ḯ' => 'Ḯ', 'ḯ' => 'ḯ', 'Ḱ' => 'Ḱ', 'ḱ' => 'ḱ', 'Ḳ' => 'Ḳ', 'ḳ' => 'ḳ', 'Ḵ' => 'Ḵ', 'ḵ' => 'ḵ', 'Ḷ' => 'Ḷ', 'ḷ' => 'ḷ', 'Ḹ' => 'Ḹ', 'ḹ' => 'ḹ', 'Ḻ' => 'Ḻ', 'ḻ' => 'ḻ', 'Ḽ' => 'Ḽ', 'ḽ' => 'ḽ', 'Ḿ' => 'Ḿ', 'ḿ' => 'ḿ', 'Ṁ' => 'Ṁ', 'ṁ' => 'ṁ', 'Ṃ' => 'Ṃ', 'ṃ' => 'ṃ', 'Ṅ' => 'Ṅ', 'ṅ' => 'ṅ', 'Ṇ' => 'Ṇ', 'ṇ' => 'ṇ', 'Ṉ' => 'Ṉ', 'ṉ' => 'ṉ', 'Ṋ' => 'Ṋ', 'ṋ' => 'ṋ', 'Ṍ' => 'Ṍ', 'ṍ' => 'ṍ', 'Ṏ' => 'Ṏ', 'ṏ' => 'ṏ', 'Ṑ' => 'Ṑ', 'ṑ' => 'ṑ', 'Ṓ' => 'Ṓ', 'ṓ' => 'ṓ', 'Ṕ' => 'Ṕ', 'ṕ' => 'ṕ', 'Ṗ' => 'Ṗ', 'ṗ' => 'ṗ', 'Ṙ' => 'Ṙ', 'ṙ' => 'ṙ', 'Ṛ' => 'Ṛ', 'ṛ' => 'ṛ', 'Ṝ' => 'Ṝ', 'ṝ' => 'ṝ', 'Ṟ' => 'Ṟ', 'ṟ' => 'ṟ', 'Ṡ' => 'Ṡ', 'ṡ' => 'ṡ', 'Ṣ' => 'Ṣ', 'ṣ' => 'ṣ', 'Ṥ' => 'Ṥ', 'ṥ' => 'ṥ', 'Ṧ' => 'Ṧ', 'ṧ' => 'ṧ', 'Ṩ' => 'Ṩ', 'ṩ' => 'ṩ', 'Ṫ' => 'Ṫ', 'ṫ' => 'ṫ', 'Ṭ' => 'Ṭ', 'ṭ' => 'ṭ', 'Ṯ' => 'Ṯ', 'ṯ' => 'ṯ', 'Ṱ' => 'Ṱ', 'ṱ' => 'ṱ', 'Ṳ' => 'Ṳ', 'ṳ' => 'ṳ', 'Ṵ' => 'Ṵ', 'ṵ' => 'ṵ', 'Ṷ' => 'Ṷ', 'ṷ' => 'ṷ', 'Ṹ' => 'Ṹ', 'ṹ' => 'ṹ', 'Ṻ' => 'Ṻ', 'ṻ' => 'ṻ', 'Ṽ' => 'Ṽ', 'ṽ' => 'ṽ', 'Ṿ' => 'Ṿ', 'ṿ' => 'ṿ', 'Ẁ' => 'Ẁ', 'ẁ' => 'ẁ', 'Ẃ' => 'Ẃ', 'ẃ' => 'ẃ', 'Ẅ' => 'Ẅ', 'ẅ' => 'ẅ', 'Ẇ' => 'Ẇ', 'ẇ' => 'ẇ', 'Ẉ' => 'Ẉ', 'ẉ' => 'ẉ', 'Ẋ' => 'Ẋ', 'ẋ' => 'ẋ', 'Ẍ' => 'Ẍ', 'ẍ' => 'ẍ', 'Ẏ' => 'Ẏ', 'ẏ' => 'ẏ', 'Ẑ' => 'Ẑ', 'ẑ' => 'ẑ', 'Ẓ' => 'Ẓ', 'ẓ' => 'ẓ', 'Ẕ' => 'Ẕ', 'ẕ' => 'ẕ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẛ' => 'ẛ', 'Ạ' => 'Ạ', 'ạ' => 'ạ', 'Ả' => 'Ả', 'ả' => 'ả', 'Ấ' => 'Ấ', 'ấ' => 'ấ', 'Ầ' => 'Ầ', 'ầ' => 'ầ', 'Ẩ' => 'Ẩ', 'ẩ' => 'ẩ', 'Ẫ' => 'Ẫ', 'ẫ' => 'ẫ', 'Ậ' => 'Ậ', 'ậ' => 'ậ', 'Ắ' => 'Ắ', 'ắ' => 'ắ', 'Ằ' => 'Ằ', 'ằ' => 'ằ', 'Ẳ' => 'Ẳ', 'ẳ' => 'ẳ', 'Ẵ' => 'Ẵ', 'ẵ' => 'ẵ', 'Ặ' => 'Ặ', 'ặ' => 'ặ', 'Ẹ' => 'Ẹ', 'ẹ' => 'ẹ', 'Ẻ' => 'Ẻ', 'ẻ' => 'ẻ', 'Ẽ' => 'Ẽ', 'ẽ' => 'ẽ', 'Ế' => 'Ế', 'ế' => 'ế', 'Ề' => 'Ề', 'ề' => 'ề', 'Ể' => 'Ể', 'ể' => 'ể', 'Ễ' => 'Ễ', 'ễ' => 'ễ', 'Ệ' => 'Ệ', 'ệ' => 'ệ', 'Ỉ' => 'Ỉ', 'ỉ' => 'ỉ', 'Ị' => 'Ị', 'ị' => 'ị', 'Ọ' => 'Ọ', 'ọ' => 'ọ', 'Ỏ' => 'Ỏ', 'ỏ' => 'ỏ', 'Ố' => 'Ố', 'ố' => 'ố', 'Ồ' => 'Ồ', 'ồ' => 'ồ', 'Ổ' => 'Ổ', 'ổ' => 'ổ', 'Ỗ' => 'Ỗ', 'ỗ' => 'ỗ', 'Ộ' => 'Ộ', 'ộ' => 'ộ', 'Ớ' => 'Ớ', 'ớ' => 'ớ', 'Ờ' => 'Ờ', 'ờ' => 'ờ', 'Ở' => 'Ở', 'ở' => 'ở', 'Ỡ' => 'Ỡ', 'ỡ' => 'ỡ', 'Ợ' => 'Ợ', 'ợ' => 'ợ', 'Ụ' => 'Ụ', 'ụ' => 'ụ', 'Ủ' => 'Ủ', 'ủ' => 'ủ', 'Ứ' => 'Ứ', 'ứ' => 'ứ', 'Ừ' => 'Ừ', 'ừ' => 'ừ', 'Ử' => 'Ử', 'ử' => 'ử', 'Ữ' => 'Ữ', 'ữ' => 'ữ', 'Ự' => 'Ự', 'ự' => 'ự', 'Ỳ' => 'Ỳ', 'ỳ' => 'ỳ', 'Ỵ' => 'Ỵ', 'ỵ' => 'ỵ', 'Ỷ' => 'Ỷ', 'ỷ' => 'ỷ', 'Ỹ' => 'Ỹ', 'ỹ' => 'ỹ', 'ἀ' => 'ἀ', 'ἁ' => 'ἁ', 'ἂ' => 'ἂ', 'ἃ' => 'ἃ', 'ἄ' => 'ἄ', 'ἅ' => 'ἅ', 'ἆ' => 'ἆ', 'ἇ' => 'ἇ', 'Ἀ' => 'Ἀ', 'Ἁ' => 'Ἁ', 'Ἂ' => 'Ἂ', 'Ἃ' => 'Ἃ', 'Ἄ' => 'Ἄ', 'Ἅ' => 'Ἅ', 'Ἆ' => 'Ἆ', 'Ἇ' => 'Ἇ', 'ἐ' => 'ἐ', 'ἑ' => 'ἑ', 'ἒ' => 'ἒ', 'ἓ' => 'ἓ', 'ἔ' => 'ἔ', 'ἕ' => 'ἕ', 'Ἐ' => 'Ἐ', 'Ἑ' => 'Ἑ', 'Ἒ' => 'Ἒ', 'Ἓ' => 'Ἓ', 'Ἔ' => 'Ἔ', 'Ἕ' => 'Ἕ', 'ἠ' => 'ἠ', 'ἡ' => 'ἡ', 'ἢ' => 'ἢ', 'ἣ' => 'ἣ', 'ἤ' => 'ἤ', 'ἥ' => 'ἥ', 'ἦ' => 'ἦ', 'ἧ' => 'ἧ', 'Ἠ' => 'Ἠ', 'Ἡ' => 'Ἡ', 'Ἢ' => 'Ἢ', 'Ἣ' => 'Ἣ', 'Ἤ' => 'Ἤ', 'Ἥ' => 'Ἥ', 'Ἦ' => 'Ἦ', 'Ἧ' => 'Ἧ', 'ἰ' => 'ἰ', 'ἱ' => 'ἱ', 'ἲ' => 'ἲ', 'ἳ' => 'ἳ', 'ἴ' => 'ἴ', 'ἵ' => 'ἵ', 'ἶ' => 'ἶ', 'ἷ' => 'ἷ', 'Ἰ' => 'Ἰ', 'Ἱ' => 'Ἱ', 'Ἲ' => 'Ἲ', 'Ἳ' => 'Ἳ', 'Ἴ' => 'Ἴ', 'Ἵ' => 'Ἵ', 'Ἶ' => 'Ἶ', 'Ἷ' => 'Ἷ', 'ὀ' => 'ὀ', 'ὁ' => 'ὁ', 'ὂ' => 'ὂ', 'ὃ' => 'ὃ', 'ὄ' => 'ὄ', 'ὅ' => 'ὅ', 'Ὀ' => 'Ὀ', 'Ὁ' => 'Ὁ', 'Ὂ' => 'Ὂ', 'Ὃ' => 'Ὃ', 'Ὄ' => 'Ὄ', 'Ὅ' => 'Ὅ', 'ὐ' => 'ὐ', 'ὑ' => 'ὑ', 'ὒ' => 'ὒ', 'ὓ' => 'ὓ', 'ὔ' => 'ὔ', 'ὕ' => 'ὕ', 'ὖ' => 'ὖ', 'ὗ' => 'ὗ', 'Ὑ' => 'Ὑ', 'Ὓ' => 'Ὓ', 'Ὕ' => 'Ὕ', 'Ὗ' => 'Ὗ', 'ὠ' => 'ὠ', 'ὡ' => 'ὡ', 'ὢ' => 'ὢ', 'ὣ' => 'ὣ', 'ὤ' => 'ὤ', 'ὥ' => 'ὥ', 'ὦ' => 'ὦ', 'ὧ' => 'ὧ', 'Ὠ' => 'Ὠ', 'Ὡ' => 'Ὡ', 'Ὢ' => 'Ὢ', 'Ὣ' => 'Ὣ', 'Ὤ' => 'Ὤ', 'Ὥ' => 'Ὥ', 'Ὦ' => 'Ὦ', 'Ὧ' => 'Ὧ', 'ὰ' => 'ὰ', 'ὲ' => 'ὲ', 'ὴ' => 'ὴ', 'ὶ' => 'ὶ', 'ὸ' => 'ὸ', 'ὺ' => 'ὺ', 'ὼ' => 'ὼ', 'ᾀ' => 'ᾀ', 'ᾁ' => 'ᾁ', 'ᾂ' => 'ᾂ', 'ᾃ' => 'ᾃ', 'ᾄ' => 'ᾄ', 'ᾅ' => 'ᾅ', 'ᾆ' => 'ᾆ', 'ᾇ' => 'ᾇ', 'ᾈ' => 'ᾈ', 'ᾉ' => 'ᾉ', 'ᾊ' => 'ᾊ', 'ᾋ' => 'ᾋ', 'ᾌ' => 'ᾌ', 'ᾍ' => 'ᾍ', 'ᾎ' => 'ᾎ', 'ᾏ' => 'ᾏ', 'ᾐ' => 'ᾐ', 'ᾑ' => 'ᾑ', 'ᾒ' => 'ᾒ', 'ᾓ' => 'ᾓ', 'ᾔ' => 'ᾔ', 'ᾕ' => 'ᾕ', 'ᾖ' => 'ᾖ', 'ᾗ' => 'ᾗ', 'ᾘ' => 'ᾘ', 'ᾙ' => 'ᾙ', 'ᾚ' => 'ᾚ', 'ᾛ' => 'ᾛ', 'ᾜ' => 'ᾜ', 'ᾝ' => 'ᾝ', 'ᾞ' => 'ᾞ', 'ᾟ' => 'ᾟ', 'ᾠ' => 'ᾠ', 'ᾡ' => 'ᾡ', 'ᾢ' => 'ᾢ', 'ᾣ' => 'ᾣ', 'ᾤ' => 'ᾤ', 'ᾥ' => 'ᾥ', 'ᾦ' => 'ᾦ', 'ᾧ' => 'ᾧ', 'ᾨ' => 'ᾨ', 'ᾩ' => 'ᾩ', 'ᾪ' => 'ᾪ', 'ᾫ' => 'ᾫ', 'ᾬ' => 'ᾬ', 'ᾭ' => 'ᾭ', 'ᾮ' => 'ᾮ', 'ᾯ' => 'ᾯ', 'ᾰ' => 'ᾰ', 'ᾱ' => 'ᾱ', 'ᾲ' => 'ᾲ', 'ᾳ' => 'ᾳ', 'ᾴ' => 'ᾴ', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾷ', 'Ᾰ' => 'Ᾰ', 'Ᾱ' => 'Ᾱ', 'Ὰ' => 'Ὰ', 'ᾼ' => 'ᾼ', '῁' => '῁', 'ῂ' => 'ῂ', 'ῃ' => 'ῃ', 'ῄ' => 'ῄ', 'ῆ' => 'ῆ', 'ῇ' => 'ῇ', 'Ὲ' => 'Ὲ', 'Ὴ' => 'Ὴ', 'ῌ' => 'ῌ', '῍' => '῍', '῎' => '῎', '῏' => '῏', 'ῐ' => 'ῐ', 'ῑ' => 'ῑ', 'ῒ' => 'ῒ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'Ῐ' => 'Ῐ', 'Ῑ' => 'Ῑ', 'Ὶ' => 'Ὶ', '῝' => '῝', '῞' => '῞', '῟' => '῟', 'ῠ' => 'ῠ', 'ῡ' => 'ῡ', 'ῢ' => 'ῢ', 'ῤ' => 'ῤ', 'ῥ' => 'ῥ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'Ῠ' => 'Ῠ', 'Ῡ' => 'Ῡ', 'Ὺ' => 'Ὺ', 'Ῥ' => 'Ῥ', '῭' => '῭', 'ῲ' => 'ῲ', 'ῳ' => 'ῳ', 'ῴ' => 'ῴ', 'ῶ' => 'ῶ', 'ῷ' => 'ῷ', 'Ὸ' => 'Ὸ', 'Ὼ' => 'Ὼ', 'ῼ' => 'ῼ', '↚' => '↚', '↛' => '↛', '↮' => '↮', '⇍' => '⇍', '⇎' => '⇎', '⇏' => '⇏', '∄' => '∄', '∉' => '∉', '∌' => '∌', '∤' => '∤', '∦' => '∦', '≁' => '≁', '≄' => '≄', '≇' => '≇', '≉' => '≉', '≠' => '≠', '≢' => '≢', '≭' => '≭', '≮' => '≮', '≯' => '≯', '≰' => '≰', '≱' => '≱', '≴' => '≴', '≵' => '≵', '≸' => '≸', '≹' => '≹', '⊀' => '⊀', '⊁' => '⊁', '⊄' => '⊄', '⊅' => '⊅', '⊈' => '⊈', '⊉' => '⊉', '⊬' => '⊬', '⊭' => '⊭', '⊮' => '⊮', '⊯' => '⊯', '⋠' => '⋠', '⋡' => '⋡', '⋢' => '⋢', '⋣' => '⋣', '⋪' => '⋪', '⋫' => '⋫', '⋬' => '⋬', '⋭' => '⋭', 'が' => 'が', 'ぎ' => 'ぎ', 'ぐ' => 'ぐ', 'げ' => 'げ', 'ご' => 'ご', 'ざ' => 'ざ', 'じ' => 'じ', 'ず' => 'ず', 'ぜ' => 'ぜ', 'ぞ' => 'ぞ', 'だ' => 'だ', 'ぢ' => 'ぢ', 'づ' => 'づ', 'で' => 'で', 'ど' => 'ど', 'ば' => 'ば', 'ぱ' => 'ぱ', 'び' => 'び', 'ぴ' => 'ぴ', 'ぶ' => 'ぶ', 'ぷ' => 'ぷ', 'べ' => 'べ', 'ぺ' => 'ぺ', 'ぼ' => 'ぼ', 'ぽ' => 'ぽ', 'ゔ' => 'ゔ', 'ゞ' => 'ゞ', 'ガ' => 'ガ', 'ギ' => 'ギ', 'グ' => 'グ', 'ゲ' => 'ゲ', 'ゴ' => 'ゴ', 'ザ' => 'ザ', 'ジ' => 'ジ', 'ズ' => 'ズ', 'ゼ' => 'ゼ', 'ゾ' => 'ゾ', 'ダ' => 'ダ', 'ヂ' => 'ヂ', 'ヅ' => 'ヅ', 'デ' => 'デ', 'ド' => 'ド', 'バ' => 'バ', 'パ' => 'パ', 'ビ' => 'ビ', 'ピ' => 'ピ', 'ブ' => 'ブ', 'プ' => 'プ', 'ベ' => 'ベ', 'ペ' => 'ペ', 'ボ' => 'ボ', 'ポ' => 'ポ', 'ヴ' => 'ヴ', 'ヷ' => 'ヷ', 'ヸ' => 'ヸ', 'ヹ' => 'ヹ', 'ヺ' => 'ヺ', 'ヾ' => 'ヾ', '𑂚' => '𑂚', '𑂜' => '𑂜', '𑂫' => '𑂫', '𑄮' => '𑄮', '𑄯' => '𑄯', '𑍋' => '𑍋', '𑍌' => '𑍌', '𑒻' => '𑒻', '𑒼' => '𑒼', '𑒾' => '𑒾', '𑖺' => '𑖺', '𑖻' => '𑖻', '𑤸' => '𑤸', ); 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', 'Ā' => 'Ā', 'ā' => 'ā', 'Ă' => 'Ă', 'ă' => 'ă', 'Ą' => 'Ą', 'ą' => 'ą', 'Ć' => 'Ć', 'ć' => 'ć', 'Ĉ' => 'Ĉ', 'ĉ' => 'ĉ', 'Ċ' => 'Ċ', 'ċ' => 'ċ', 'Č' => 'Č', 'č' => 'č', 'Ď' => 'Ď', 'ď' => 'ď', 'Ē' => 'Ē', 'ē' => 'ē', 'Ĕ' => 'Ĕ', 'ĕ' => 'ĕ', 'Ė' => 'Ė', 'ė' => 'ė', 'Ę' => 'Ę', 'ę' => 'ę', 'Ě' => 'Ě', 'ě' => 'ě', 'Ĝ' => 'Ĝ', 'ĝ' => 'ĝ', 'Ğ' => 'Ğ', 'ğ' => 'ğ', 'Ġ' => 'Ġ', 'ġ' => 'ġ', 'Ģ' => 'Ģ', 'ģ' => 'ģ', 'Ĥ' => 'Ĥ', 'ĥ' => 'ĥ', 'Ĩ' => 'Ĩ', 'ĩ' => 'ĩ', 'Ī' => 'Ī', 'ī' => 'ī', 'Ĭ' => 'Ĭ', 'ĭ' => 'ĭ', 'Į' => 'Į', 'į' => 'į', 'İ' => 'İ', 'Ĵ' => 'Ĵ', 'ĵ' => 'ĵ', 'Ķ' => 'Ķ', 'ķ' => 'ķ', 'Ĺ' => 'Ĺ', 'ĺ' => 'ĺ', 'Ļ' => 'Ļ', 'ļ' => 'ļ', 'Ľ' => 'Ľ', 'ľ' => 'ľ', 'Ń' => 'Ń', 'ń' => 'ń', 'Ņ' => 'Ņ', 'ņ' => 'ņ', 'Ň' => 'Ň', 'ň' => 'ň', 'Ō' => 'Ō', 'ō' => 'ō', 'Ŏ' => 'Ŏ', 'ŏ' => 'ŏ', 'Ő' => 'Ő', 'ő' => 'ő', 'Ŕ' => 'Ŕ', 'ŕ' => 'ŕ', 'Ŗ' => 'Ŗ', 'ŗ' => 'ŗ', 'Ř' => 'Ř', 'ř' => 'ř', 'Ś' => 'Ś', 'ś' => 'ś', 'Ŝ' => 'Ŝ', 'ŝ' => 'ŝ', 'Ş' => 'Ş', 'ş' => 'ş', 'Š' => 'Š', 'š' => 'š', 'Ţ' => 'Ţ', 'ţ' => 'ţ', 'Ť' => 'Ť', 'ť' => 'ť', 'Ũ' => 'Ũ', 'ũ' => 'ũ', 'Ū' => 'Ū', 'ū' => 'ū', 'Ŭ' => 'Ŭ', 'ŭ' => 'ŭ', 'Ů' => 'Ů', 'ů' => 'ů', 'Ű' => 'Ű', 'ű' => 'ű', 'Ų' => 'Ų', 'ų' => 'ų', 'Ŵ' => 'Ŵ', 'ŵ' => 'ŵ', 'Ŷ' => 'Ŷ', 'ŷ' => 'ŷ', 'Ÿ' => 'Ÿ', 'Ź' => 'Ź', 'ź' => 'ź', 'Ż' => 'Ż', 'ż' => 'ż', 'Ž' => 'Ž', 'ž' => 'ž', 'Ơ' => 'Ơ', 'ơ' => 'ơ', 'Ư' => 'Ư', 'ư' => 'ư', 'Ǎ' => 'Ǎ', 'ǎ' => 'ǎ', 'Ǐ' => 'Ǐ', 'ǐ' => 'ǐ', 'Ǒ' => 'Ǒ', 'ǒ' => 'ǒ', 'Ǔ' => 'Ǔ', 'ǔ' => 'ǔ', 'Ǖ' => 'Ǖ', 'ǖ' => 'ǖ', 'Ǘ' => 'Ǘ', 'ǘ' => 'ǘ', 'Ǚ' => 'Ǚ', 'ǚ' => 'ǚ', 'Ǜ' => 'Ǜ', 'ǜ' => 'ǜ', 'Ǟ' => 'Ǟ', 'ǟ' => 'ǟ', 'Ǡ' => 'Ǡ', 'ǡ' => 'ǡ', 'Ǣ' => 'Ǣ', 'ǣ' => 'ǣ', 'Ǧ' => 'Ǧ', 'ǧ' => 'ǧ', 'Ǩ' => 'Ǩ', 'ǩ' => 'ǩ', 'Ǫ' => 'Ǫ', 'ǫ' => 'ǫ', 'Ǭ' => 'Ǭ', 'ǭ' => 'ǭ', 'Ǯ' => 'Ǯ', 'ǯ' => 'ǯ', 'ǰ' => 'ǰ', 'Ǵ' => 'Ǵ', 'ǵ' => 'ǵ', 'Ǹ' => 'Ǹ', 'ǹ' => 'ǹ', 'Ǻ' => 'Ǻ', 'ǻ' => 'ǻ', 'Ǽ' => 'Ǽ', 'ǽ' => 'ǽ', 'Ǿ' => 'Ǿ', 'ǿ' => 'ǿ', 'Ȁ' => 'Ȁ', 'ȁ' => 'ȁ', 'Ȃ' => 'Ȃ', 'ȃ' => 'ȃ', 'Ȅ' => 'Ȅ', 'ȅ' => 'ȅ', 'Ȇ' => 'Ȇ', 'ȇ' => 'ȇ', 'Ȉ' => 'Ȉ', 'ȉ' => 'ȉ', 'Ȋ' => 'Ȋ', 'ȋ' => 'ȋ', 'Ȍ' => 'Ȍ', 'ȍ' => 'ȍ', 'Ȏ' => 'Ȏ', 'ȏ' => 'ȏ', 'Ȑ' => 'Ȑ', 'ȑ' => 'ȑ', 'Ȓ' => 'Ȓ', 'ȓ' => 'ȓ', 'Ȕ' => 'Ȕ', 'ȕ' => 'ȕ', 'Ȗ' => 'Ȗ', 'ȗ' => 'ȗ', 'Ș' => 'Ș', 'ș' => 'ș', 'Ț' => 'Ț', 'ț' => 'ț', 'Ȟ' => 'Ȟ', 'ȟ' => 'ȟ', 'Ȧ' => 'Ȧ', 'ȧ' => 'ȧ', 'Ȩ' => 'Ȩ', 'ȩ' => 'ȩ', 'Ȫ' => 'Ȫ', 'ȫ' => 'ȫ', 'Ȭ' => 'Ȭ', 'ȭ' => 'ȭ', 'Ȯ' => 'Ȯ', 'ȯ' => 'ȯ', 'Ȱ' => 'Ȱ', 'ȱ' => 'ȱ', 'Ȳ' => 'Ȳ', 'ȳ' => 'ȳ', '̀' => '̀', '́' => '́', '̓' => '̓', '̈́' => '̈́', 'ʹ' => 'ʹ', ';' => ';', '΅' => '΅', 'Ά' => 'Ά', '·' => '·', 'Έ' => 'Έ', 'Ή' => 'Ή', 'Ί' => 'Ί', 'Ό' => 'Ό', 'Ύ' => 'Ύ', 'Ώ' => 'Ώ', 'ΐ' => 'ΐ', 'Ϊ' => 'Ϊ', 'Ϋ' => 'Ϋ', 'ά' => 'ά', 'έ' => 'έ', 'ή' => 'ή', 'ί' => 'ί', 'ΰ' => 'ΰ', 'ϊ' => 'ϊ', 'ϋ' => 'ϋ', 'ό' => 'ό', 'ύ' => 'ύ', 'ώ' => 'ώ', 'ϓ' => 'ϓ', 'ϔ' => 'ϔ', 'Ѐ' => 'Ѐ', 'Ё' => 'Ё', 'Ѓ' => 'Ѓ', 'Ї' => 'Ї', 'Ќ' => 'Ќ', 'Ѝ' => 'Ѝ', 'Ў' => 'Ў', 'Й' => 'Й', 'й' => 'й', 'ѐ' => 'ѐ', 'ё' => 'ё', 'ѓ' => 'ѓ', 'ї' => 'ї', 'ќ' => 'ќ', 'ѝ' => 'ѝ', 'ў' => 'ў', 'Ѷ' => 'Ѷ', 'ѷ' => 'ѷ', 'Ӂ' => 'Ӂ', 'ӂ' => 'ӂ', 'Ӑ' => 'Ӑ', 'ӑ' => 'ӑ', 'Ӓ' => 'Ӓ', 'ӓ' => 'ӓ', 'Ӗ' => 'Ӗ', 'ӗ' => 'ӗ', 'Ӛ' => 'Ӛ', 'ӛ' => 'ӛ', 'Ӝ' => 'Ӝ', 'ӝ' => 'ӝ', 'Ӟ' => 'Ӟ', 'ӟ' => 'ӟ', 'Ӣ' => 'Ӣ', 'ӣ' => 'ӣ', 'Ӥ' => 'Ӥ', 'ӥ' => 'ӥ', 'Ӧ' => 'Ӧ', 'ӧ' => 'ӧ', 'Ӫ' => 'Ӫ', 'ӫ' => 'ӫ', 'Ӭ' => 'Ӭ', 'ӭ' => 'ӭ', 'Ӯ' => 'Ӯ', 'ӯ' => 'ӯ', 'Ӱ' => 'Ӱ', 'ӱ' => 'ӱ', 'Ӳ' => 'Ӳ', 'ӳ' => 'ӳ', 'Ӵ' => 'Ӵ', 'ӵ' => 'ӵ', 'Ӹ' => 'Ӹ', 'ӹ' => 'ӹ', 'آ' => 'آ', 'أ' => 'أ', 'ؤ' => 'ؤ', 'إ' => 'إ', 'ئ' => 'ئ', 'ۀ' => 'ۀ', 'ۂ' => 'ۂ', 'ۓ' => 'ۓ', 'ऩ' => 'ऩ', 'ऱ' => 'ऱ', 'ऴ' => 'ऴ', 'क़' => 'क़', 'ख़' => 'ख़', 'ग़' => 'ग़', 'ज़' => 'ज़', 'ड़' => 'ड़', 'ढ़' => 'ढ़', 'फ़' => 'फ़', 'य़' => 'य़', 'ো' => 'ো', 'ৌ' => 'ৌ', 'ড়' => 'ড়', 'ঢ়' => 'ঢ়', 'য়' => 'য়', 'ਲ਼' => 'ਲ਼', 'ਸ਼' => 'ਸ਼', 'ਖ਼' => 'ਖ਼', 'ਗ਼' => 'ਗ਼', 'ਜ਼' => 'ਜ਼', 'ਫ਼' => 'ਫ਼', 'ୈ' => 'ୈ', 'ୋ' => 'ୋ', 'ୌ' => 'ୌ', 'ଡ଼' => 'ଡ଼', 'ଢ଼' => 'ଢ଼', 'ஔ' => 'ஔ', 'ொ' => 'ொ', 'ோ' => 'ோ', 'ௌ' => 'ௌ', 'ై' => 'ై', 'ೀ' => 'ೀ', 'ೇ' => 'ೇ', 'ೈ' => 'ೈ', 'ೊ' => 'ೊ', 'ೋ' => 'ೋ', 'ൊ' => 'ൊ', 'ോ' => 'ോ', 'ൌ' => 'ൌ', 'ේ' => 'ේ', 'ො' => 'ො', 'ෝ' => 'ෝ', 'ෞ' => 'ෞ', 'གྷ' => 'གྷ', 'ཌྷ' => 'ཌྷ', 'དྷ' => 'དྷ', 'བྷ' => 'བྷ', 'ཛྷ' => 'ཛྷ', 'ཀྵ' => 'ཀྵ', 'ཱི' => 'ཱི', 'ཱུ' => 'ཱུ', 'ྲྀ' => 'ྲྀ', 'ླྀ' => 'ླྀ', 'ཱྀ' => 'ཱྀ', 'ྒྷ' => 'ྒྷ', 'ྜྷ' => 'ྜྷ', 'ྡྷ' => 'ྡྷ', 'ྦྷ' => 'ྦྷ', 'ྫྷ' => 'ྫྷ', 'ྐྵ' => 'ྐྵ', 'ဦ' => 'ဦ', 'ᬆ' => 'ᬆ', 'ᬈ' => 'ᬈ', 'ᬊ' => 'ᬊ', 'ᬌ' => 'ᬌ', 'ᬎ' => 'ᬎ', 'ᬒ' => 'ᬒ', 'ᬻ' => 'ᬻ', 'ᬽ' => 'ᬽ', 'ᭀ' => 'ᭀ', 'ᭁ' => 'ᭁ', 'ᭃ' => 'ᭃ', 'Ḁ' => 'Ḁ', 'ḁ' => 'ḁ', 'Ḃ' => 'Ḃ', 'ḃ' => 'ḃ', 'Ḅ' => 'Ḅ', 'ḅ' => 'ḅ', 'Ḇ' => 'Ḇ', 'ḇ' => 'ḇ', 'Ḉ' => 'Ḉ', 'ḉ' => 'ḉ', 'Ḋ' => 'Ḋ', 'ḋ' => 'ḋ', 'Ḍ' => 'Ḍ', 'ḍ' => 'ḍ', 'Ḏ' => 'Ḏ', 'ḏ' => 'ḏ', 'Ḑ' => 'Ḑ', 'ḑ' => 'ḑ', 'Ḓ' => 'Ḓ', 'ḓ' => 'ḓ', 'Ḕ' => 'Ḕ', 'ḕ' => 'ḕ', 'Ḗ' => 'Ḗ', 'ḗ' => 'ḗ', 'Ḙ' => 'Ḙ', 'ḙ' => 'ḙ', 'Ḛ' => 'Ḛ', 'ḛ' => 'ḛ', 'Ḝ' => 'Ḝ', 'ḝ' => 'ḝ', 'Ḟ' => 'Ḟ', 'ḟ' => 'ḟ', 'Ḡ' => 'Ḡ', 'ḡ' => 'ḡ', 'Ḣ' => 'Ḣ', 'ḣ' => 'ḣ', 'Ḥ' => 'Ḥ', 'ḥ' => 'ḥ', 'Ḧ' => 'Ḧ', 'ḧ' => 'ḧ', 'Ḩ' => 'Ḩ', 'ḩ' => 'ḩ', 'Ḫ' => 'Ḫ', 'ḫ' => 'ḫ', 'Ḭ' => 'Ḭ', 'ḭ' => 'ḭ', 'Ḯ' => 'Ḯ', 'ḯ' => 'ḯ', 'Ḱ' => 'Ḱ', 'ḱ' => 'ḱ', 'Ḳ' => 'Ḳ', 'ḳ' => 'ḳ', 'Ḵ' => 'Ḵ', 'ḵ' => 'ḵ', 'Ḷ' => 'Ḷ', 'ḷ' => 'ḷ', 'Ḹ' => 'Ḹ', 'ḹ' => 'ḹ', 'Ḻ' => 'Ḻ', 'ḻ' => 'ḻ', 'Ḽ' => 'Ḽ', 'ḽ' => 'ḽ', 'Ḿ' => 'Ḿ', 'ḿ' => 'ḿ', 'Ṁ' => 'Ṁ', 'ṁ' => 'ṁ', 'Ṃ' => 'Ṃ', 'ṃ' => 'ṃ', 'Ṅ' => 'Ṅ', 'ṅ' => 'ṅ', 'Ṇ' => 'Ṇ', 'ṇ' => 'ṇ', 'Ṉ' => 'Ṉ', 'ṉ' => 'ṉ', 'Ṋ' => 'Ṋ', 'ṋ' => 'ṋ', 'Ṍ' => 'Ṍ', 'ṍ' => 'ṍ', 'Ṏ' => 'Ṏ', 'ṏ' => 'ṏ', 'Ṑ' => 'Ṑ', 'ṑ' => 'ṑ', 'Ṓ' => 'Ṓ', 'ṓ' => 'ṓ', 'Ṕ' => 'Ṕ', 'ṕ' => 'ṕ', 'Ṗ' => 'Ṗ', 'ṗ' => 'ṗ', 'Ṙ' => 'Ṙ', 'ṙ' => 'ṙ', 'Ṛ' => 'Ṛ', 'ṛ' => 'ṛ', 'Ṝ' => 'Ṝ', 'ṝ' => 'ṝ', 'Ṟ' => 'Ṟ', 'ṟ' => 'ṟ', 'Ṡ' => 'Ṡ', 'ṡ' => 'ṡ', 'Ṣ' => 'Ṣ', 'ṣ' => 'ṣ', 'Ṥ' => 'Ṥ', 'ṥ' => 'ṥ', 'Ṧ' => 'Ṧ', 'ṧ' => 'ṧ', 'Ṩ' => 'Ṩ', 'ṩ' => 'ṩ', 'Ṫ' => 'Ṫ', 'ṫ' => 'ṫ', 'Ṭ' => 'Ṭ', 'ṭ' => 'ṭ', 'Ṯ' => 'Ṯ', 'ṯ' => 'ṯ', 'Ṱ' => 'Ṱ', 'ṱ' => 'ṱ', 'Ṳ' => 'Ṳ', 'ṳ' => 'ṳ', 'Ṵ' => 'Ṵ', 'ṵ' => 'ṵ', 'Ṷ' => 'Ṷ', 'ṷ' => 'ṷ', 'Ṹ' => 'Ṹ', 'ṹ' => 'ṹ', 'Ṻ' => 'Ṻ', 'ṻ' => 'ṻ', 'Ṽ' => 'Ṽ', 'ṽ' => 'ṽ', 'Ṿ' => 'Ṿ', 'ṿ' => 'ṿ', 'Ẁ' => 'Ẁ', 'ẁ' => 'ẁ', 'Ẃ' => 'Ẃ', 'ẃ' => 'ẃ', 'Ẅ' => 'Ẅ', 'ẅ' => 'ẅ', 'Ẇ' => 'Ẇ', 'ẇ' => 'ẇ', 'Ẉ' => 'Ẉ', 'ẉ' => 'ẉ', 'Ẋ' => 'Ẋ', 'ẋ' => 'ẋ', 'Ẍ' => 'Ẍ', 'ẍ' => 'ẍ', 'Ẏ' => 'Ẏ', 'ẏ' => 'ẏ', 'Ẑ' => 'Ẑ', 'ẑ' => 'ẑ', 'Ẓ' => 'Ẓ', 'ẓ' => 'ẓ', 'Ẕ' => 'Ẕ', 'ẕ' => 'ẕ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẛ' => 'ẛ', 'Ạ' => 'Ạ', 'ạ' => 'ạ', 'Ả' => 'Ả', 'ả' => 'ả', 'Ấ' => 'Ấ', 'ấ' => 'ấ', 'Ầ' => 'Ầ', 'ầ' => 'ầ', 'Ẩ' => 'Ẩ', 'ẩ' => 'ẩ', 'Ẫ' => 'Ẫ', 'ẫ' => 'ẫ', 'Ậ' => 'Ậ', 'ậ' => 'ậ', 'Ắ' => 'Ắ', 'ắ' => 'ắ', 'Ằ' => 'Ằ', 'ằ' => 'ằ', 'Ẳ' => 'Ẳ', 'ẳ' => 'ẳ', 'Ẵ' => 'Ẵ', 'ẵ' => 'ẵ', 'Ặ' => 'Ặ', 'ặ' => 'ặ', 'Ẹ' => 'Ẹ', 'ẹ' => 'ẹ', 'Ẻ' => 'Ẻ', 'ẻ' => 'ẻ', 'Ẽ' => 'Ẽ', 'ẽ' => 'ẽ', 'Ế' => 'Ế', 'ế' => 'ế', 'Ề' => 'Ề', 'ề' => 'ề', 'Ể' => 'Ể', 'ể' => 'ể', 'Ễ' => 'Ễ', 'ễ' => 'ễ', 'Ệ' => 'Ệ', 'ệ' => 'ệ', 'Ỉ' => 'Ỉ', 'ỉ' => 'ỉ', 'Ị' => 'Ị', 'ị' => 'ị', 'Ọ' => 'Ọ', 'ọ' => 'ọ', 'Ỏ' => 'Ỏ', 'ỏ' => 'ỏ', 'Ố' => 'Ố', 'ố' => 'ố', 'Ồ' => 'Ồ', 'ồ' => 'ồ', 'Ổ' => 'Ổ', 'ổ' => 'ổ', 'Ỗ' => 'Ỗ', 'ỗ' => 'ỗ', 'Ộ' => 'Ộ', 'ộ' => 'ộ', 'Ớ' => 'Ớ', 'ớ' => 'ớ', 'Ờ' => 'Ờ', 'ờ' => 'ờ', 'Ở' => 'Ở', 'ở' => 'ở', 'Ỡ' => 'Ỡ', 'ỡ' => 'ỡ', 'Ợ' => 'Ợ', 'ợ' => 'ợ', 'Ụ' => 'Ụ', 'ụ' => 'ụ', 'Ủ' => 'Ủ', 'ủ' => 'ủ', 'Ứ' => 'Ứ', 'ứ' => 'ứ', 'Ừ' => 'Ừ', 'ừ' => 'ừ', 'Ử' => 'Ử', 'ử' => 'ử', 'Ữ' => 'Ữ', 'ữ' => 'ữ', 'Ự' => 'Ự', 'ự' => 'ự', 'Ỳ' => 'Ỳ', 'ỳ' => 'ỳ', 'Ỵ' => 'Ỵ', 'ỵ' => 'ỵ', 'Ỷ' => 'Ỷ', 'ỷ' => 'ỷ', 'Ỹ' => 'Ỹ', 'ỹ' => 'ỹ', 'ἀ' => 'ἀ', 'ἁ' => 'ἁ', 'ἂ' => 'ἂ', 'ἃ' => 'ἃ', 'ἄ' => 'ἄ', 'ἅ' => 'ἅ', 'ἆ' => 'ἆ', 'ἇ' => 'ἇ', 'Ἀ' => 'Ἀ', 'Ἁ' => 'Ἁ', 'Ἂ' => 'Ἂ', 'Ἃ' => 'Ἃ', 'Ἄ' => 'Ἄ', 'Ἅ' => 'Ἅ', 'Ἆ' => 'Ἆ', 'Ἇ' => 'Ἇ', 'ἐ' => 'ἐ', 'ἑ' => 'ἑ', 'ἒ' => 'ἒ', 'ἓ' => 'ἓ', 'ἔ' => 'ἔ', 'ἕ' => 'ἕ', 'Ἐ' => 'Ἐ', 'Ἑ' => 'Ἑ', 'Ἒ' => 'Ἒ', 'Ἓ' => 'Ἓ', 'Ἔ' => 'Ἔ', 'Ἕ' => 'Ἕ', 'ἠ' => 'ἠ', 'ἡ' => 'ἡ', 'ἢ' => 'ἢ', 'ἣ' => 'ἣ', 'ἤ' => 'ἤ', 'ἥ' => 'ἥ', 'ἦ' => 'ἦ', 'ἧ' => 'ἧ', 'Ἠ' => 'Ἠ', 'Ἡ' => 'Ἡ', 'Ἢ' => 'Ἢ', 'Ἣ' => 'Ἣ', 'Ἤ' => 'Ἤ', 'Ἥ' => 'Ἥ', 'Ἦ' => 'Ἦ', 'Ἧ' => 'Ἧ', 'ἰ' => 'ἰ', 'ἱ' => 'ἱ', 'ἲ' => 'ἲ', 'ἳ' => 'ἳ', 'ἴ' => 'ἴ', 'ἵ' => 'ἵ', 'ἶ' => 'ἶ', 'ἷ' => 'ἷ', 'Ἰ' => 'Ἰ', 'Ἱ' => 'Ἱ', 'Ἲ' => 'Ἲ', 'Ἳ' => 'Ἳ', 'Ἴ' => 'Ἴ', 'Ἵ' => 'Ἵ', 'Ἶ' => 'Ἶ', 'Ἷ' => 'Ἷ', 'ὀ' => 'ὀ', 'ὁ' => 'ὁ', 'ὂ' => 'ὂ', 'ὃ' => 'ὃ', 'ὄ' => 'ὄ', 'ὅ' => 'ὅ', 'Ὀ' => 'Ὀ', 'Ὁ' => 'Ὁ', 'Ὂ' => 'Ὂ', 'Ὃ' => 'Ὃ', 'Ὄ' => 'Ὄ', 'Ὅ' => 'Ὅ', 'ὐ' => 'ὐ', 'ὑ' => 'ὑ', 'ὒ' => 'ὒ', 'ὓ' => 'ὓ', 'ὔ' => 'ὔ', 'ὕ' => 'ὕ', 'ὖ' => 'ὖ', 'ὗ' => 'ὗ', 'Ὑ' => 'Ὑ', 'Ὓ' => 'Ὓ', 'Ὕ' => 'Ὕ', 'Ὗ' => 'Ὗ', 'ὠ' => 'ὠ', 'ὡ' => 'ὡ', 'ὢ' => 'ὢ', 'ὣ' => 'ὣ', 'ὤ' => 'ὤ', 'ὥ' => 'ὥ', 'ὦ' => 'ὦ', 'ὧ' => 'ὧ', 'Ὠ' => 'Ὠ', 'Ὡ' => 'Ὡ', 'Ὢ' => 'Ὢ', 'Ὣ' => 'Ὣ', 'Ὤ' => 'Ὤ', 'Ὥ' => 'Ὥ', 'Ὦ' => 'Ὦ', 'Ὧ' => 'Ὧ', 'ὰ' => 'ὰ', 'ά' => 'ά', 'ὲ' => 'ὲ', 'έ' => 'έ', 'ὴ' => 'ὴ', 'ή' => 'ή', 'ὶ' => 'ὶ', 'ί' => 'ί', 'ὸ' => 'ὸ', 'ό' => 'ό', 'ὺ' => 'ὺ', 'ύ' => 'ύ', 'ὼ' => 'ὼ', 'ώ' => 'ώ', 'ᾀ' => 'ᾀ', 'ᾁ' => 'ᾁ', 'ᾂ' => 'ᾂ', 'ᾃ' => 'ᾃ', 'ᾄ' => 'ᾄ', 'ᾅ' => 'ᾅ', 'ᾆ' => 'ᾆ', 'ᾇ' => 'ᾇ', 'ᾈ' => 'ᾈ', 'ᾉ' => 'ᾉ', 'ᾊ' => 'ᾊ', 'ᾋ' => 'ᾋ', 'ᾌ' => 'ᾌ', 'ᾍ' => 'ᾍ', 'ᾎ' => 'ᾎ', 'ᾏ' => 'ᾏ', 'ᾐ' => 'ᾐ', 'ᾑ' => 'ᾑ', 'ᾒ' => 'ᾒ', 'ᾓ' => 'ᾓ', 'ᾔ' => 'ᾔ', 'ᾕ' => 'ᾕ', 'ᾖ' => 'ᾖ', 'ᾗ' => 'ᾗ', 'ᾘ' => 'ᾘ', 'ᾙ' => 'ᾙ', 'ᾚ' => 'ᾚ', 'ᾛ' => 'ᾛ', 'ᾜ' => 'ᾜ', 'ᾝ' => 'ᾝ', 'ᾞ' => 'ᾞ', 'ᾟ' => 'ᾟ', 'ᾠ' => 'ᾠ', 'ᾡ' => 'ᾡ', 'ᾢ' => 'ᾢ', 'ᾣ' => 'ᾣ', 'ᾤ' => 'ᾤ', 'ᾥ' => 'ᾥ', 'ᾦ' => 'ᾦ', 'ᾧ' => 'ᾧ', 'ᾨ' => 'ᾨ', 'ᾩ' => 'ᾩ', 'ᾪ' => 'ᾪ', 'ᾫ' => 'ᾫ', 'ᾬ' => 'ᾬ', 'ᾭ' => 'ᾭ', 'ᾮ' => 'ᾮ', 'ᾯ' => 'ᾯ', 'ᾰ' => 'ᾰ', 'ᾱ' => 'ᾱ', 'ᾲ' => 'ᾲ', 'ᾳ' => 'ᾳ', 'ᾴ' => 'ᾴ', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾷ', 'Ᾰ' => 'Ᾰ', 'Ᾱ' => 'Ᾱ', 'Ὰ' => 'Ὰ', 'Ά' => 'Ά', 'ᾼ' => 'ᾼ', 'ι' => 'ι', '῁' => '῁', 'ῂ' => 'ῂ', 'ῃ' => 'ῃ', 'ῄ' => 'ῄ', 'ῆ' => 'ῆ', 'ῇ' => 'ῇ', 'Ὲ' => 'Ὲ', 'Έ' => 'Έ', 'Ὴ' => 'Ὴ', 'Ή' => 'Ή', 'ῌ' => 'ῌ', '῍' => '῍', '῎' => '῎', '῏' => '῏', 'ῐ' => 'ῐ', 'ῑ' => 'ῑ', 'ῒ' => 'ῒ', 'ΐ' => 'ΐ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'Ῐ' => 'Ῐ', 'Ῑ' => 'Ῑ', 'Ὶ' => 'Ὶ', 'Ί' => 'Ί', '῝' => '῝', '῞' => '῞', '῟' => '῟', 'ῠ' => 'ῠ', 'ῡ' => 'ῡ', 'ῢ' => 'ῢ', 'ΰ' => 'ΰ', 'ῤ' => 'ῤ', 'ῥ' => 'ῥ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'Ῠ' => 'Ῠ', 'Ῡ' => 'Ῡ', 'Ὺ' => 'Ὺ', 'Ύ' => 'Ύ', 'Ῥ' => 'Ῥ', '῭' => '῭', '΅' => '΅', '`' => '`', 'ῲ' => 'ῲ', 'ῳ' => 'ῳ', 'ῴ' => 'ῴ', 'ῶ' => 'ῶ', 'ῷ' => 'ῷ', 'Ὸ' => 'Ὸ', 'Ό' => 'Ό', 'Ὼ' => 'Ὼ', 'Ώ' => 'Ώ', 'ῼ' => 'ῼ', '´' => '´', ' ' => ' ', ' ' => ' ', 'Ω' => 'Ω', 'K' => 'K', 'Å' => 'Å', '↚' => '↚', '↛' => '↛', '↮' => '↮', '⇍' => '⇍', '⇎' => '⇎', '⇏' => '⇏', '∄' => '∄', '∉' => '∉', '∌' => '∌', '∤' => '∤', '∦' => '∦', '≁' => '≁', '≄' => '≄', '≇' => '≇', '≉' => '≉', '≠' => '≠', '≢' => '≢', '≭' => '≭', '≮' => '≮', '≯' => '≯', '≰' => '≰', '≱' => '≱', '≴' => '≴', '≵' => '≵', '≸' => '≸', '≹' => '≹', '⊀' => '⊀', '⊁' => '⊁', '⊄' => '⊄', '⊅' => '⊅', '⊈' => '⊈', '⊉' => '⊉', '⊬' => '⊬', '⊭' => '⊭', '⊮' => '⊮', '⊯' => '⊯', '⋠' => '⋠', '⋡' => '⋡', '⋢' => '⋢', '⋣' => '⋣', '⋪' => '⋪', '⋫' => '⋫', '⋬' => '⋬', '⋭' => '⋭', '〈' => '〈', '〉' => '〉', '⫝̸' => '⫝̸', 'が' => 'が', 'ぎ' => 'ぎ', 'ぐ' => 'ぐ', 'げ' => 'げ', 'ご' => 'ご', 'ざ' => 'ざ', 'じ' => 'じ', 'ず' => 'ず', 'ぜ' => 'ぜ', 'ぞ' => 'ぞ', 'だ' => 'だ', 'ぢ' => 'ぢ', 'づ' => 'づ', 'で' => 'で', 'ど' => 'ど', 'ば' => 'ば', 'ぱ' => 'ぱ', 'び' => 'び', 'ぴ' => 'ぴ', 'ぶ' => 'ぶ', 'ぷ' => 'ぷ', 'べ' => 'べ', 'ぺ' => 'ぺ', 'ぼ' => 'ぼ', 'ぽ' => 'ぽ', 'ゔ' => 'ゔ', 'ゞ' => 'ゞ', 'ガ' => 'ガ', 'ギ' => 'ギ', 'グ' => 'グ', 'ゲ' => 'ゲ', 'ゴ' => 'ゴ', 'ザ' => 'ザ', 'ジ' => 'ジ', 'ズ' => 'ズ', 'ゼ' => 'ゼ', 'ゾ' => 'ゾ', 'ダ' => 'ダ', 'ヂ' => 'ヂ', 'ヅ' => 'ヅ', 'デ' => 'デ', 'ド' => 'ド', 'バ' => 'バ', 'パ' => 'パ', 'ビ' => 'ビ', 'ピ' => 'ピ', 'ブ' => 'ブ', 'プ' => 'プ', 'ベ' => 'ベ', 'ペ' => 'ペ', 'ボ' => 'ボ', 'ポ' => 'ポ', 'ヴ' => 'ヴ', 'ヷ' => 'ヷ', 'ヸ' => 'ヸ', 'ヹ' => 'ヹ', 'ヺ' => 'ヺ', 'ヾ' => 'ヾ', '豈' => '豈', '更' => '更', '車' => '車', '賈' => '賈', '滑' => '滑', '串' => '串', '句' => '句', '龜' => '龜', '龜' => '龜', '契' => '契', '金' => '金', '喇' => '喇', '奈' => '奈', '懶' => '懶', '癩' => '癩', '羅' => '羅', '蘿' => '蘿', '螺' => '螺', '裸' => '裸', '邏' => '邏', '樂' => '樂', '洛' => '洛', '烙' => '烙', '珞' => '珞', '落' => '落', '酪' => '酪', '駱' => '駱', '亂' => '亂', '卵' => '卵', '欄' => '欄', '爛' => '爛', '蘭' => '蘭', '鸞' => '鸞', '嵐' => '嵐', '濫' => '濫', '藍' => '藍', '襤' => '襤', '拉' => '拉', '臘' => '臘', '蠟' => '蠟', '廊' => '廊', '朗' => '朗', '浪' => '浪', '狼' => '狼', '郎' => '郎', '來' => '來', '冷' => '冷', '勞' => '勞', '擄' => '擄', '櫓' => '櫓', '爐' => '爐', '盧' => '盧', '老' => '老', '蘆' => '蘆', '虜' => '虜', '路' => '路', '露' => '露', '魯' => '魯', '鷺' => '鷺', '碌' => '碌', '祿' => '祿', '綠' => '綠', '菉' => '菉', '錄' => '錄', '鹿' => '鹿', '論' => '論', '壟' => '壟', '弄' => '弄', '籠' => '籠', '聾' => '聾', '牢' => '牢', '磊' => '磊', '賂' => '賂', '雷' => '雷', '壘' => '壘', '屢' => '屢', '樓' => '樓', '淚' => '淚', '漏' => '漏', '累' => '累', '縷' => '縷', '陋' => '陋', '勒' => '勒', '肋' => '肋', '凜' => '凜', '凌' => '凌', '稜' => '稜', '綾' => '綾', '菱' => '菱', '陵' => '陵', '讀' => '讀', '拏' => '拏', '樂' => '樂', '諾' => '諾', '丹' => '丹', '寧' => '寧', '怒' => '怒', '率' => '率', '異' => '異', '北' => '北', '磻' => '磻', '便' => '便', '復' => '復', '不' => '不', '泌' => '泌', '數' => '數', '索' => '索', '參' => '參', '塞' => '塞', '省' => '省', '葉' => '葉', '說' => '說', '殺' => '殺', '辰' => '辰', '沈' => '沈', '拾' => '拾', '若' => '若', '掠' => '掠', '略' => '略', '亮' => '亮', '兩' => '兩', '凉' => '凉', '梁' => '梁', '糧' => '糧', '良' => '良', '諒' => '諒', '量' => '量', '勵' => '勵', '呂' => '呂', '女' => '女', '廬' => '廬', '旅' => '旅', '濾' => '濾', '礪' => '礪', '閭' => '閭', '驪' => '驪', '麗' => '麗', '黎' => '黎', '力' => '力', '曆' => '曆', '歷' => '歷', '轢' => '轢', '年' => '年', '憐' => '憐', '戀' => '戀', '撚' => '撚', '漣' => '漣', '煉' => '煉', '璉' => '璉', '秊' => '秊', '練' => '練', '聯' => '聯', '輦' => '輦', '蓮' => '蓮', '連' => '連', '鍊' => '鍊', '列' => '列', '劣' => '劣', '咽' => '咽', '烈' => '烈', '裂' => '裂', '說' => '說', '廉' => '廉', '念' => '念', '捻' => '捻', '殮' => '殮', '簾' => '簾', '獵' => '獵', '令' => '令', '囹' => '囹', '寧' => '寧', '嶺' => '嶺', '怜' => '怜', '玲' => '玲', '瑩' => '瑩', '羚' => '羚', '聆' => '聆', '鈴' => '鈴', '零' => '零', '靈' => '靈', '領' => '領', '例' => '例', '禮' => '禮', '醴' => '醴', '隸' => '隸', '惡' => '惡', '了' => '了', '僚' => '僚', '寮' => '寮', '尿' => '尿', '料' => '料', '樂' => '樂', '燎' => '燎', '療' => '療', '蓼' => '蓼', '遼' => '遼', '龍' => '龍', '暈' => '暈', '阮' => '阮', '劉' => '劉', '杻' => '杻', '柳' => '柳', '流' => '流', '溜' => '溜', '琉' => '琉', '留' => '留', '硫' => '硫', '紐' => '紐', '類' => '類', '六' => '六', '戮' => '戮', '陸' => '陸', '倫' => '倫', '崙' => '崙', '淪' => '淪', '輪' => '輪', '律' => '律', '慄' => '慄', '栗' => '栗', '率' => '率', '隆' => '隆', '利' => '利', '吏' => '吏', '履' => '履', '易' => '易', '李' => '李', '梨' => '梨', '泥' => '泥', '理' => '理', '痢' => '痢', '罹' => '罹', '裏' => '裏', '裡' => '裡', '里' => '里', '離' => '離', '匿' => '匿', '溺' => '溺', '吝' => '吝', '燐' => '燐', '璘' => '璘', '藺' => '藺', '隣' => '隣', '鱗' => '鱗', '麟' => '麟', '林' => '林', '淋' => '淋', '臨' => '臨', '立' => '立', '笠' => '笠', '粒' => '粒', '狀' => '狀', '炙' => '炙', '識' => '識', '什' => '什', '茶' => '茶', '刺' => '刺', '切' => '切', '度' => '度', '拓' => '拓', '糖' => '糖', '宅' => '宅', '洞' => '洞', '暴' => '暴', '輻' => '輻', '行' => '行', '降' => '降', '見' => '見', '廓' => '廓', '兀' => '兀', '嗀' => '嗀', '塚' => '塚', '晴' => '晴', '凞' => '凞', '猪' => '猪', '益' => '益', '礼' => '礼', '神' => '神', '祥' => '祥', '福' => '福', '靖' => '靖', '精' => '精', '羽' => '羽', '蘒' => '蘒', '諸' => '諸', '逸' => '逸', '都' => '都', '飯' => '飯', '飼' => '飼', '館' => '館', '鶴' => '鶴', '郞' => '郞', '隷' => '隷', '侮' => '侮', '僧' => '僧', '免' => '免', '勉' => '勉', '勤' => '勤', '卑' => '卑', '喝' => '喝', '嘆' => '嘆', '器' => '器', '塀' => '塀', '墨' => '墨', '層' => '層', '屮' => '屮', '悔' => '悔', '慨' => '慨', '憎' => '憎', '懲' => '懲', '敏' => '敏', '既' => '既', '暑' => '暑', '梅' => '梅', '海' => '海', '渚' => '渚', '漢' => '漢', '煮' => '煮', '爫' => '爫', '琢' => '琢', '碑' => '碑', '社' => '社', '祉' => '祉', '祈' => '祈', '祐' => '祐', '祖' => '祖', '祝' => '祝', '禍' => '禍', '禎' => '禎', '穀' => '穀', '突' => '突', '節' => '節', '練' => '練', '縉' => '縉', '繁' => '繁', '署' => '署', '者' => '者', '臭' => '臭', '艹' => '艹', '艹' => '艹', '著' => '著', '褐' => '褐', '視' => '視', '謁' => '謁', '謹' => '謹', '賓' => '賓', '贈' => '贈', '辶' => '辶', '逸' => '逸', '難' => '難', '響' => '響', '頻' => '頻', '恵' => '恵', '𤋮' => '𤋮', '舘' => '舘', '並' => '並', '况' => '况', '全' => '全', '侀' => '侀', '充' => '充', '冀' => '冀', '勇' => '勇', '勺' => '勺', '喝' => '喝', '啕' => '啕', '喙' => '喙', '嗢' => '嗢', '塚' => '塚', '墳' => '墳', '奄' => '奄', '奔' => '奔', '婢' => '婢', '嬨' => '嬨', '廒' => '廒', '廙' => '廙', '彩' => '彩', '徭' => '徭', '惘' => '惘', '慎' => '慎', '愈' => '愈', '憎' => '憎', '慠' => '慠', '懲' => '懲', '戴' => '戴', '揄' => '揄', '搜' => '搜', '摒' => '摒', '敖' => '敖', '晴' => '晴', '朗' => '朗', '望' => '望', '杖' => '杖', '歹' => '歹', '殺' => '殺', '流' => '流', '滛' => '滛', '滋' => '滋', '漢' => '漢', '瀞' => '瀞', '煮' => '煮', '瞧' => '瞧', '爵' => '爵', '犯' => '犯', '猪' => '猪', '瑱' => '瑱', '甆' => '甆', '画' => '画', '瘝' => '瘝', '瘟' => '瘟', '益' => '益', '盛' => '盛', '直' => '直', '睊' => '睊', '着' => '着', '磌' => '磌', '窱' => '窱', '節' => '節', '类' => '类', '絛' => '絛', '練' => '練', '缾' => '缾', '者' => '者', '荒' => '荒', '華' => '華', '蝹' => '蝹', '襁' => '襁', '覆' => '覆', '視' => '視', '調' => '調', '諸' => '諸', '請' => '請', '謁' => '謁', '諾' => '諾', '諭' => '諭', '謹' => '謹', '變' => '變', '贈' => '贈', '輸' => '輸', '遲' => '遲', '醙' => '醙', '鉶' => '鉶', '陼' => '陼', '難' => '難', '靖' => '靖', '韛' => '韛', '響' => '響', '頋' => '頋', '頻' => '頻', '鬒' => '鬒', '龜' => '龜', '𢡊' => '𢡊', '𢡄' => '𢡄', '𣏕' => '𣏕', '㮝' => '㮝', '䀘' => '䀘', '䀹' => '䀹', '𥉉' => '𥉉', '𥳐' => '𥳐', '𧻓' => '𧻓', '齃' => '齃', '龎' => '龎', 'יִ' => 'יִ', 'ײַ' => 'ײַ', 'שׁ' => 'שׁ', 'שׂ' => 'שׂ', 'שּׁ' => 'שּׁ', 'שּׂ' => 'שּׂ', 'אַ' => 'אַ', 'אָ' => 'אָ', 'אּ' => 'אּ', 'בּ' => 'בּ', 'גּ' => 'גּ', 'דּ' => 'דּ', 'הּ' => 'הּ', 'וּ' => 'וּ', 'זּ' => 'זּ', 'טּ' => 'טּ', 'יּ' => 'יּ', 'ךּ' => 'ךּ', 'כּ' => 'כּ', 'לּ' => 'לּ', 'מּ' => 'מּ', 'נּ' => 'נּ', 'סּ' => 'סּ', 'ףּ' => 'ףּ', 'פּ' => 'פּ', 'צּ' => 'צּ', 'קּ' => 'קּ', 'רּ' => 'רּ', 'שּ' => 'שּ', 'תּ' => 'תּ', 'וֹ' => 'וֹ', 'בֿ' => 'בֿ', 'כֿ' => 'כֿ', 'פֿ' => 'פֿ', '𑂚' => '𑂚', '𑂜' => '𑂜', '𑂫' => '𑂫', '𑄮' => '𑄮', '𑄯' => '𑄯', '𑍋' => '𑍋', '𑍌' => '𑍌', '𑒻' => '𑒻', '𑒼' => '𑒼', '𑒾' => '𑒾', '𑖺' => '𑖺', '𑖻' => '𑖻', '𑤸' => '𑤸', '𝅗𝅥' => '𝅗𝅥', '𝅘𝅥' => '𝅘𝅥', '𝅘𝅥𝅮' => '𝅘𝅥𝅮', '𝅘𝅥𝅯' => '𝅘𝅥𝅯', '𝅘𝅥𝅰' => '𝅘𝅥𝅰', '𝅘𝅥𝅱' => '𝅘𝅥𝅱', '𝅘𝅥𝅲' => '𝅘𝅥𝅲', '𝆹𝅥' => '𝆹𝅥', '𝆺𝅥' => '𝆺𝅥', '𝆹𝅥𝅮' => '𝆹𝅥𝅮', '𝆺𝅥𝅮' => '𝆺𝅥𝅮', '𝆹𝅥𝅯' => '𝆹𝅥𝅯', '𝆺𝅥𝅯' => '𝆺𝅥𝅯', '丽' => '丽', '丸' => '丸', '乁' => '乁', '𠄢' => '𠄢', '你' => '你', '侮' => '侮', '侻' => '侻', '倂' => '倂', '偺' => '偺', '備' => '備', '僧' => '僧', '像' => '像', '㒞' => '㒞', '𠘺' => '𠘺', '免' => '免', '兔' => '兔', '兤' => '兤', '具' => '具', '𠔜' => '𠔜', '㒹' => '㒹', '內' => '內', '再' => '再', '𠕋' => '𠕋', '冗' => '冗', '冤' => '冤', '仌' => '仌', '冬' => '冬', '况' => '况', '𩇟' => '𩇟', '凵' => '凵', '刃' => '刃', '㓟' => '㓟', '刻' => '刻', '剆' => '剆', '割' => '割', '剷' => '剷', '㔕' => '㔕', '勇' => '勇', '勉' => '勉', '勤' => '勤', '勺' => '勺', '包' => '包', '匆' => '匆', '北' => '北', '卉' => '卉', '卑' => '卑', '博' => '博', '即' => '即', '卽' => '卽', '卿' => '卿', '卿' => '卿', '卿' => '卿', '𠨬' => '𠨬', '灰' => '灰', '及' => '及', '叟' => '叟', '𠭣' => '𠭣', '叫' => '叫', '叱' => '叱', '吆' => '吆', '咞' => '咞', '吸' => '吸', '呈' => '呈', '周' => '周', '咢' => '咢', '哶' => '哶', '唐' => '唐', '啓' => '啓', '啣' => '啣', '善' => '善', '善' => '善', '喙' => '喙', '喫' => '喫', '喳' => '喳', '嗂' => '嗂', '圖' => '圖', '嘆' => '嘆', '圗' => '圗', '噑' => '噑', '噴' => '噴', '切' => '切', '壮' => '壮', '城' => '城', '埴' => '埴', '堍' => '堍', '型' => '型', '堲' => '堲', '報' => '報', '墬' => '墬', '𡓤' => '𡓤', '売' => '売', '壷' => '壷', '夆' => '夆', '多' => '多', '夢' => '夢', '奢' => '奢', '𡚨' => '𡚨', '𡛪' => '𡛪', '姬' => '姬', '娛' => '娛', '娧' => '娧', '姘' => '姘', '婦' => '婦', '㛮' => '㛮', '㛼' => '㛼', '嬈' => '嬈', '嬾' => '嬾', '嬾' => '嬾', '𡧈' => '𡧈', '寃' => '寃', '寘' => '寘', '寧' => '寧', '寳' => '寳', '𡬘' => '𡬘', '寿' => '寿', '将' => '将', '当' => '当', '尢' => '尢', '㞁' => '㞁', '屠' => '屠', '屮' => '屮', '峀' => '峀', '岍' => '岍', '𡷤' => '𡷤', '嵃' => '嵃', '𡷦' => '𡷦', '嵮' => '嵮', '嵫' => '嵫', '嵼' => '嵼', '巡' => '巡', '巢' => '巢', '㠯' => '㠯', '巽' => '巽', '帨' => '帨', '帽' => '帽', '幩' => '幩', '㡢' => '㡢', '𢆃' => '𢆃', '㡼' => '㡼', '庰' => '庰', '庳' => '庳', '庶' => '庶', '廊' => '廊', '𪎒' => '𪎒', '廾' => '廾', '𢌱' => '𢌱', '𢌱' => '𢌱', '舁' => '舁', '弢' => '弢', '弢' => '弢', '㣇' => '㣇', '𣊸' => '𣊸', '𦇚' => '𦇚', '形' => '形', '彫' => '彫', '㣣' => '㣣', '徚' => '徚', '忍' => '忍', '志' => '志', '忹' => '忹', '悁' => '悁', '㤺' => '㤺', '㤜' => '㤜', '悔' => '悔', '𢛔' => '𢛔', '惇' => '惇', '慈' => '慈', '慌' => '慌', '慎' => '慎', '慌' => '慌', '慺' => '慺', '憎' => '憎', '憲' => '憲', '憤' => '憤', '憯' => '憯', '懞' => '懞', '懲' => '懲', '懶' => '懶', '成' => '成', '戛' => '戛', '扝' => '扝', '抱' => '抱', '拔' => '拔', '捐' => '捐', '𢬌' => '𢬌', '挽' => '挽', '拼' => '拼', '捨' => '捨', '掃' => '掃', '揤' => '揤', '𢯱' => '𢯱', '搢' => '搢', '揅' => '揅', '掩' => '掩', '㨮' => '㨮', '摩' => '摩', '摾' => '摾', '撝' => '撝', '摷' => '摷', '㩬' => '㩬', '敏' => '敏', '敬' => '敬', '𣀊' => '𣀊', '旣' => '旣', '書' => '書', '晉' => '晉', '㬙' => '㬙', '暑' => '暑', '㬈' => '㬈', '㫤' => '㫤', '冒' => '冒', '冕' => '冕', '最' => '最', '暜' => '暜', '肭' => '肭', '䏙' => '䏙', '朗' => '朗', '望' => '望', '朡' => '朡', '杞' => '杞', '杓' => '杓', '𣏃' => '𣏃', '㭉' => '㭉', '柺' => '柺', '枅' => '枅', '桒' => '桒', '梅' => '梅', '𣑭' => '𣑭', '梎' => '梎', '栟' => '栟', '椔' => '椔', '㮝' => '㮝', '楂' => '楂', '榣' => '榣', '槪' => '槪', '檨' => '檨', '𣚣' => '𣚣', '櫛' => '櫛', '㰘' => '㰘', '次' => '次', '𣢧' => '𣢧', '歔' => '歔', '㱎' => '㱎', '歲' => '歲', '殟' => '殟', '殺' => '殺', '殻' => '殻', '𣪍' => '𣪍', '𡴋' => '𡴋', '𣫺' => '𣫺', '汎' => '汎', '𣲼' => '𣲼', '沿' => '沿', '泍' => '泍', '汧' => '汧', '洖' => '洖', '派' => '派', '海' => '海', '流' => '流', '浩' => '浩', '浸' => '浸', '涅' => '涅', '𣴞' => '𣴞', '洴' => '洴', '港' => '港', '湮' => '湮', '㴳' => '㴳', '滋' => '滋', '滇' => '滇', '𣻑' => '𣻑', '淹' => '淹', '潮' => '潮', '𣽞' => '𣽞', '𣾎' => '𣾎', '濆' => '濆', '瀹' => '瀹', '瀞' => '瀞', '瀛' => '瀛', '㶖' => '㶖', '灊' => '灊', '災' => '災', '灷' => '灷', '炭' => '炭', '𠔥' => '𠔥', '煅' => '煅', '𤉣' => '𤉣', '熜' => '熜', '𤎫' => '𤎫', '爨' => '爨', '爵' => '爵', '牐' => '牐', '𤘈' => '𤘈', '犀' => '犀', '犕' => '犕', '𤜵' => '𤜵', '𤠔' => '𤠔', '獺' => '獺', '王' => '王', '㺬' => '㺬', '玥' => '玥', '㺸' => '㺸', '㺸' => '㺸', '瑇' => '瑇', '瑜' => '瑜', '瑱' => '瑱', '璅' => '璅', '瓊' => '瓊', '㼛' => '㼛', '甤' => '甤', '𤰶' => '𤰶', '甾' => '甾', '𤲒' => '𤲒', '異' => '異', '𢆟' => '𢆟', '瘐' => '瘐', '𤾡' => '𤾡', '𤾸' => '𤾸', '𥁄' => '𥁄', '㿼' => '㿼', '䀈' => '䀈', '直' => '直', '𥃳' => '𥃳', '𥃲' => '𥃲', '𥄙' => '𥄙', '𥄳' => '𥄳', '眞' => '眞', '真' => '真', '真' => '真', '睊' => '睊', '䀹' => '䀹', '瞋' => '瞋', '䁆' => '䁆', '䂖' => '䂖', '𥐝' => '𥐝', '硎' => '硎', '碌' => '碌', '磌' => '磌', '䃣' => '䃣', '𥘦' => '𥘦', '祖' => '祖', '𥚚' => '𥚚', '𥛅' => '𥛅', '福' => '福', '秫' => '秫', '䄯' => '䄯', '穀' => '穀', '穊' => '穊', '穏' => '穏', '𥥼' => '𥥼', '𥪧' => '𥪧', '𥪧' => '𥪧', '竮' => '竮', '䈂' => '䈂', '𥮫' => '𥮫', '篆' => '篆', '築' => '築', '䈧' => '䈧', '𥲀' => '𥲀', '糒' => '糒', '䊠' => '䊠', '糨' => '糨', '糣' => '糣', '紀' => '紀', '𥾆' => '𥾆', '絣' => '絣', '䌁' => '䌁', '緇' => '緇', '縂' => '縂', '繅' => '繅', '䌴' => '䌴', '𦈨' => '𦈨', '𦉇' => '𦉇', '䍙' => '䍙', '𦋙' => '𦋙', '罺' => '罺', '𦌾' => '𦌾', '羕' => '羕', '翺' => '翺', '者' => '者', '𦓚' => '𦓚', '𦔣' => '𦔣', '聠' => '聠', '𦖨' => '𦖨', '聰' => '聰', '𣍟' => '𣍟', '䏕' => '䏕', '育' => '育', '脃' => '脃', '䐋' => '䐋', '脾' => '脾', '媵' => '媵', '𦞧' => '𦞧', '𦞵' => '𦞵', '𣎓' => '𣎓', '𣎜' => '𣎜', '舁' => '舁', '舄' => '舄', '辞' => '辞', '䑫' => '䑫', '芑' => '芑', '芋' => '芋', '芝' => '芝', '劳' => '劳', '花' => '花', '芳' => '芳', '芽' => '芽', '苦' => '苦', '𦬼' => '𦬼', '若' => '若', '茝' => '茝', '荣' => '荣', '莭' => '莭', '茣' => '茣', '莽' => '莽', '菧' => '菧', '著' => '著', '荓' => '荓', '菊' => '菊', '菌' => '菌', '菜' => '菜', '𦰶' => '𦰶', '𦵫' => '𦵫', '𦳕' => '𦳕', '䔫' => '䔫', '蓱' => '蓱', '蓳' => '蓳', '蔖' => '蔖', '𧏊' => '𧏊', '蕤' => '蕤', '𦼬' => '𦼬', '䕝' => '䕝', '䕡' => '䕡', '𦾱' => '𦾱', '𧃒' => '𧃒', '䕫' => '䕫', '虐' => '虐', '虜' => '虜', '虧' => '虧', '虩' => '虩', '蚩' => '蚩', '蚈' => '蚈', '蜎' => '蜎', '蛢' => '蛢', '蝹' => '蝹', '蜨' => '蜨', '蝫' => '蝫', '螆' => '螆', '䗗' => '䗗', '蟡' => '蟡', '蠁' => '蠁', '䗹' => '䗹', '衠' => '衠', '衣' => '衣', '𧙧' => '𧙧', '裗' => '裗', '裞' => '裞', '䘵' => '䘵', '裺' => '裺', '㒻' => '㒻', '𧢮' => '𧢮', '𧥦' => '𧥦', '䚾' => '䚾', '䛇' => '䛇', '誠' => '誠', '諭' => '諭', '變' => '變', '豕' => '豕', '𧲨' => '𧲨', '貫' => '貫', '賁' => '賁', '贛' => '贛', '起' => '起', '𧼯' => '𧼯', '𠠄' => '𠠄', '跋' => '跋', '趼' => '趼', '跰' => '跰', '𠣞' => '𠣞', '軔' => '軔', '輸' => '輸', '𨗒' => '𨗒', '𨗭' => '𨗭', '邔' => '邔', '郱' => '郱', '鄑' => '鄑', '𨜮' => '𨜮', '鄛' => '鄛', '鈸' => '鈸', '鋗' => '鋗', '鋘' => '鋘', '鉼' => '鉼', '鏹' => '鏹', '鐕' => '鐕', '𨯺' => '𨯺', '開' => '開', '䦕' => '䦕', '閷' => '閷', '𨵷' => '𨵷', '䧦' => '䧦', '雃' => '雃', '嶲' => '嶲', '霣' => '霣', '𩅅' => '𩅅', '𩈚' => '𩈚', '䩮' => '䩮', '䩶' => '䩶', '韠' => '韠', '𩐊' => '𩐊', '䪲' => '䪲', '𩒖' => '𩒖', '頋' => '頋', '頋' => '頋', '頩' => '頩', '𩖶' => '𩖶', '飢' => '飢', '䬳' => '䬳', '餩' => '餩', '馧' => '馧', '駂' => '駂', '駾' => '駾', '䯎' => '䯎', '𩬰' => '𩬰', '鬒' => '鬒', '鱀' => '鱀', '鳽' => '鳽', '䳎' => '䳎', '䳭' => '䳭', '鵧' => '鵧', '𪃎' => '𪃎', '䳸' => '䳸', '𪄅' => '𪄅', '𪈎' => '𪈎', '𪊑' => '𪊑', '麻' => '麻', '䵖' => '䵖', '黹' => '黹', '黾' => '黾', '鼅' => '鼅', '鼏' => '鼏', '鼖' => '鼖', '鼻' => '鼻', '𪘀' => '𪘀', ); 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, ); ' ', '¨' => ' ̈', 'ª' => 'a', '¯' => ' ̄', '²' => '2', '³' => '3', '´' => ' ́', 'µ' => 'μ', '¸' => ' ̧', '¹' => '1', 'º' => 'o', '¼' => '1⁄4', '½' => '1⁄2', '¾' => '3⁄4', 'IJ' => 'IJ', 'ij' => 'ij', 'Ŀ' => 'L·', 'ŀ' => 'l·', 'ʼn' => 'ʼn', 'ſ' => 's', 'DŽ' => 'DŽ', 'Dž' => 'Dž', 'dž' => 'dž', 'LJ' => 'LJ', 'Lj' => 'Lj', 'lj' => 'lj', 'NJ' => 'NJ', 'Nj' => 'Nj', 'nj' => 'nj', 'DZ' => 'DZ', 'Dz' => 'Dz', 'dz' => 'dz', 'ʰ' => 'h', 'ʱ' => 'ɦ', 'ʲ' => 'j', 'ʳ' => 'r', 'ʴ' => 'ɹ', 'ʵ' => 'ɻ', 'ʶ' => 'ʁ', 'ʷ' => 'w', 'ʸ' => 'y', '˘' => ' ̆', '˙' => ' ̇', '˚' => ' ̊', '˛' => ' ̨', '˜' => ' ̃', '˝' => ' ̋', 'ˠ' => 'ɣ', 'ˡ' => 'l', 'ˢ' => 's', 'ˣ' => 'x', 'ˤ' => 'ʕ', 'ͺ' => ' ͅ', '΄' => ' ́', '΅' => ' ̈́', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϒ' => 'Υ', 'ϓ' => 'Ύ', 'ϔ' => 'Ϋ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϲ' => 'ς', 'ϴ' => 'Θ', 'ϵ' => 'ε', 'Ϲ' => 'Σ', 'և' => 'եւ', 'ٵ' => 'اٴ', 'ٶ' => 'وٴ', 'ٷ' => 'ۇٴ', 'ٸ' => 'يٴ', 'ำ' => 'ํา', 'ຳ' => 'ໍາ', 'ໜ' => 'ຫນ', 'ໝ' => 'ຫມ', '༌' => '་', 'ཷ' => 'ྲཱྀ', 'ཹ' => 'ླཱྀ', 'ჼ' => 'ნ', 'ᴬ' => 'A', 'ᴭ' => 'Æ', 'ᴮ' => 'B', 'ᴰ' => 'D', 'ᴱ' => 'E', 'ᴲ' => 'Ǝ', 'ᴳ' => 'G', 'ᴴ' => 'H', 'ᴵ' => 'I', 'ᴶ' => 'J', 'ᴷ' => 'K', 'ᴸ' => 'L', 'ᴹ' => 'M', 'ᴺ' => 'N', 'ᴼ' => 'O', 'ᴽ' => 'Ȣ', 'ᴾ' => 'P', 'ᴿ' => 'R', 'ᵀ' => 'T', 'ᵁ' => 'U', 'ᵂ' => 'W', 'ᵃ' => 'a', 'ᵄ' => 'ɐ', 'ᵅ' => 'ɑ', 'ᵆ' => 'ᴂ', 'ᵇ' => 'b', 'ᵈ' => 'd', 'ᵉ' => 'e', 'ᵊ' => 'ə', 'ᵋ' => 'ɛ', 'ᵌ' => 'ɜ', 'ᵍ' => 'g', 'ᵏ' => 'k', 'ᵐ' => 'm', 'ᵑ' => 'ŋ', 'ᵒ' => 'o', 'ᵓ' => 'ɔ', 'ᵔ' => 'ᴖ', 'ᵕ' => 'ᴗ', 'ᵖ' => 'p', 'ᵗ' => 't', 'ᵘ' => 'u', 'ᵙ' => 'ᴝ', 'ᵚ' => 'ɯ', 'ᵛ' => 'v', 'ᵜ' => 'ᴥ', 'ᵝ' => 'β', 'ᵞ' => 'γ', 'ᵟ' => 'δ', 'ᵠ' => 'φ', 'ᵡ' => 'χ', 'ᵢ' => 'i', 'ᵣ' => 'r', 'ᵤ' => 'u', 'ᵥ' => 'v', 'ᵦ' => 'β', 'ᵧ' => 'γ', 'ᵨ' => 'ρ', 'ᵩ' => 'φ', 'ᵪ' => 'χ', 'ᵸ' => 'н', 'ᶛ' => 'ɒ', 'ᶜ' => 'c', 'ᶝ' => 'ɕ', 'ᶞ' => 'ð', 'ᶟ' => 'ɜ', 'ᶠ' => 'f', 'ᶡ' => 'ɟ', 'ᶢ' => 'ɡ', 'ᶣ' => 'ɥ', 'ᶤ' => 'ɨ', 'ᶥ' => 'ɩ', 'ᶦ' => 'ɪ', 'ᶧ' => 'ᵻ', 'ᶨ' => 'ʝ', 'ᶩ' => 'ɭ', 'ᶪ' => 'ᶅ', 'ᶫ' => 'ʟ', 'ᶬ' => 'ɱ', 'ᶭ' => 'ɰ', 'ᶮ' => 'ɲ', 'ᶯ' => 'ɳ', 'ᶰ' => 'ɴ', 'ᶱ' => 'ɵ', 'ᶲ' => 'ɸ', 'ᶳ' => 'ʂ', 'ᶴ' => 'ʃ', 'ᶵ' => 'ƫ', 'ᶶ' => 'ʉ', 'ᶷ' => 'ʊ', 'ᶸ' => 'ᴜ', 'ᶹ' => 'ʋ', 'ᶺ' => 'ʌ', 'ᶻ' => 'z', 'ᶼ' => 'ʐ', 'ᶽ' => 'ʑ', 'ᶾ' => 'ʒ', 'ᶿ' => 'θ', 'ẚ' => 'aʾ', 'ẛ' => 'ṡ', '᾽' => ' ̓', '᾿' => ' ̓', '῀' => ' ͂', '῁' => ' ̈͂', '῍' => ' ̓̀', '῎' => ' ̓́', '῏' => ' ̓͂', '῝' => ' ̔̀', '῞' => ' ̔́', '῟' => ' ̔͂', '῭' => ' ̈̀', '΅' => ' ̈́', '´' => ' ́', '῾' => ' ̔', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '‑' => '‐', '‗' => ' ̳', '․' => '.', '‥' => '..', '…' => '...', ' ' => ' ', '″' => '′′', '‴' => '′′′', '‶' => '‵‵', '‷' => '‵‵‵', '‼' => '!!', '‾' => ' ̅', '⁇' => '??', '⁈' => '?!', '⁉' => '!?', '⁗' => '′′′′', ' ' => ' ', '⁰' => '0', 'ⁱ' => 'i', '⁴' => '4', '⁵' => '5', '⁶' => '6', '⁷' => '7', '⁸' => '8', '⁹' => '9', '⁺' => '+', '⁻' => '−', '⁼' => '=', '⁽' => '(', '⁾' => ')', 'ⁿ' => 'n', '₀' => '0', '₁' => '1', '₂' => '2', '₃' => '3', '₄' => '4', '₅' => '5', '₆' => '6', '₇' => '7', '₈' => '8', '₉' => '9', '₊' => '+', '₋' => '−', '₌' => '=', '₍' => '(', '₎' => ')', 'ₐ' => 'a', 'ₑ' => 'e', 'ₒ' => 'o', 'ₓ' => 'x', 'ₔ' => 'ə', 'ₕ' => 'h', 'ₖ' => 'k', 'ₗ' => 'l', 'ₘ' => 'm', 'ₙ' => 'n', 'ₚ' => 'p', 'ₛ' => 's', 'ₜ' => 't', '₨' => 'Rs', '℀' => 'a/c', '℁' => 'a/s', 'ℂ' => 'C', '℃' => '°C', '℅' => 'c/o', '℆' => 'c/u', 'ℇ' => 'Ɛ', '℉' => '°F', 'ℊ' => 'g', 'ℋ' => 'H', 'ℌ' => 'H', 'ℍ' => 'H', 'ℎ' => 'h', 'ℏ' => 'ħ', 'ℐ' => 'I', 'ℑ' => 'I', 'ℒ' => 'L', 'ℓ' => 'l', 'ℕ' => 'N', '№' => 'No', 'ℙ' => 'P', 'ℚ' => 'Q', 'ℛ' => 'R', 'ℜ' => 'R', 'ℝ' => 'R', '℠' => 'SM', '℡' => 'TEL', '™' => 'TM', 'ℤ' => 'Z', 'ℨ' => 'Z', 'ℬ' => 'B', 'ℭ' => 'C', 'ℯ' => 'e', 'ℰ' => 'E', 'ℱ' => 'F', 'ℳ' => 'M', 'ℴ' => 'o', 'ℵ' => 'א', 'ℶ' => 'ב', 'ℷ' => 'ג', 'ℸ' => 'ד', 'ℹ' => 'i', '℻' => 'FAX', 'ℼ' => 'π', 'ℽ' => 'γ', 'ℾ' => 'Γ', 'ℿ' => 'Π', '⅀' => '∑', 'ⅅ' => 'D', 'ⅆ' => 'd', 'ⅇ' => 'e', 'ⅈ' => 'i', 'ⅉ' => 'j', '⅐' => '1⁄7', '⅑' => '1⁄9', '⅒' => '1⁄10', '⅓' => '1⁄3', '⅔' => '2⁄3', '⅕' => '1⁄5', '⅖' => '2⁄5', '⅗' => '3⁄5', '⅘' => '4⁄5', '⅙' => '1⁄6', '⅚' => '5⁄6', '⅛' => '1⁄8', '⅜' => '3⁄8', '⅝' => '5⁄8', '⅞' => '7⁄8', '⅟' => '1⁄', 'Ⅰ' => 'I', 'Ⅱ' => 'II', 'Ⅲ' => 'III', 'Ⅳ' => 'IV', 'Ⅴ' => 'V', 'Ⅵ' => 'VI', 'Ⅶ' => 'VII', 'Ⅷ' => 'VIII', 'Ⅸ' => 'IX', 'Ⅹ' => 'X', 'Ⅺ' => 'XI', 'Ⅻ' => 'XII', 'Ⅼ' => 'L', 'Ⅽ' => 'C', 'Ⅾ' => 'D', 'Ⅿ' => 'M', 'ⅰ' => 'i', 'ⅱ' => 'ii', 'ⅲ' => 'iii', 'ⅳ' => 'iv', 'ⅴ' => 'v', 'ⅵ' => 'vi', 'ⅶ' => 'vii', 'ⅷ' => 'viii', 'ⅸ' => 'ix', 'ⅹ' => 'x', 'ⅺ' => 'xi', 'ⅻ' => 'xii', 'ⅼ' => 'l', 'ⅽ' => 'c', 'ⅾ' => 'd', 'ⅿ' => 'm', '↉' => '0⁄3', '∬' => '∫∫', '∭' => '∫∫∫', '∯' => '∮∮', '∰' => '∮∮∮', '①' => '1', '②' => '2', '③' => '3', '④' => '4', '⑤' => '5', '⑥' => '6', '⑦' => '7', '⑧' => '8', '⑨' => '9', '⑩' => '10', '⑪' => '11', '⑫' => '12', '⑬' => '13', '⑭' => '14', '⑮' => '15', '⑯' => '16', '⑰' => '17', '⑱' => '18', '⑲' => '19', '⑳' => '20', '⑴' => '(1)', '⑵' => '(2)', '⑶' => '(3)', '⑷' => '(4)', '⑸' => '(5)', '⑹' => '(6)', '⑺' => '(7)', '⑻' => '(8)', '⑼' => '(9)', '⑽' => '(10)', '⑾' => '(11)', '⑿' => '(12)', '⒀' => '(13)', '⒁' => '(14)', '⒂' => '(15)', '⒃' => '(16)', '⒄' => '(17)', '⒅' => '(18)', '⒆' => '(19)', '⒇' => '(20)', '⒈' => '1.', '⒉' => '2.', '⒊' => '3.', '⒋' => '4.', '⒌' => '5.', '⒍' => '6.', '⒎' => '7.', '⒏' => '8.', '⒐' => '9.', '⒑' => '10.', '⒒' => '11.', '⒓' => '12.', '⒔' => '13.', '⒕' => '14.', '⒖' => '15.', '⒗' => '16.', '⒘' => '17.', '⒙' => '18.', '⒚' => '19.', '⒛' => '20.', '⒜' => '(a)', '⒝' => '(b)', '⒞' => '(c)', '⒟' => '(d)', '⒠' => '(e)', '⒡' => '(f)', '⒢' => '(g)', '⒣' => '(h)', '⒤' => '(i)', '⒥' => '(j)', '⒦' => '(k)', '⒧' => '(l)', '⒨' => '(m)', '⒩' => '(n)', '⒪' => '(o)', '⒫' => '(p)', '⒬' => '(q)', '⒭' => '(r)', '⒮' => '(s)', '⒯' => '(t)', '⒰' => '(u)', '⒱' => '(v)', '⒲' => '(w)', '⒳' => '(x)', '⒴' => '(y)', '⒵' => '(z)', 'Ⓐ' => 'A', 'Ⓑ' => 'B', 'Ⓒ' => 'C', 'Ⓓ' => 'D', 'Ⓔ' => 'E', 'Ⓕ' => 'F', 'Ⓖ' => 'G', 'Ⓗ' => 'H', 'Ⓘ' => 'I', 'Ⓙ' => 'J', 'Ⓚ' => 'K', 'Ⓛ' => 'L', 'Ⓜ' => 'M', 'Ⓝ' => 'N', 'Ⓞ' => 'O', 'Ⓟ' => 'P', 'Ⓠ' => 'Q', 'Ⓡ' => 'R', 'Ⓢ' => 'S', 'Ⓣ' => 'T', 'Ⓤ' => 'U', 'Ⓥ' => 'V', 'Ⓦ' => 'W', 'Ⓧ' => 'X', 'Ⓨ' => 'Y', 'Ⓩ' => 'Z', 'ⓐ' => 'a', 'ⓑ' => 'b', 'ⓒ' => 'c', 'ⓓ' => 'd', 'ⓔ' => 'e', 'ⓕ' => 'f', 'ⓖ' => 'g', 'ⓗ' => 'h', 'ⓘ' => 'i', 'ⓙ' => 'j', 'ⓚ' => 'k', 'ⓛ' => 'l', 'ⓜ' => 'm', 'ⓝ' => 'n', 'ⓞ' => 'o', 'ⓟ' => 'p', 'ⓠ' => 'q', 'ⓡ' => 'r', 'ⓢ' => 's', 'ⓣ' => 't', 'ⓤ' => 'u', 'ⓥ' => 'v', 'ⓦ' => 'w', 'ⓧ' => 'x', 'ⓨ' => 'y', 'ⓩ' => 'z', '⓪' => '0', '⨌' => '∫∫∫∫', '⩴' => '::=', '⩵' => '==', '⩶' => '===', 'ⱼ' => 'j', 'ⱽ' => 'V', 'ⵯ' => 'ⵡ', '⺟' => '母', '⻳' => '龟', '⼀' => '一', '⼁' => '丨', '⼂' => '丶', '⼃' => '丿', '⼄' => '乙', '⼅' => '亅', '⼆' => '二', '⼇' => '亠', '⼈' => '人', '⼉' => '儿', '⼊' => '入', '⼋' => '八', '⼌' => '冂', '⼍' => '冖', '⼎' => '冫', '⼏' => '几', '⼐' => '凵', '⼑' => '刀', '⼒' => '力', '⼓' => '勹', '⼔' => '匕', '⼕' => '匚', '⼖' => '匸', '⼗' => '十', '⼘' => '卜', '⼙' => '卩', '⼚' => '厂', '⼛' => '厶', '⼜' => '又', '⼝' => '口', '⼞' => '囗', '⼟' => '土', '⼠' => '士', '⼡' => '夂', '⼢' => '夊', '⼣' => '夕', '⼤' => '大', '⼥' => '女', '⼦' => '子', '⼧' => '宀', '⼨' => '寸', '⼩' => '小', '⼪' => '尢', '⼫' => '尸', '⼬' => '屮', '⼭' => '山', '⼮' => '巛', '⼯' => '工', '⼰' => '己', '⼱' => '巾', '⼲' => '干', '⼳' => '幺', '⼴' => '广', '⼵' => '廴', '⼶' => '廾', '⼷' => '弋', '⼸' => '弓', '⼹' => '彐', '⼺' => '彡', '⼻' => '彳', '⼼' => '心', '⼽' => '戈', '⼾' => '戶', '⼿' => '手', '⽀' => '支', '⽁' => '攴', '⽂' => '文', '⽃' => '斗', '⽄' => '斤', '⽅' => '方', '⽆' => '无', '⽇' => '日', '⽈' => '曰', '⽉' => '月', '⽊' => '木', '⽋' => '欠', '⽌' => '止', '⽍' => '歹', '⽎' => '殳', '⽏' => '毋', '⽐' => '比', '⽑' => '毛', '⽒' => '氏', '⽓' => '气', '⽔' => '水', '⽕' => '火', '⽖' => '爪', '⽗' => '父', '⽘' => '爻', '⽙' => '爿', '⽚' => '片', '⽛' => '牙', '⽜' => '牛', '⽝' => '犬', '⽞' => '玄', '⽟' => '玉', '⽠' => '瓜', '⽡' => '瓦', '⽢' => '甘', '⽣' => '生', '⽤' => '用', '⽥' => '田', '⽦' => '疋', '⽧' => '疒', '⽨' => '癶', '⽩' => '白', '⽪' => '皮', '⽫' => '皿', '⽬' => '目', '⽭' => '矛', '⽮' => '矢', '⽯' => '石', '⽰' => '示', '⽱' => '禸', '⽲' => '禾', '⽳' => '穴', '⽴' => '立', '⽵' => '竹', '⽶' => '米', '⽷' => '糸', '⽸' => '缶', '⽹' => '网', '⽺' => '羊', '⽻' => '羽', '⽼' => '老', '⽽' => '而', '⽾' => '耒', '⽿' => '耳', '⾀' => '聿', '⾁' => '肉', '⾂' => '臣', '⾃' => '自', '⾄' => '至', '⾅' => '臼', '⾆' => '舌', '⾇' => '舛', '⾈' => '舟', '⾉' => '艮', '⾊' => '色', '⾋' => '艸', '⾌' => '虍', '⾍' => '虫', '⾎' => '血', '⾏' => '行', '⾐' => '衣', '⾑' => '襾', '⾒' => '見', '⾓' => '角', '⾔' => '言', '⾕' => '谷', '⾖' => '豆', '⾗' => '豕', '⾘' => '豸', '⾙' => '貝', '⾚' => '赤', '⾛' => '走', '⾜' => '足', '⾝' => '身', '⾞' => '車', '⾟' => '辛', '⾠' => '辰', '⾡' => '辵', '⾢' => '邑', '⾣' => '酉', '⾤' => '釆', '⾥' => '里', '⾦' => '金', '⾧' => '長', '⾨' => '門', '⾩' => '阜', '⾪' => '隶', '⾫' => '隹', '⾬' => '雨', '⾭' => '靑', '⾮' => '非', '⾯' => '面', '⾰' => '革', '⾱' => '韋', '⾲' => '韭', '⾳' => '音', '⾴' => '頁', '⾵' => '風', '⾶' => '飛', '⾷' => '食', '⾸' => '首', '⾹' => '香', '⾺' => '馬', '⾻' => '骨', '⾼' => '高', '⾽' => '髟', '⾾' => '鬥', '⾿' => '鬯', '⿀' => '鬲', '⿁' => '鬼', '⿂' => '魚', '⿃' => '鳥', '⿄' => '鹵', '⿅' => '鹿', '⿆' => '麥', '⿇' => '麻', '⿈' => '黃', '⿉' => '黍', '⿊' => '黑', '⿋' => '黹', '⿌' => '黽', '⿍' => '鼎', '⿎' => '鼓', '⿏' => '鼠', '⿐' => '鼻', '⿑' => '齊', '⿒' => '齒', '⿓' => '龍', '⿔' => '龜', '⿕' => '龠', ' ' => ' ', '〶' => '〒', '〸' => '十', '〹' => '卄', '〺' => '卅', '゛' => ' ゙', '゜' => ' ゚', 'ゟ' => 'より', 'ヿ' => 'コト', 'ㄱ' => 'ᄀ', 'ㄲ' => 'ᄁ', 'ㄳ' => 'ᆪ', 'ㄴ' => 'ᄂ', 'ㄵ' => 'ᆬ', 'ㄶ' => 'ᆭ', 'ㄷ' => 'ᄃ', 'ㄸ' => 'ᄄ', 'ㄹ' => 'ᄅ', 'ㄺ' => 'ᆰ', 'ㄻ' => 'ᆱ', 'ㄼ' => 'ᆲ', 'ㄽ' => 'ᆳ', 'ㄾ' => 'ᆴ', 'ㄿ' => 'ᆵ', 'ㅀ' => 'ᄚ', 'ㅁ' => 'ᄆ', 'ㅂ' => 'ᄇ', 'ㅃ' => 'ᄈ', 'ㅄ' => 'ᄡ', 'ㅅ' => 'ᄉ', 'ㅆ' => 'ᄊ', 'ㅇ' => 'ᄋ', 'ㅈ' => 'ᄌ', 'ㅉ' => 'ᄍ', 'ㅊ' => 'ᄎ', 'ㅋ' => 'ᄏ', 'ㅌ' => 'ᄐ', 'ㅍ' => 'ᄑ', 'ㅎ' => 'ᄒ', 'ㅏ' => 'ᅡ', 'ㅐ' => 'ᅢ', 'ㅑ' => 'ᅣ', 'ㅒ' => 'ᅤ', 'ㅓ' => 'ᅥ', 'ㅔ' => 'ᅦ', 'ㅕ' => 'ᅧ', 'ㅖ' => 'ᅨ', 'ㅗ' => 'ᅩ', 'ㅘ' => 'ᅪ', 'ㅙ' => 'ᅫ', 'ㅚ' => 'ᅬ', 'ㅛ' => 'ᅭ', 'ㅜ' => 'ᅮ', 'ㅝ' => 'ᅯ', 'ㅞ' => 'ᅰ', 'ㅟ' => 'ᅱ', 'ㅠ' => 'ᅲ', 'ㅡ' => 'ᅳ', 'ㅢ' => 'ᅴ', 'ㅣ' => 'ᅵ', 'ㅤ' => 'ᅠ', 'ㅥ' => 'ᄔ', 'ㅦ' => 'ᄕ', 'ㅧ' => 'ᇇ', 'ㅨ' => 'ᇈ', 'ㅩ' => 'ᇌ', 'ㅪ' => 'ᇎ', 'ㅫ' => 'ᇓ', 'ㅬ' => 'ᇗ', 'ㅭ' => 'ᇙ', 'ㅮ' => 'ᄜ', 'ㅯ' => 'ᇝ', 'ㅰ' => 'ᇟ', 'ㅱ' => 'ᄝ', 'ㅲ' => 'ᄞ', 'ㅳ' => 'ᄠ', 'ㅴ' => 'ᄢ', 'ㅵ' => 'ᄣ', 'ㅶ' => 'ᄧ', 'ㅷ' => 'ᄩ', 'ㅸ' => 'ᄫ', 'ㅹ' => 'ᄬ', 'ㅺ' => 'ᄭ', 'ㅻ' => 'ᄮ', 'ㅼ' => 'ᄯ', 'ㅽ' => 'ᄲ', 'ㅾ' => 'ᄶ', 'ㅿ' => 'ᅀ', 'ㆀ' => 'ᅇ', 'ㆁ' => 'ᅌ', 'ㆂ' => 'ᇱ', 'ㆃ' => 'ᇲ', 'ㆄ' => 'ᅗ', 'ㆅ' => 'ᅘ', 'ㆆ' => 'ᅙ', 'ㆇ' => 'ᆄ', 'ㆈ' => 'ᆅ', 'ㆉ' => 'ᆈ', 'ㆊ' => 'ᆑ', 'ㆋ' => 'ᆒ', 'ㆌ' => 'ᆔ', 'ㆍ' => 'ᆞ', 'ㆎ' => 'ᆡ', '㆒' => '一', '㆓' => '二', '㆔' => '三', '㆕' => '四', '㆖' => '上', '㆗' => '中', '㆘' => '下', '㆙' => '甲', '㆚' => '乙', '㆛' => '丙', '㆜' => '丁', '㆝' => '天', '㆞' => '地', '㆟' => '人', '㈀' => '(ᄀ)', '㈁' => '(ᄂ)', '㈂' => '(ᄃ)', '㈃' => '(ᄅ)', '㈄' => '(ᄆ)', '㈅' => '(ᄇ)', '㈆' => '(ᄉ)', '㈇' => '(ᄋ)', '㈈' => '(ᄌ)', '㈉' => '(ᄎ)', '㈊' => '(ᄏ)', '㈋' => '(ᄐ)', '㈌' => '(ᄑ)', '㈍' => '(ᄒ)', '㈎' => '(가)', '㈏' => '(나)', '㈐' => '(다)', '㈑' => '(라)', '㈒' => '(마)', '㈓' => '(바)', '㈔' => '(사)', '㈕' => '(아)', '㈖' => '(자)', '㈗' => '(차)', '㈘' => '(카)', '㈙' => '(타)', '㈚' => '(파)', '㈛' => '(하)', '㈜' => '(주)', '㈝' => '(오전)', '㈞' => '(오후)', '㈠' => '(一)', '㈡' => '(二)', '㈢' => '(三)', '㈣' => '(四)', '㈤' => '(五)', '㈥' => '(六)', '㈦' => '(七)', '㈧' => '(八)', '㈨' => '(九)', '㈩' => '(十)', '㈪' => '(月)', '㈫' => '(火)', '㈬' => '(水)', '㈭' => '(木)', '㈮' => '(金)', '㈯' => '(土)', '㈰' => '(日)', '㈱' => '(株)', '㈲' => '(有)', '㈳' => '(社)', '㈴' => '(名)', '㈵' => '(特)', '㈶' => '(財)', '㈷' => '(祝)', '㈸' => '(労)', '㈹' => '(代)', '㈺' => '(呼)', '㈻' => '(学)', '㈼' => '(監)', '㈽' => '(企)', '㈾' => '(資)', '㈿' => '(協)', '㉀' => '(祭)', '㉁' => '(休)', '㉂' => '(自)', '㉃' => '(至)', '㉄' => '問', '㉅' => '幼', '㉆' => '文', '㉇' => '箏', '㉐' => 'PTE', '㉑' => '21', '㉒' => '22', '㉓' => '23', '㉔' => '24', '㉕' => '25', '㉖' => '26', '㉗' => '27', '㉘' => '28', '㉙' => '29', '㉚' => '30', '㉛' => '31', '㉜' => '32', '㉝' => '33', '㉞' => '34', '㉟' => '35', '㉠' => 'ᄀ', '㉡' => 'ᄂ', '㉢' => 'ᄃ', '㉣' => 'ᄅ', '㉤' => 'ᄆ', '㉥' => 'ᄇ', '㉦' => 'ᄉ', '㉧' => 'ᄋ', '㉨' => 'ᄌ', '㉩' => 'ᄎ', '㉪' => 'ᄏ', '㉫' => 'ᄐ', '㉬' => 'ᄑ', '㉭' => 'ᄒ', '㉮' => '가', '㉯' => '나', '㉰' => '다', '㉱' => '라', '㉲' => '마', '㉳' => '바', '㉴' => '사', '㉵' => '아', '㉶' => '자', '㉷' => '차', '㉸' => '카', '㉹' => '타', '㉺' => '파', '㉻' => '하', '㉼' => '참고', '㉽' => '주의', '㉾' => '우', '㊀' => '一', '㊁' => '二', '㊂' => '三', '㊃' => '四', '㊄' => '五', '㊅' => '六', '㊆' => '七', '㊇' => '八', '㊈' => '九', '㊉' => '十', '㊊' => '月', '㊋' => '火', '㊌' => '水', '㊍' => '木', '㊎' => '金', '㊏' => '土', '㊐' => '日', '㊑' => '株', '㊒' => '有', '㊓' => '社', '㊔' => '名', '㊕' => '特', '㊖' => '財', '㊗' => '祝', '㊘' => '労', '㊙' => '秘', '㊚' => '男', '㊛' => '女', '㊜' => '適', '㊝' => '優', '㊞' => '印', '㊟' => '注', '㊠' => '項', '㊡' => '休', '㊢' => '写', '㊣' => '正', '㊤' => '上', '㊥' => '中', '㊦' => '下', '㊧' => '左', '㊨' => '右', '㊩' => '医', '㊪' => '宗', '㊫' => '学', '㊬' => '監', '㊭' => '企', '㊮' => '資', '㊯' => '協', '㊰' => '夜', '㊱' => '36', '㊲' => '37', '㊳' => '38', '㊴' => '39', '㊵' => '40', '㊶' => '41', '㊷' => '42', '㊸' => '43', '㊹' => '44', '㊺' => '45', '㊻' => '46', '㊼' => '47', '㊽' => '48', '㊾' => '49', '㊿' => '50', '㋀' => '1月', '㋁' => '2月', '㋂' => '3月', '㋃' => '4月', '㋄' => '5月', '㋅' => '6月', '㋆' => '7月', '㋇' => '8月', '㋈' => '9月', '㋉' => '10月', '㋊' => '11月', '㋋' => '12月', '㋌' => 'Hg', '㋍' => 'erg', '㋎' => 'eV', '㋏' => 'LTD', '㋐' => 'ア', '㋑' => 'イ', '㋒' => 'ウ', '㋓' => 'エ', '㋔' => 'オ', '㋕' => 'カ', '㋖' => 'キ', '㋗' => 'ク', '㋘' => 'ケ', '㋙' => 'コ', '㋚' => 'サ', '㋛' => 'シ', '㋜' => 'ス', '㋝' => 'セ', '㋞' => 'ソ', '㋟' => 'タ', '㋠' => 'チ', '㋡' => 'ツ', '㋢' => 'テ', '㋣' => 'ト', '㋤' => 'ナ', '㋥' => 'ニ', '㋦' => 'ヌ', '㋧' => 'ネ', '㋨' => 'ノ', '㋩' => 'ハ', '㋪' => 'ヒ', '㋫' => 'フ', '㋬' => 'ヘ', '㋭' => 'ホ', '㋮' => 'マ', '㋯' => 'ミ', '㋰' => 'ム', '㋱' => 'メ', '㋲' => 'モ', '㋳' => 'ヤ', '㋴' => 'ユ', '㋵' => 'ヨ', '㋶' => 'ラ', '㋷' => 'リ', '㋸' => 'ル', '㋹' => 'レ', '㋺' => 'ロ', '㋻' => 'ワ', '㋼' => 'ヰ', '㋽' => 'ヱ', '㋾' => 'ヲ', '㋿' => '令和', '㌀' => 'アパート', '㌁' => 'アルファ', '㌂' => 'アンペア', '㌃' => 'アール', '㌄' => 'イニング', '㌅' => 'インチ', '㌆' => 'ウォン', '㌇' => 'エスクード', '㌈' => 'エーカー', '㌉' => 'オンス', '㌊' => 'オーム', '㌋' => 'カイリ', '㌌' => 'カラット', '㌍' => 'カロリー', '㌎' => 'ガロン', '㌏' => 'ガンマ', '㌐' => 'ギガ', '㌑' => 'ギニー', '㌒' => 'キュリー', '㌓' => 'ギルダー', '㌔' => 'キロ', '㌕' => 'キログラム', '㌖' => 'キロメートル', '㌗' => 'キロワット', '㌘' => 'グラム', '㌙' => 'グラムトン', '㌚' => 'クルゼイロ', '㌛' => 'クローネ', '㌜' => 'ケース', '㌝' => 'コルナ', '㌞' => 'コーポ', '㌟' => 'サイクル', '㌠' => 'サンチーム', '㌡' => 'シリング', '㌢' => 'センチ', '㌣' => 'セント', '㌤' => 'ダース', '㌥' => 'デシ', '㌦' => 'ドル', '㌧' => 'トン', '㌨' => 'ナノ', '㌩' => 'ノット', '㌪' => 'ハイツ', '㌫' => 'パーセント', '㌬' => 'パーツ', '㌭' => 'バーレル', '㌮' => 'ピアストル', '㌯' => 'ピクル', '㌰' => 'ピコ', '㌱' => 'ビル', '㌲' => 'ファラッド', '㌳' => 'フィート', '㌴' => 'ブッシェル', '㌵' => 'フラン', '㌶' => 'ヘクタール', '㌷' => 'ペソ', '㌸' => 'ペニヒ', '㌹' => 'ヘルツ', '㌺' => 'ペンス', '㌻' => 'ページ', '㌼' => 'ベータ', '㌽' => 'ポイント', '㌾' => 'ボルト', '㌿' => 'ホン', '㍀' => 'ポンド', '㍁' => 'ホール', '㍂' => 'ホーン', '㍃' => 'マイクロ', '㍄' => 'マイル', '㍅' => 'マッハ', '㍆' => 'マルク', '㍇' => 'マンション', '㍈' => 'ミクロン', '㍉' => 'ミリ', '㍊' => 'ミリバール', '㍋' => 'メガ', '㍌' => 'メガトン', '㍍' => 'メートル', '㍎' => 'ヤード', '㍏' => 'ヤール', '㍐' => 'ユアン', '㍑' => 'リットル', '㍒' => 'リラ', '㍓' => 'ルピー', '㍔' => 'ルーブル', '㍕' => 'レム', '㍖' => 'レントゲン', '㍗' => 'ワット', '㍘' => '0点', '㍙' => '1点', '㍚' => '2点', '㍛' => '3点', '㍜' => '4点', '㍝' => '5点', '㍞' => '6点', '㍟' => '7点', '㍠' => '8点', '㍡' => '9点', '㍢' => '10点', '㍣' => '11点', '㍤' => '12点', '㍥' => '13点', '㍦' => '14点', '㍧' => '15点', '㍨' => '16点', '㍩' => '17点', '㍪' => '18点', '㍫' => '19点', '㍬' => '20点', '㍭' => '21点', '㍮' => '22点', '㍯' => '23点', '㍰' => '24点', '㍱' => 'hPa', '㍲' => 'da', '㍳' => 'AU', '㍴' => 'bar', '㍵' => 'oV', '㍶' => 'pc', '㍷' => 'dm', '㍸' => 'dm2', '㍹' => 'dm3', '㍺' => 'IU', '㍻' => '平成', '㍼' => '昭和', '㍽' => '大正', '㍾' => '明治', '㍿' => '株式会社', '㎀' => 'pA', '㎁' => 'nA', '㎂' => 'μA', '㎃' => 'mA', '㎄' => 'kA', '㎅' => 'KB', '㎆' => 'MB', '㎇' => 'GB', '㎈' => 'cal', '㎉' => 'kcal', '㎊' => 'pF', '㎋' => 'nF', '㎌' => 'μF', '㎍' => 'μg', '㎎' => 'mg', '㎏' => 'kg', '㎐' => 'Hz', '㎑' => 'kHz', '㎒' => 'MHz', '㎓' => 'GHz', '㎔' => 'THz', '㎕' => 'μl', '㎖' => 'ml', '㎗' => 'dl', '㎘' => 'kl', '㎙' => 'fm', '㎚' => 'nm', '㎛' => 'μm', '㎜' => 'mm', '㎝' => 'cm', '㎞' => 'km', '㎟' => 'mm2', '㎠' => 'cm2', '㎡' => 'm2', '㎢' => 'km2', '㎣' => 'mm3', '㎤' => 'cm3', '㎥' => 'm3', '㎦' => 'km3', '㎧' => 'm∕s', '㎨' => 'm∕s2', '㎩' => 'Pa', '㎪' => 'kPa', '㎫' => 'MPa', '㎬' => 'GPa', '㎭' => 'rad', '㎮' => 'rad∕s', '㎯' => 'rad∕s2', '㎰' => 'ps', '㎱' => 'ns', '㎲' => 'μs', '㎳' => 'ms', '㎴' => 'pV', '㎵' => 'nV', '㎶' => 'μV', '㎷' => 'mV', '㎸' => 'kV', '㎹' => 'MV', '㎺' => 'pW', '㎻' => 'nW', '㎼' => 'μW', '㎽' => 'mW', '㎾' => 'kW', '㎿' => 'MW', '㏀' => 'kΩ', '㏁' => 'MΩ', '㏂' => 'a.m.', '㏃' => 'Bq', '㏄' => 'cc', '㏅' => 'cd', '㏆' => 'C∕kg', '㏇' => 'Co.', '㏈' => 'dB', '㏉' => 'Gy', '㏊' => 'ha', '㏋' => 'HP', '㏌' => 'in', '㏍' => 'KK', '㏎' => 'KM', '㏏' => 'kt', '㏐' => 'lm', '㏑' => 'ln', '㏒' => 'log', '㏓' => 'lx', '㏔' => 'mb', '㏕' => 'mil', '㏖' => 'mol', '㏗' => 'PH', '㏘' => 'p.m.', '㏙' => 'PPM', '㏚' => 'PR', '㏛' => 'sr', '㏜' => 'Sv', '㏝' => 'Wb', '㏞' => 'V∕m', '㏟' => 'A∕m', '㏠' => '1日', '㏡' => '2日', '㏢' => '3日', '㏣' => '4日', '㏤' => '5日', '㏥' => '6日', '㏦' => '7日', '㏧' => '8日', '㏨' => '9日', '㏩' => '10日', '㏪' => '11日', '㏫' => '12日', '㏬' => '13日', '㏭' => '14日', '㏮' => '15日', '㏯' => '16日', '㏰' => '17日', '㏱' => '18日', '㏲' => '19日', '㏳' => '20日', '㏴' => '21日', '㏵' => '22日', '㏶' => '23日', '㏷' => '24日', '㏸' => '25日', '㏹' => '26日', '㏺' => '27日', '㏻' => '28日', '㏼' => '29日', '㏽' => '30日', '㏾' => '31日', '㏿' => 'gal', 'ꚜ' => 'ъ', 'ꚝ' => 'ь', 'ꝰ' => 'ꝯ', 'ꟸ' => 'Ħ', 'ꟹ' => 'œ', 'ꭜ' => 'ꜧ', 'ꭝ' => 'ꬷ', 'ꭞ' => 'ɫ', 'ꭟ' => 'ꭒ', 'ꭩ' => 'ʍ', 'ff' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'st', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ', 'ﬠ' => 'ע', 'ﬡ' => 'א', 'ﬢ' => 'ד', 'ﬣ' => 'ה', 'ﬤ' => 'כ', 'ﬥ' => 'ל', 'ﬦ' => 'ם', 'ﬧ' => 'ר', 'ﬨ' => 'ת', '﬩' => '+', 'ﭏ' => 'אל', 'ﭐ' => 'ٱ', 'ﭑ' => 'ٱ', 'ﭒ' => 'ٻ', 'ﭓ' => 'ٻ', 'ﭔ' => 'ٻ', 'ﭕ' => 'ٻ', 'ﭖ' => 'پ', 'ﭗ' => 'پ', 'ﭘ' => 'پ', 'ﭙ' => 'پ', 'ﭚ' => 'ڀ', 'ﭛ' => 'ڀ', 'ﭜ' => 'ڀ', 'ﭝ' => 'ڀ', 'ﭞ' => 'ٺ', 'ﭟ' => 'ٺ', 'ﭠ' => 'ٺ', 'ﭡ' => 'ٺ', 'ﭢ' => 'ٿ', 'ﭣ' => 'ٿ', 'ﭤ' => 'ٿ', 'ﭥ' => 'ٿ', 'ﭦ' => 'ٹ', 'ﭧ' => 'ٹ', 'ﭨ' => 'ٹ', 'ﭩ' => 'ٹ', 'ﭪ' => 'ڤ', 'ﭫ' => 'ڤ', 'ﭬ' => 'ڤ', 'ﭭ' => 'ڤ', 'ﭮ' => 'ڦ', 'ﭯ' => 'ڦ', 'ﭰ' => 'ڦ', 'ﭱ' => 'ڦ', 'ﭲ' => 'ڄ', 'ﭳ' => 'ڄ', 'ﭴ' => 'ڄ', 'ﭵ' => 'ڄ', 'ﭶ' => 'ڃ', 'ﭷ' => 'ڃ', 'ﭸ' => 'ڃ', 'ﭹ' => 'ڃ', 'ﭺ' => 'چ', 'ﭻ' => 'چ', 'ﭼ' => 'چ', 'ﭽ' => 'چ', 'ﭾ' => 'ڇ', 'ﭿ' => 'ڇ', 'ﮀ' => 'ڇ', 'ﮁ' => 'ڇ', 'ﮂ' => 'ڍ', 'ﮃ' => 'ڍ', 'ﮄ' => 'ڌ', 'ﮅ' => 'ڌ', 'ﮆ' => 'ڎ', 'ﮇ' => 'ڎ', 'ﮈ' => 'ڈ', 'ﮉ' => 'ڈ', 'ﮊ' => 'ژ', 'ﮋ' => 'ژ', 'ﮌ' => 'ڑ', 'ﮍ' => 'ڑ', 'ﮎ' => 'ک', 'ﮏ' => 'ک', 'ﮐ' => 'ک', 'ﮑ' => 'ک', 'ﮒ' => 'گ', 'ﮓ' => 'گ', 'ﮔ' => 'گ', 'ﮕ' => 'گ', 'ﮖ' => 'ڳ', 'ﮗ' => 'ڳ', 'ﮘ' => 'ڳ', 'ﮙ' => 'ڳ', 'ﮚ' => 'ڱ', 'ﮛ' => 'ڱ', 'ﮜ' => 'ڱ', 'ﮝ' => 'ڱ', 'ﮞ' => 'ں', 'ﮟ' => 'ں', 'ﮠ' => 'ڻ', 'ﮡ' => 'ڻ', 'ﮢ' => 'ڻ', 'ﮣ' => 'ڻ', 'ﮤ' => 'ۀ', 'ﮥ' => 'ۀ', 'ﮦ' => 'ہ', 'ﮧ' => 'ہ', 'ﮨ' => 'ہ', 'ﮩ' => 'ہ', 'ﮪ' => 'ھ', 'ﮫ' => 'ھ', 'ﮬ' => 'ھ', 'ﮭ' => 'ھ', 'ﮮ' => 'ے', 'ﮯ' => 'ے', 'ﮰ' => 'ۓ', 'ﮱ' => 'ۓ', 'ﯓ' => 'ڭ', 'ﯔ' => 'ڭ', 'ﯕ' => 'ڭ', 'ﯖ' => 'ڭ', 'ﯗ' => 'ۇ', 'ﯘ' => 'ۇ', 'ﯙ' => 'ۆ', 'ﯚ' => 'ۆ', 'ﯛ' => 'ۈ', 'ﯜ' => 'ۈ', 'ﯝ' => 'ۇٴ', 'ﯞ' => 'ۋ', 'ﯟ' => 'ۋ', 'ﯠ' => 'ۅ', 'ﯡ' => 'ۅ', 'ﯢ' => 'ۉ', 'ﯣ' => 'ۉ', 'ﯤ' => 'ې', 'ﯥ' => 'ې', 'ﯦ' => 'ې', 'ﯧ' => 'ې', 'ﯨ' => 'ى', 'ﯩ' => 'ى', 'ﯪ' => 'ئا', 'ﯫ' => 'ئا', 'ﯬ' => 'ئە', 'ﯭ' => 'ئە', 'ﯮ' => 'ئو', 'ﯯ' => 'ئو', 'ﯰ' => 'ئۇ', 'ﯱ' => 'ئۇ', 'ﯲ' => 'ئۆ', 'ﯳ' => 'ئۆ', 'ﯴ' => 'ئۈ', 'ﯵ' => 'ئۈ', 'ﯶ' => 'ئې', 'ﯷ' => 'ئې', 'ﯸ' => 'ئې', 'ﯹ' => 'ئى', 'ﯺ' => 'ئى', 'ﯻ' => 'ئى', 'ﯼ' => 'ی', 'ﯽ' => 'ی', 'ﯾ' => 'ی', 'ﯿ' => 'ی', 'ﰀ' => 'ئج', 'ﰁ' => 'ئح', 'ﰂ' => 'ئم', 'ﰃ' => 'ئى', 'ﰄ' => 'ئي', 'ﰅ' => 'بج', 'ﰆ' => 'بح', 'ﰇ' => 'بخ', 'ﰈ' => 'بم', 'ﰉ' => 'بى', 'ﰊ' => 'بي', 'ﰋ' => 'تج', 'ﰌ' => 'تح', 'ﰍ' => 'تخ', 'ﰎ' => 'تم', 'ﰏ' => 'تى', 'ﰐ' => 'تي', 'ﰑ' => 'ثج', 'ﰒ' => 'ثم', 'ﰓ' => 'ثى', 'ﰔ' => 'ثي', 'ﰕ' => 'جح', 'ﰖ' => 'جم', 'ﰗ' => 'حج', 'ﰘ' => 'حم', 'ﰙ' => 'خج', 'ﰚ' => 'خح', 'ﰛ' => 'خم', 'ﰜ' => 'سج', 'ﰝ' => 'سح', 'ﰞ' => 'سخ', 'ﰟ' => 'سم', 'ﰠ' => 'صح', 'ﰡ' => 'صم', 'ﰢ' => 'ضج', 'ﰣ' => 'ضح', 'ﰤ' => 'ضخ', 'ﰥ' => 'ضم', 'ﰦ' => 'طح', 'ﰧ' => 'طم', 'ﰨ' => 'ظم', 'ﰩ' => 'عج', 'ﰪ' => 'عم', 'ﰫ' => 'غج', 'ﰬ' => 'غم', 'ﰭ' => 'فج', 'ﰮ' => 'فح', 'ﰯ' => 'فخ', 'ﰰ' => 'فم', 'ﰱ' => 'فى', 'ﰲ' => 'في', 'ﰳ' => 'قح', 'ﰴ' => 'قم', 'ﰵ' => 'قى', 'ﰶ' => 'قي', 'ﰷ' => 'كا', 'ﰸ' => 'كج', 'ﰹ' => 'كح', 'ﰺ' => 'كخ', 'ﰻ' => 'كل', 'ﰼ' => 'كم', 'ﰽ' => 'كى', 'ﰾ' => 'كي', 'ﰿ' => 'لج', 'ﱀ' => 'لح', 'ﱁ' => 'لخ', 'ﱂ' => 'لم', 'ﱃ' => 'لى', 'ﱄ' => 'لي', 'ﱅ' => 'مج', 'ﱆ' => 'مح', 'ﱇ' => 'مخ', 'ﱈ' => 'مم', 'ﱉ' => 'مى', 'ﱊ' => 'مي', 'ﱋ' => 'نج', 'ﱌ' => 'نح', 'ﱍ' => 'نخ', 'ﱎ' => 'نم', 'ﱏ' => 'نى', 'ﱐ' => 'ني', 'ﱑ' => 'هج', 'ﱒ' => 'هم', 'ﱓ' => 'هى', 'ﱔ' => 'هي', 'ﱕ' => 'يج', 'ﱖ' => 'يح', 'ﱗ' => 'يخ', 'ﱘ' => 'يم', 'ﱙ' => 'يى', 'ﱚ' => 'يي', 'ﱛ' => 'ذٰ', 'ﱜ' => 'رٰ', 'ﱝ' => 'ىٰ', 'ﱞ' => ' ٌّ', 'ﱟ' => ' ٍّ', 'ﱠ' => ' َّ', 'ﱡ' => ' ُّ', 'ﱢ' => ' ِّ', 'ﱣ' => ' ّٰ', 'ﱤ' => 'ئر', 'ﱥ' => 'ئز', 'ﱦ' => 'ئم', 'ﱧ' => 'ئن', 'ﱨ' => 'ئى', 'ﱩ' => 'ئي', 'ﱪ' => 'بر', 'ﱫ' => 'بز', 'ﱬ' => 'بم', 'ﱭ' => 'بن', 'ﱮ' => 'بى', 'ﱯ' => 'بي', 'ﱰ' => 'تر', 'ﱱ' => 'تز', 'ﱲ' => 'تم', 'ﱳ' => 'تن', 'ﱴ' => 'تى', 'ﱵ' => 'تي', 'ﱶ' => 'ثر', 'ﱷ' => 'ثز', 'ﱸ' => 'ثم', 'ﱹ' => 'ثن', 'ﱺ' => 'ثى', 'ﱻ' => 'ثي', 'ﱼ' => 'فى', 'ﱽ' => 'في', 'ﱾ' => 'قى', 'ﱿ' => 'قي', 'ﲀ' => 'كا', 'ﲁ' => 'كل', 'ﲂ' => 'كم', 'ﲃ' => 'كى', 'ﲄ' => 'كي', 'ﲅ' => 'لم', 'ﲆ' => 'لى', 'ﲇ' => 'لي', 'ﲈ' => 'ما', 'ﲉ' => 'مم', 'ﲊ' => 'نر', 'ﲋ' => 'نز', 'ﲌ' => 'نم', 'ﲍ' => 'نن', 'ﲎ' => 'نى', 'ﲏ' => 'ني', 'ﲐ' => 'ىٰ', 'ﲑ' => 'ير', 'ﲒ' => 'يز', 'ﲓ' => 'يم', 'ﲔ' => 'ين', 'ﲕ' => 'يى', 'ﲖ' => 'يي', 'ﲗ' => 'ئج', 'ﲘ' => 'ئح', 'ﲙ' => 'ئخ', 'ﲚ' => 'ئم', 'ﲛ' => 'ئه', 'ﲜ' => 'بج', 'ﲝ' => 'بح', 'ﲞ' => 'بخ', 'ﲟ' => 'بم', 'ﲠ' => 'به', 'ﲡ' => 'تج', 'ﲢ' => 'تح', 'ﲣ' => 'تخ', 'ﲤ' => 'تم', 'ﲥ' => 'ته', 'ﲦ' => 'ثم', 'ﲧ' => 'جح', 'ﲨ' => 'جم', 'ﲩ' => 'حج', 'ﲪ' => 'حم', 'ﲫ' => 'خج', 'ﲬ' => 'خم', 'ﲭ' => 'سج', 'ﲮ' => 'سح', 'ﲯ' => 'سخ', 'ﲰ' => 'سم', 'ﲱ' => 'صح', 'ﲲ' => 'صخ', 'ﲳ' => 'صم', 'ﲴ' => 'ضج', 'ﲵ' => 'ضح', 'ﲶ' => 'ضخ', 'ﲷ' => 'ضم', 'ﲸ' => 'طح', 'ﲹ' => 'ظم', 'ﲺ' => 'عج', 'ﲻ' => 'عم', 'ﲼ' => 'غج', 'ﲽ' => 'غم', 'ﲾ' => 'فج', 'ﲿ' => 'فح', 'ﳀ' => 'فخ', 'ﳁ' => 'فم', 'ﳂ' => 'قح', 'ﳃ' => 'قم', 'ﳄ' => 'كج', 'ﳅ' => 'كح', 'ﳆ' => 'كخ', 'ﳇ' => 'كل', 'ﳈ' => 'كم', 'ﳉ' => 'لج', 'ﳊ' => 'لح', 'ﳋ' => 'لخ', 'ﳌ' => 'لم', 'ﳍ' => 'له', 'ﳎ' => 'مج', 'ﳏ' => 'مح', 'ﳐ' => 'مخ', 'ﳑ' => 'مم', 'ﳒ' => 'نج', 'ﳓ' => 'نح', 'ﳔ' => 'نخ', 'ﳕ' => 'نم', 'ﳖ' => 'نه', 'ﳗ' => 'هج', 'ﳘ' => 'هم', 'ﳙ' => 'هٰ', 'ﳚ' => 'يج', 'ﳛ' => 'يح', 'ﳜ' => 'يخ', 'ﳝ' => 'يم', 'ﳞ' => 'يه', 'ﳟ' => 'ئم', 'ﳠ' => 'ئه', 'ﳡ' => 'بم', 'ﳢ' => 'به', 'ﳣ' => 'تم', 'ﳤ' => 'ته', 'ﳥ' => 'ثم', 'ﳦ' => 'ثه', 'ﳧ' => 'سم', 'ﳨ' => 'سه', 'ﳩ' => 'شم', 'ﳪ' => 'شه', 'ﳫ' => 'كل', 'ﳬ' => 'كم', 'ﳭ' => 'لم', 'ﳮ' => 'نم', 'ﳯ' => 'نه', 'ﳰ' => 'يم', 'ﳱ' => 'يه', 'ﳲ' => 'ـَّ', 'ﳳ' => 'ـُّ', 'ﳴ' => 'ـِّ', 'ﳵ' => 'طى', 'ﳶ' => 'طي', 'ﳷ' => 'عى', 'ﳸ' => 'عي', 'ﳹ' => 'غى', 'ﳺ' => 'غي', 'ﳻ' => 'سى', 'ﳼ' => 'سي', 'ﳽ' => 'شى', 'ﳾ' => 'شي', 'ﳿ' => 'حى', 'ﴀ' => 'حي', 'ﴁ' => 'جى', 'ﴂ' => 'جي', 'ﴃ' => 'خى', 'ﴄ' => 'خي', 'ﴅ' => 'صى', 'ﴆ' => 'صي', 'ﴇ' => 'ضى', 'ﴈ' => 'ضي', 'ﴉ' => 'شج', 'ﴊ' => 'شح', 'ﴋ' => 'شخ', 'ﴌ' => 'شم', 'ﴍ' => 'شر', 'ﴎ' => 'سر', 'ﴏ' => 'صر', 'ﴐ' => 'ضر', 'ﴑ' => 'طى', 'ﴒ' => 'طي', 'ﴓ' => 'عى', 'ﴔ' => 'عي', 'ﴕ' => 'غى', 'ﴖ' => 'غي', 'ﴗ' => 'سى', 'ﴘ' => 'سي', 'ﴙ' => 'شى', 'ﴚ' => 'شي', 'ﴛ' => 'حى', 'ﴜ' => 'حي', 'ﴝ' => 'جى', 'ﴞ' => 'جي', 'ﴟ' => 'خى', 'ﴠ' => 'خي', 'ﴡ' => 'صى', 'ﴢ' => 'صي', 'ﴣ' => 'ضى', 'ﴤ' => 'ضي', 'ﴥ' => 'شج', 'ﴦ' => 'شح', 'ﴧ' => 'شخ', 'ﴨ' => 'شم', 'ﴩ' => 'شر', 'ﴪ' => 'سر', 'ﴫ' => 'صر', 'ﴬ' => 'ضر', 'ﴭ' => 'شج', 'ﴮ' => 'شح', 'ﴯ' => 'شخ', 'ﴰ' => 'شم', 'ﴱ' => 'سه', 'ﴲ' => 'شه', 'ﴳ' => 'طم', 'ﴴ' => 'سج', 'ﴵ' => 'سح', 'ﴶ' => 'سخ', 'ﴷ' => 'شج', 'ﴸ' => 'شح', 'ﴹ' => 'شخ', 'ﴺ' => 'طم', 'ﴻ' => 'ظم', 'ﴼ' => 'اً', 'ﴽ' => 'اً', 'ﵐ' => 'تجم', 'ﵑ' => 'تحج', 'ﵒ' => 'تحج', 'ﵓ' => 'تحم', 'ﵔ' => 'تخم', 'ﵕ' => 'تمج', 'ﵖ' => 'تمح', 'ﵗ' => 'تمخ', 'ﵘ' => 'جمح', 'ﵙ' => 'جمح', 'ﵚ' => 'حمي', 'ﵛ' => 'حمى', 'ﵜ' => 'سحج', 'ﵝ' => 'سجح', 'ﵞ' => 'سجى', 'ﵟ' => 'سمح', 'ﵠ' => 'سمح', 'ﵡ' => 'سمج', 'ﵢ' => 'سمم', 'ﵣ' => 'سمم', 'ﵤ' => 'صحح', 'ﵥ' => 'صحح', 'ﵦ' => 'صمم', 'ﵧ' => 'شحم', 'ﵨ' => 'شحم', 'ﵩ' => 'شجي', 'ﵪ' => 'شمخ', 'ﵫ' => 'شمخ', 'ﵬ' => 'شمم', 'ﵭ' => 'شمم', 'ﵮ' => 'ضحى', 'ﵯ' => 'ضخم', 'ﵰ' => 'ضخم', 'ﵱ' => 'طمح', 'ﵲ' => 'طمح', 'ﵳ' => 'طمم', 'ﵴ' => 'طمي', 'ﵵ' => 'عجم', 'ﵶ' => 'عمم', 'ﵷ' => 'عمم', 'ﵸ' => 'عمى', 'ﵹ' => 'غمم', 'ﵺ' => 'غمي', 'ﵻ' => 'غمى', 'ﵼ' => 'فخم', 'ﵽ' => 'فخم', 'ﵾ' => 'قمح', 'ﵿ' => 'قمم', 'ﶀ' => 'لحم', 'ﶁ' => 'لحي', 'ﶂ' => 'لحى', 'ﶃ' => 'لجج', 'ﶄ' => 'لجج', 'ﶅ' => 'لخم', 'ﶆ' => 'لخم', 'ﶇ' => 'لمح', 'ﶈ' => 'لمح', 'ﶉ' => 'محج', 'ﶊ' => 'محم', 'ﶋ' => 'محي', 'ﶌ' => 'مجح', 'ﶍ' => 'مجم', 'ﶎ' => 'مخج', 'ﶏ' => 'مخم', 'ﶒ' => 'مجخ', 'ﶓ' => 'همج', 'ﶔ' => 'همم', 'ﶕ' => 'نحم', 'ﶖ' => 'نحى', 'ﶗ' => 'نجم', 'ﶘ' => 'نجم', 'ﶙ' => 'نجى', 'ﶚ' => 'نمي', 'ﶛ' => 'نمى', 'ﶜ' => 'يمم', 'ﶝ' => 'يمم', 'ﶞ' => 'بخي', 'ﶟ' => 'تجي', 'ﶠ' => 'تجى', 'ﶡ' => 'تخي', 'ﶢ' => 'تخى', 'ﶣ' => 'تمي', 'ﶤ' => 'تمى', 'ﶥ' => 'جمي', 'ﶦ' => 'جحى', 'ﶧ' => 'جمى', 'ﶨ' => 'سخى', 'ﶩ' => 'صحي', 'ﶪ' => 'شحي', 'ﶫ' => 'ضحي', 'ﶬ' => 'لجي', 'ﶭ' => 'لمي', 'ﶮ' => 'يحي', 'ﶯ' => 'يجي', 'ﶰ' => 'يمي', 'ﶱ' => 'ممي', 'ﶲ' => 'قمي', 'ﶳ' => 'نحي', 'ﶴ' => 'قمح', 'ﶵ' => 'لحم', 'ﶶ' => 'عمي', 'ﶷ' => 'كمي', 'ﶸ' => 'نجح', 'ﶹ' => 'مخي', 'ﶺ' => 'لجم', 'ﶻ' => 'كمم', 'ﶼ' => 'لجم', 'ﶽ' => 'نجح', 'ﶾ' => 'جحي', 'ﶿ' => 'حجي', 'ﷀ' => 'مجي', 'ﷁ' => 'فمي', 'ﷂ' => 'بحي', 'ﷃ' => 'كمم', 'ﷄ' => 'عجم', 'ﷅ' => 'صمم', 'ﷆ' => 'سخي', 'ﷇ' => 'نجي', 'ﷰ' => 'صلے', 'ﷱ' => 'قلے', 'ﷲ' => 'الله', 'ﷳ' => 'اكبر', 'ﷴ' => 'محمد', 'ﷵ' => 'صلعم', 'ﷶ' => 'رسول', 'ﷷ' => 'عليه', 'ﷸ' => 'وسلم', 'ﷹ' => 'صلى', 'ﷺ' => 'صلى الله عليه وسلم', 'ﷻ' => 'جل جلاله', '﷼' => 'ریال', '︐' => ',', '︑' => '、', '︒' => '。', '︓' => ':', '︔' => ';', '︕' => '!', '︖' => '?', '︗' => '〖', '︘' => '〗', '︙' => '...', '︰' => '..', '︱' => '—', '︲' => '–', '︳' => '_', '︴' => '_', '︵' => '(', '︶' => ')', '︷' => '{', '︸' => '}', '︹' => '〔', '︺' => '〕', '︻' => '【', '︼' => '】', '︽' => '《', '︾' => '》', '︿' => '〈', '﹀' => '〉', '﹁' => '「', '﹂' => '」', '﹃' => '『', '﹄' => '』', '﹇' => '[', '﹈' => ']', '﹉' => ' ̅', '﹊' => ' ̅', '﹋' => ' ̅', '﹌' => ' ̅', '﹍' => '_', '﹎' => '_', '﹏' => '_', '﹐' => ',', '﹑' => '、', '﹒' => '.', '﹔' => ';', '﹕' => ':', '﹖' => '?', '﹗' => '!', '﹘' => '—', '﹙' => '(', '﹚' => ')', '﹛' => '{', '﹜' => '}', '﹝' => '〔', '﹞' => '〕', '﹟' => '#', '﹠' => '&', '﹡' => '*', '﹢' => '+', '﹣' => '-', '﹤' => '<', '﹥' => '>', '﹦' => '=', '﹨' => '\\', '﹩' => '$', '﹪' => '%', '﹫' => '@', 'ﹰ' => ' ً', 'ﹱ' => 'ـً', 'ﹲ' => ' ٌ', 'ﹴ' => ' ٍ', 'ﹶ' => ' َ', 'ﹷ' => 'ـَ', 'ﹸ' => ' ُ', 'ﹹ' => 'ـُ', 'ﹺ' => ' ِ', 'ﹻ' => 'ـِ', 'ﹼ' => ' ّ', 'ﹽ' => 'ـّ', 'ﹾ' => ' ْ', 'ﹿ' => 'ـْ', 'ﺀ' => 'ء', 'ﺁ' => 'آ', 'ﺂ' => 'آ', 'ﺃ' => 'أ', 'ﺄ' => 'أ', 'ﺅ' => 'ؤ', 'ﺆ' => 'ؤ', 'ﺇ' => 'إ', 'ﺈ' => 'إ', 'ﺉ' => 'ئ', 'ﺊ' => 'ئ', 'ﺋ' => 'ئ', 'ﺌ' => 'ئ', 'ﺍ' => 'ا', 'ﺎ' => 'ا', 'ﺏ' => 'ب', 'ﺐ' => 'ب', 'ﺑ' => 'ب', 'ﺒ' => 'ب', 'ﺓ' => 'ة', 'ﺔ' => 'ة', 'ﺕ' => 'ت', 'ﺖ' => 'ت', 'ﺗ' => 'ت', 'ﺘ' => 'ت', 'ﺙ' => 'ث', 'ﺚ' => 'ث', 'ﺛ' => 'ث', 'ﺜ' => 'ث', 'ﺝ' => 'ج', 'ﺞ' => 'ج', 'ﺟ' => 'ج', 'ﺠ' => 'ج', 'ﺡ' => 'ح', 'ﺢ' => 'ح', 'ﺣ' => 'ح', 'ﺤ' => 'ح', 'ﺥ' => 'خ', 'ﺦ' => 'خ', 'ﺧ' => 'خ', 'ﺨ' => 'خ', 'ﺩ' => 'د', 'ﺪ' => 'د', 'ﺫ' => 'ذ', 'ﺬ' => 'ذ', 'ﺭ' => 'ر', 'ﺮ' => 'ر', 'ﺯ' => 'ز', 'ﺰ' => 'ز', 'ﺱ' => 'س', 'ﺲ' => 'س', 'ﺳ' => 'س', 'ﺴ' => 'س', 'ﺵ' => 'ش', 'ﺶ' => 'ش', 'ﺷ' => 'ش', 'ﺸ' => 'ش', 'ﺹ' => 'ص', 'ﺺ' => 'ص', 'ﺻ' => 'ص', 'ﺼ' => 'ص', 'ﺽ' => 'ض', 'ﺾ' => 'ض', 'ﺿ' => 'ض', 'ﻀ' => 'ض', 'ﻁ' => 'ط', 'ﻂ' => 'ط', 'ﻃ' => 'ط', 'ﻄ' => 'ط', 'ﻅ' => 'ظ', 'ﻆ' => 'ظ', 'ﻇ' => 'ظ', 'ﻈ' => 'ظ', 'ﻉ' => 'ع', 'ﻊ' => 'ع', 'ﻋ' => 'ع', 'ﻌ' => 'ع', 'ﻍ' => 'غ', 'ﻎ' => 'غ', 'ﻏ' => 'غ', 'ﻐ' => 'غ', 'ﻑ' => 'ف', 'ﻒ' => 'ف', 'ﻓ' => 'ف', 'ﻔ' => 'ف', 'ﻕ' => 'ق', 'ﻖ' => 'ق', 'ﻗ' => 'ق', 'ﻘ' => 'ق', 'ﻙ' => 'ك', 'ﻚ' => 'ك', 'ﻛ' => 'ك', 'ﻜ' => 'ك', 'ﻝ' => 'ل', 'ﻞ' => 'ل', 'ﻟ' => 'ل', 'ﻠ' => 'ل', 'ﻡ' => 'م', 'ﻢ' => 'م', 'ﻣ' => 'م', 'ﻤ' => 'م', 'ﻥ' => 'ن', 'ﻦ' => 'ن', 'ﻧ' => 'ن', 'ﻨ' => 'ن', 'ﻩ' => 'ه', 'ﻪ' => 'ه', 'ﻫ' => 'ه', 'ﻬ' => 'ه', 'ﻭ' => 'و', 'ﻮ' => 'و', 'ﻯ' => 'ى', 'ﻰ' => 'ى', 'ﻱ' => 'ي', 'ﻲ' => 'ي', 'ﻳ' => 'ي', 'ﻴ' => 'ي', 'ﻵ' => 'لآ', 'ﻶ' => 'لآ', 'ﻷ' => 'لأ', 'ﻸ' => 'لأ', 'ﻹ' => 'لإ', 'ﻺ' => 'لإ', 'ﻻ' => 'لا', 'ﻼ' => 'لا', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', ''' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', '0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9', ':' => ':', ';' => ';', '<' => '<', '=' => '=', '>' => '>', '?' => '?', '@' => '@', 'A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D', 'E' => 'E', 'F' => 'F', 'G' => 'G', 'H' => 'H', 'I' => 'I', 'J' => 'J', 'K' => 'K', 'L' => 'L', 'M' => 'M', 'N' => 'N', 'O' => 'O', 'P' => 'P', 'Q' => 'Q', 'R' => 'R', 'S' => 'S', 'T' => 'T', 'U' => 'U', 'V' => 'V', 'W' => 'W', 'X' => 'X', 'Y' => 'Y', 'Z' => 'Z', '[' => '[', '\' => '\\', ']' => ']', '^' => '^', '_' => '_', '`' => '`', 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd', 'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'h', 'i' => 'i', 'j' => 'j', 'k' => 'k', 'l' => 'l', 'm' => 'm', 'n' => 'n', 'o' => 'o', 'p' => 'p', 'q' => 'q', 'r' => 'r', 's' => 's', 't' => 't', 'u' => 'u', 'v' => 'v', 'w' => 'w', 'x' => 'x', 'y' => 'y', 'z' => 'z', '{' => '{', '|' => '|', '}' => '}', '~' => '~', '⦅' => '⦅', '⦆' => '⦆', '。' => '。', '「' => '「', '」' => '」', '、' => '、', '・' => '・', 'ヲ' => 'ヲ', 'ァ' => 'ァ', 'ィ' => 'ィ', 'ゥ' => 'ゥ', 'ェ' => 'ェ', 'ォ' => 'ォ', 'ャ' => 'ャ', 'ュ' => 'ュ', 'ョ' => 'ョ', 'ッ' => 'ッ', 'ー' => 'ー', 'ア' => 'ア', 'イ' => 'イ', 'ウ' => 'ウ', 'エ' => 'エ', 'オ' => 'オ', 'カ' => 'カ', 'キ' => 'キ', 'ク' => 'ク', 'ケ' => 'ケ', 'コ' => 'コ', 'サ' => 'サ', 'シ' => 'シ', 'ス' => 'ス', 'セ' => 'セ', 'ソ' => 'ソ', 'タ' => 'タ', 'チ' => 'チ', 'ツ' => 'ツ', 'テ' => 'テ', 'ト' => 'ト', 'ナ' => 'ナ', 'ニ' => 'ニ', 'ヌ' => 'ヌ', 'ネ' => 'ネ', 'ノ' => 'ノ', 'ハ' => 'ハ', 'ヒ' => 'ヒ', 'フ' => 'フ', 'ヘ' => 'ヘ', 'ホ' => 'ホ', 'マ' => 'マ', 'ミ' => 'ミ', 'ム' => 'ム', 'メ' => 'メ', 'モ' => 'モ', 'ヤ' => 'ヤ', 'ユ' => 'ユ', 'ヨ' => 'ヨ', 'ラ' => 'ラ', 'リ' => 'リ', 'ル' => 'ル', 'レ' => 'レ', 'ロ' => 'ロ', 'ワ' => 'ワ', 'ン' => 'ン', '゙' => '゙', '゚' => '゚', 'ᅠ' => 'ᅠ', 'ᄀ' => 'ᄀ', 'ᄁ' => 'ᄁ', 'ᆪ' => 'ᆪ', 'ᄂ' => 'ᄂ', 'ᆬ' => 'ᆬ', 'ᆭ' => 'ᆭ', 'ᄃ' => 'ᄃ', 'ᄄ' => 'ᄄ', 'ᄅ' => 'ᄅ', 'ᆰ' => 'ᆰ', 'ᆱ' => 'ᆱ', 'ᆲ' => 'ᆲ', 'ᆳ' => 'ᆳ', 'ᆴ' => 'ᆴ', 'ᆵ' => 'ᆵ', 'ᄚ' => 'ᄚ', 'ᄆ' => 'ᄆ', 'ᄇ' => 'ᄇ', 'ᄈ' => 'ᄈ', 'ᄡ' => 'ᄡ', 'ᄉ' => 'ᄉ', 'ᄊ' => 'ᄊ', 'ᄋ' => 'ᄋ', 'ᄌ' => 'ᄌ', 'ᄍ' => 'ᄍ', 'ᄎ' => 'ᄎ', 'ᄏ' => 'ᄏ', 'ᄐ' => 'ᄐ', 'ᄑ' => 'ᄑ', 'ᄒ' => 'ᄒ', 'ᅡ' => 'ᅡ', 'ᅢ' => 'ᅢ', 'ᅣ' => 'ᅣ', 'ᅤ' => 'ᅤ', 'ᅥ' => 'ᅥ', 'ᅦ' => 'ᅦ', 'ᅧ' => 'ᅧ', 'ᅨ' => 'ᅨ', 'ᅩ' => 'ᅩ', 'ᅪ' => 'ᅪ', 'ᅫ' => 'ᅫ', 'ᅬ' => 'ᅬ', 'ᅭ' => 'ᅭ', 'ᅮ' => 'ᅮ', 'ᅯ' => 'ᅯ', 'ᅰ' => 'ᅰ', 'ᅱ' => 'ᅱ', 'ᅲ' => 'ᅲ', 'ᅳ' => 'ᅳ', 'ᅴ' => 'ᅴ', 'ᅵ' => 'ᅵ', '¢' => '¢', '£' => '£', '¬' => '¬', ' ̄' => ' ̄', '¦' => '¦', '¥' => '¥', '₩' => '₩', '│' => '│', '←' => '←', '↑' => '↑', '→' => '→', '↓' => '↓', '■' => '■', '○' => '○', '𝐀' => 'A', '𝐁' => 'B', '𝐂' => 'C', '𝐃' => 'D', '𝐄' => 'E', '𝐅' => 'F', '𝐆' => 'G', '𝐇' => 'H', '𝐈' => 'I', '𝐉' => 'J', '𝐊' => 'K', '𝐋' => 'L', '𝐌' => 'M', '𝐍' => 'N', '𝐎' => 'O', '𝐏' => 'P', '𝐐' => 'Q', '𝐑' => 'R', '𝐒' => 'S', '𝐓' => 'T', '𝐔' => 'U', '𝐕' => 'V', '𝐖' => 'W', '𝐗' => 'X', '𝐘' => 'Y', '𝐙' => 'Z', '𝐚' => 'a', '𝐛' => 'b', '𝐜' => 'c', '𝐝' => 'd', '𝐞' => 'e', '𝐟' => 'f', '𝐠' => 'g', '𝐡' => 'h', '𝐢' => 'i', '𝐣' => 'j', '𝐤' => 'k', '𝐥' => 'l', '𝐦' => 'm', '𝐧' => 'n', '𝐨' => 'o', '𝐩' => 'p', '𝐪' => 'q', '𝐫' => 'r', '𝐬' => 's', '𝐭' => 't', '𝐮' => 'u', '𝐯' => 'v', '𝐰' => 'w', '𝐱' => 'x', '𝐲' => 'y', '𝐳' => 'z', '𝐴' => 'A', '𝐵' => 'B', '𝐶' => 'C', '𝐷' => 'D', '𝐸' => 'E', '𝐹' => 'F', '𝐺' => 'G', '𝐻' => 'H', '𝐼' => 'I', '𝐽' => 'J', '𝐾' => 'K', '𝐿' => 'L', '𝑀' => 'M', '𝑁' => 'N', '𝑂' => 'O', '𝑃' => 'P', '𝑄' => 'Q', '𝑅' => 'R', '𝑆' => 'S', '𝑇' => 'T', '𝑈' => 'U', '𝑉' => 'V', '𝑊' => 'W', '𝑋' => 'X', '𝑌' => 'Y', '𝑍' => 'Z', '𝑎' => 'a', '𝑏' => 'b', '𝑐' => 'c', '𝑑' => 'd', '𝑒' => 'e', '𝑓' => 'f', '𝑔' => 'g', '𝑖' => 'i', '𝑗' => 'j', '𝑘' => 'k', '𝑙' => 'l', '𝑚' => 'm', '𝑛' => 'n', '𝑜' => 'o', '𝑝' => 'p', '𝑞' => 'q', '𝑟' => 'r', '𝑠' => 's', '𝑡' => 't', '𝑢' => 'u', '𝑣' => 'v', '𝑤' => 'w', '𝑥' => 'x', '𝑦' => 'y', '𝑧' => 'z', '𝑨' => 'A', '𝑩' => 'B', '𝑪' => 'C', '𝑫' => 'D', '𝑬' => 'E', '𝑭' => 'F', '𝑮' => 'G', '𝑯' => 'H', '𝑰' => 'I', '𝑱' => 'J', '𝑲' => 'K', '𝑳' => 'L', '𝑴' => 'M', '𝑵' => 'N', '𝑶' => 'O', '𝑷' => 'P', '𝑸' => 'Q', '𝑹' => 'R', '𝑺' => 'S', '𝑻' => 'T', '𝑼' => 'U', '𝑽' => 'V', '𝑾' => 'W', '𝑿' => 'X', '𝒀' => 'Y', '𝒁' => 'Z', '𝒂' => 'a', '𝒃' => 'b', '𝒄' => 'c', '𝒅' => 'd', '𝒆' => 'e', '𝒇' => 'f', '𝒈' => 'g', '𝒉' => 'h', '𝒊' => 'i', '𝒋' => 'j', '𝒌' => 'k', '𝒍' => 'l', '𝒎' => 'm', '𝒏' => 'n', '𝒐' => 'o', '𝒑' => 'p', '𝒒' => 'q', '𝒓' => 'r', '𝒔' => 's', '𝒕' => 't', '𝒖' => 'u', '𝒗' => 'v', '𝒘' => 'w', '𝒙' => 'x', '𝒚' => 'y', '𝒛' => 'z', '𝒜' => 'A', '𝒞' => 'C', '𝒟' => 'D', '𝒢' => 'G', '𝒥' => 'J', '𝒦' => 'K', '𝒩' => 'N', '𝒪' => 'O', '𝒫' => 'P', '𝒬' => 'Q', '𝒮' => 'S', '𝒯' => 'T', '𝒰' => 'U', '𝒱' => 'V', '𝒲' => 'W', '𝒳' => 'X', '𝒴' => 'Y', '𝒵' => 'Z', '𝒶' => 'a', '𝒷' => 'b', '𝒸' => 'c', '𝒹' => 'd', '𝒻' => 'f', '𝒽' => 'h', '𝒾' => 'i', '𝒿' => 'j', '𝓀' => 'k', '𝓁' => 'l', '𝓂' => 'm', '𝓃' => 'n', '𝓅' => 'p', '𝓆' => 'q', '𝓇' => 'r', '𝓈' => 's', '𝓉' => 't', '𝓊' => 'u', '𝓋' => 'v', '𝓌' => 'w', '𝓍' => 'x', '𝓎' => 'y', '𝓏' => 'z', '𝓐' => 'A', '𝓑' => 'B', '𝓒' => 'C', '𝓓' => 'D', '𝓔' => 'E', '𝓕' => 'F', '𝓖' => 'G', '𝓗' => 'H', '𝓘' => 'I', '𝓙' => 'J', '𝓚' => 'K', '𝓛' => 'L', '𝓜' => 'M', '𝓝' => 'N', '𝓞' => 'O', '𝓟' => 'P', '𝓠' => 'Q', '𝓡' => 'R', '𝓢' => 'S', '𝓣' => 'T', '𝓤' => 'U', '𝓥' => 'V', '𝓦' => 'W', '𝓧' => 'X', '𝓨' => 'Y', '𝓩' => 'Z', '𝓪' => 'a', '𝓫' => 'b', '𝓬' => 'c', '𝓭' => 'd', '𝓮' => 'e', '𝓯' => 'f', '𝓰' => 'g', '𝓱' => 'h', '𝓲' => 'i', '𝓳' => 'j', '𝓴' => 'k', '𝓵' => 'l', '𝓶' => 'm', '𝓷' => 'n', '𝓸' => 'o', '𝓹' => 'p', '𝓺' => 'q', '𝓻' => 'r', '𝓼' => 's', '𝓽' => 't', '𝓾' => 'u', '𝓿' => 'v', '𝔀' => 'w', '𝔁' => 'x', '𝔂' => 'y', '𝔃' => 'z', '𝔄' => 'A', '𝔅' => 'B', '𝔇' => 'D', '𝔈' => 'E', '𝔉' => 'F', '𝔊' => 'G', '𝔍' => 'J', '𝔎' => 'K', '𝔏' => 'L', '𝔐' => 'M', '𝔑' => 'N', '𝔒' => 'O', '𝔓' => 'P', '𝔔' => 'Q', '𝔖' => 'S', '𝔗' => 'T', '𝔘' => 'U', '𝔙' => 'V', '𝔚' => 'W', '𝔛' => 'X', '𝔜' => 'Y', '𝔞' => 'a', '𝔟' => 'b', '𝔠' => 'c', '𝔡' => 'd', '𝔢' => 'e', '𝔣' => 'f', '𝔤' => 'g', '𝔥' => 'h', '𝔦' => 'i', '𝔧' => 'j', '𝔨' => 'k', '𝔩' => 'l', '𝔪' => 'm', '𝔫' => 'n', '𝔬' => 'o', '𝔭' => 'p', '𝔮' => 'q', '𝔯' => 'r', '𝔰' => 's', '𝔱' => 't', '𝔲' => 'u', '𝔳' => 'v', '𝔴' => 'w', '𝔵' => 'x', '𝔶' => 'y', '𝔷' => 'z', '𝔸' => 'A', '𝔹' => 'B', '𝔻' => 'D', '𝔼' => 'E', '𝔽' => 'F', '𝔾' => 'G', '𝕀' => 'I', '𝕁' => 'J', '𝕂' => 'K', '𝕃' => 'L', '𝕄' => 'M', '𝕆' => 'O', '𝕊' => 'S', '𝕋' => 'T', '𝕌' => 'U', '𝕍' => 'V', '𝕎' => 'W', '𝕏' => 'X', '𝕐' => 'Y', '𝕒' => 'a', '𝕓' => 'b', '𝕔' => 'c', '𝕕' => 'd', '𝕖' => 'e', '𝕗' => 'f', '𝕘' => 'g', '𝕙' => 'h', '𝕚' => 'i', '𝕛' => 'j', '𝕜' => 'k', '𝕝' => 'l', '𝕞' => 'm', '𝕟' => 'n', '𝕠' => 'o', '𝕡' => 'p', '𝕢' => 'q', '𝕣' => 'r', '𝕤' => 's', '𝕥' => 't', '𝕦' => 'u', '𝕧' => 'v', '𝕨' => 'w', '𝕩' => 'x', '𝕪' => 'y', '𝕫' => 'z', '𝕬' => 'A', '𝕭' => 'B', '𝕮' => 'C', '𝕯' => 'D', '𝕰' => 'E', '𝕱' => 'F', '𝕲' => 'G', '𝕳' => 'H', '𝕴' => 'I', '𝕵' => 'J', '𝕶' => 'K', '𝕷' => 'L', '𝕸' => 'M', '𝕹' => 'N', '𝕺' => 'O', '𝕻' => 'P', '𝕼' => 'Q', '𝕽' => 'R', '𝕾' => 'S', '𝕿' => 'T', '𝖀' => 'U', '𝖁' => 'V', '𝖂' => 'W', '𝖃' => 'X', '𝖄' => 'Y', '𝖅' => 'Z', '𝖆' => 'a', '𝖇' => 'b', '𝖈' => 'c', '𝖉' => 'd', '𝖊' => 'e', '𝖋' => 'f', '𝖌' => 'g', '𝖍' => 'h', '𝖎' => 'i', '𝖏' => 'j', '𝖐' => 'k', '𝖑' => 'l', '𝖒' => 'm', '𝖓' => 'n', '𝖔' => 'o', '𝖕' => 'p', '𝖖' => 'q', '𝖗' => 'r', '𝖘' => 's', '𝖙' => 't', '𝖚' => 'u', '𝖛' => 'v', '𝖜' => 'w', '𝖝' => 'x', '𝖞' => 'y', '𝖟' => 'z', '𝖠' => 'A', '𝖡' => 'B', '𝖢' => 'C', '𝖣' => 'D', '𝖤' => 'E', '𝖥' => 'F', '𝖦' => 'G', '𝖧' => 'H', '𝖨' => 'I', '𝖩' => 'J', '𝖪' => 'K', '𝖫' => 'L', '𝖬' => 'M', '𝖭' => 'N', '𝖮' => 'O', '𝖯' => 'P', '𝖰' => 'Q', '𝖱' => 'R', '𝖲' => 'S', '𝖳' => 'T', '𝖴' => 'U', '𝖵' => 'V', '𝖶' => 'W', '𝖷' => 'X', '𝖸' => 'Y', '𝖹' => 'Z', '𝖺' => 'a', '𝖻' => 'b', '𝖼' => 'c', '𝖽' => 'd', '𝖾' => 'e', '𝖿' => 'f', '𝗀' => 'g', '𝗁' => 'h', '𝗂' => 'i', '𝗃' => 'j', '𝗄' => 'k', '𝗅' => 'l', '𝗆' => 'm', '𝗇' => 'n', '𝗈' => 'o', '𝗉' => 'p', '𝗊' => 'q', '𝗋' => 'r', '𝗌' => 's', '𝗍' => 't', '𝗎' => 'u', '𝗏' => 'v', '𝗐' => 'w', '𝗑' => 'x', '𝗒' => 'y', '𝗓' => 'z', '𝗔' => 'A', '𝗕' => 'B', '𝗖' => 'C', '𝗗' => 'D', '𝗘' => 'E', '𝗙' => 'F', '𝗚' => 'G', '𝗛' => 'H', '𝗜' => 'I', '𝗝' => 'J', '𝗞' => 'K', '𝗟' => 'L', '𝗠' => 'M', '𝗡' => 'N', '𝗢' => 'O', '𝗣' => 'P', '𝗤' => 'Q', '𝗥' => 'R', '𝗦' => 'S', '𝗧' => 'T', '𝗨' => 'U', '𝗩' => 'V', '𝗪' => 'W', '𝗫' => 'X', '𝗬' => 'Y', '𝗭' => 'Z', '𝗮' => 'a', '𝗯' => 'b', '𝗰' => 'c', '𝗱' => 'd', '𝗲' => 'e', '𝗳' => 'f', '𝗴' => 'g', '𝗵' => 'h', '𝗶' => 'i', '𝗷' => 'j', '𝗸' => 'k', '𝗹' => 'l', '𝗺' => 'm', '𝗻' => 'n', '𝗼' => 'o', '𝗽' => 'p', '𝗾' => 'q', '𝗿' => 'r', '𝘀' => 's', '𝘁' => 't', '𝘂' => 'u', '𝘃' => 'v', '𝘄' => 'w', '𝘅' => 'x', '𝘆' => 'y', '𝘇' => 'z', '𝘈' => 'A', '𝘉' => 'B', '𝘊' => 'C', '𝘋' => 'D', '𝘌' => 'E', '𝘍' => 'F', '𝘎' => 'G', '𝘏' => 'H', '𝘐' => 'I', '𝘑' => 'J', '𝘒' => 'K', '𝘓' => 'L', '𝘔' => 'M', '𝘕' => 'N', '𝘖' => 'O', '𝘗' => 'P', '𝘘' => 'Q', '𝘙' => 'R', '𝘚' => 'S', '𝘛' => 'T', '𝘜' => 'U', '𝘝' => 'V', '𝘞' => 'W', '𝘟' => 'X', '𝘠' => 'Y', '𝘡' => 'Z', '𝘢' => 'a', '𝘣' => 'b', '𝘤' => 'c', '𝘥' => 'd', '𝘦' => 'e', '𝘧' => 'f', '𝘨' => 'g', '𝘩' => 'h', '𝘪' => 'i', '𝘫' => 'j', '𝘬' => 'k', '𝘭' => 'l', '𝘮' => 'm', '𝘯' => 'n', '𝘰' => 'o', '𝘱' => 'p', '𝘲' => 'q', '𝘳' => 'r', '𝘴' => 's', '𝘵' => 't', '𝘶' => 'u', '𝘷' => 'v', '𝘸' => 'w', '𝘹' => 'x', '𝘺' => 'y', '𝘻' => 'z', '𝘼' => 'A', '𝘽' => 'B', '𝘾' => 'C', '𝘿' => 'D', '𝙀' => 'E', '𝙁' => 'F', '𝙂' => 'G', '𝙃' => 'H', '𝙄' => 'I', '𝙅' => 'J', '𝙆' => 'K', '𝙇' => 'L', '𝙈' => 'M', '𝙉' => 'N', '𝙊' => 'O', '𝙋' => 'P', '𝙌' => 'Q', '𝙍' => 'R', '𝙎' => 'S', '𝙏' => 'T', '𝙐' => 'U', '𝙑' => 'V', '𝙒' => 'W', '𝙓' => 'X', '𝙔' => 'Y', '𝙕' => 'Z', '𝙖' => 'a', '𝙗' => 'b', '𝙘' => 'c', '𝙙' => 'd', '𝙚' => 'e', '𝙛' => 'f', '𝙜' => 'g', '𝙝' => 'h', '𝙞' => 'i', '𝙟' => 'j', '𝙠' => 'k', '𝙡' => 'l', '𝙢' => 'm', '𝙣' => 'n', '𝙤' => 'o', '𝙥' => 'p', '𝙦' => 'q', '𝙧' => 'r', '𝙨' => 's', '𝙩' => 't', '𝙪' => 'u', '𝙫' => 'v', '𝙬' => 'w', '𝙭' => 'x', '𝙮' => 'y', '𝙯' => 'z', '𝙰' => 'A', '𝙱' => 'B', '𝙲' => 'C', '𝙳' => 'D', '𝙴' => 'E', '𝙵' => 'F', '𝙶' => 'G', '𝙷' => 'H', '𝙸' => 'I', '𝙹' => 'J', '𝙺' => 'K', '𝙻' => 'L', '𝙼' => 'M', '𝙽' => 'N', '𝙾' => 'O', '𝙿' => 'P', '𝚀' => 'Q', '𝚁' => 'R', '𝚂' => 'S', '𝚃' => 'T', '𝚄' => 'U', '𝚅' => 'V', '𝚆' => 'W', '𝚇' => 'X', '𝚈' => 'Y', '𝚉' => 'Z', '𝚊' => 'a', '𝚋' => 'b', '𝚌' => 'c', '𝚍' => 'd', '𝚎' => 'e', '𝚏' => 'f', '𝚐' => 'g', '𝚑' => 'h', '𝚒' => 'i', '𝚓' => 'j', '𝚔' => 'k', '𝚕' => 'l', '𝚖' => 'm', '𝚗' => 'n', '𝚘' => 'o', '𝚙' => 'p', '𝚚' => 'q', '𝚛' => 'r', '𝚜' => 's', '𝚝' => 't', '𝚞' => 'u', '𝚟' => 'v', '𝚠' => 'w', '𝚡' => 'x', '𝚢' => 'y', '𝚣' => 'z', '𝚤' => 'ı', '𝚥' => 'ȷ', '𝚨' => 'Α', '𝚩' => 'Β', '𝚪' => 'Γ', '𝚫' => 'Δ', '𝚬' => 'Ε', '𝚭' => 'Ζ', '𝚮' => 'Η', '𝚯' => 'Θ', '𝚰' => 'Ι', '𝚱' => 'Κ', '𝚲' => 'Λ', '𝚳' => 'Μ', '𝚴' => 'Ν', '𝚵' => 'Ξ', '𝚶' => 'Ο', '𝚷' => 'Π', '𝚸' => 'Ρ', '𝚹' => 'Θ', '𝚺' => 'Σ', '𝚻' => 'Τ', '𝚼' => 'Υ', '𝚽' => 'Φ', '𝚾' => 'Χ', '𝚿' => 'Ψ', '𝛀' => 'Ω', '𝛁' => '∇', '𝛂' => 'α', '𝛃' => 'β', '𝛄' => 'γ', '𝛅' => 'δ', '𝛆' => 'ε', '𝛇' => 'ζ', '𝛈' => 'η', '𝛉' => 'θ', '𝛊' => 'ι', '𝛋' => 'κ', '𝛌' => 'λ', '𝛍' => 'μ', '𝛎' => 'ν', '𝛏' => 'ξ', '𝛐' => 'ο', '𝛑' => 'π', '𝛒' => 'ρ', '𝛓' => 'ς', '𝛔' => 'σ', '𝛕' => 'τ', '𝛖' => 'υ', '𝛗' => 'φ', '𝛘' => 'χ', '𝛙' => 'ψ', '𝛚' => 'ω', '𝛛' => '∂', '𝛜' => 'ε', '𝛝' => 'θ', '𝛞' => 'κ', '𝛟' => 'φ', '𝛠' => 'ρ', '𝛡' => 'π', '𝛢' => 'Α', '𝛣' => 'Β', '𝛤' => 'Γ', '𝛥' => 'Δ', '𝛦' => 'Ε', '𝛧' => 'Ζ', '𝛨' => 'Η', '𝛩' => 'Θ', '𝛪' => 'Ι', '𝛫' => 'Κ', '𝛬' => 'Λ', '𝛭' => 'Μ', '𝛮' => 'Ν', '𝛯' => 'Ξ', '𝛰' => 'Ο', '𝛱' => 'Π', '𝛲' => 'Ρ', '𝛳' => 'Θ', '𝛴' => 'Σ', '𝛵' => 'Τ', '𝛶' => 'Υ', '𝛷' => 'Φ', '𝛸' => 'Χ', '𝛹' => 'Ψ', '𝛺' => 'Ω', '𝛻' => '∇', '𝛼' => 'α', '𝛽' => 'β', '𝛾' => 'γ', '𝛿' => 'δ', '𝜀' => 'ε', '𝜁' => 'ζ', '𝜂' => 'η', '𝜃' => 'θ', '𝜄' => 'ι', '𝜅' => 'κ', '𝜆' => 'λ', '𝜇' => 'μ', '𝜈' => 'ν', '𝜉' => 'ξ', '𝜊' => 'ο', '𝜋' => 'π', '𝜌' => 'ρ', '𝜍' => 'ς', '𝜎' => 'σ', '𝜏' => 'τ', '𝜐' => 'υ', '𝜑' => 'φ', '𝜒' => 'χ', '𝜓' => 'ψ', '𝜔' => 'ω', '𝜕' => '∂', '𝜖' => 'ε', '𝜗' => 'θ', '𝜘' => 'κ', '𝜙' => 'φ', '𝜚' => 'ρ', '𝜛' => 'π', '𝜜' => 'Α', '𝜝' => 'Β', '𝜞' => 'Γ', '𝜟' => 'Δ', '𝜠' => 'Ε', '𝜡' => 'Ζ', '𝜢' => 'Η', '𝜣' => 'Θ', '𝜤' => 'Ι', '𝜥' => 'Κ', '𝜦' => 'Λ', '𝜧' => 'Μ', '𝜨' => 'Ν', '𝜩' => 'Ξ', '𝜪' => 'Ο', '𝜫' => 'Π', '𝜬' => 'Ρ', '𝜭' => 'Θ', '𝜮' => 'Σ', '𝜯' => 'Τ', '𝜰' => 'Υ', '𝜱' => 'Φ', '𝜲' => 'Χ', '𝜳' => 'Ψ', '𝜴' => 'Ω', '𝜵' => '∇', '𝜶' => 'α', '𝜷' => 'β', '𝜸' => 'γ', '𝜹' => 'δ', '𝜺' => 'ε', '𝜻' => 'ζ', '𝜼' => 'η', '𝜽' => 'θ', '𝜾' => 'ι', '𝜿' => 'κ', '𝝀' => 'λ', '𝝁' => 'μ', '𝝂' => 'ν', '𝝃' => 'ξ', '𝝄' => 'ο', '𝝅' => 'π', '𝝆' => 'ρ', '𝝇' => 'ς', '𝝈' => 'σ', '𝝉' => 'τ', '𝝊' => 'υ', '𝝋' => 'φ', '𝝌' => 'χ', '𝝍' => 'ψ', '𝝎' => 'ω', '𝝏' => '∂', '𝝐' => 'ε', '𝝑' => 'θ', '𝝒' => 'κ', '𝝓' => 'φ', '𝝔' => 'ρ', '𝝕' => 'π', '𝝖' => 'Α', '𝝗' => 'Β', '𝝘' => 'Γ', '𝝙' => 'Δ', '𝝚' => 'Ε', '𝝛' => 'Ζ', '𝝜' => 'Η', '𝝝' => 'Θ', '𝝞' => 'Ι', '𝝟' => 'Κ', '𝝠' => 'Λ', '𝝡' => 'Μ', '𝝢' => 'Ν', '𝝣' => 'Ξ', '𝝤' => 'Ο', '𝝥' => 'Π', '𝝦' => 'Ρ', '𝝧' => 'Θ', '𝝨' => 'Σ', '𝝩' => 'Τ', '𝝪' => 'Υ', '𝝫' => 'Φ', '𝝬' => 'Χ', '𝝭' => 'Ψ', '𝝮' => 'Ω', '𝝯' => '∇', '𝝰' => 'α', '𝝱' => 'β', '𝝲' => 'γ', '𝝳' => 'δ', '𝝴' => 'ε', '𝝵' => 'ζ', '𝝶' => 'η', '𝝷' => 'θ', '𝝸' => 'ι', '𝝹' => 'κ', '𝝺' => 'λ', '𝝻' => 'μ', '𝝼' => 'ν', '𝝽' => 'ξ', '𝝾' => 'ο', '𝝿' => 'π', '𝞀' => 'ρ', '𝞁' => 'ς', '𝞂' => 'σ', '𝞃' => 'τ', '𝞄' => 'υ', '𝞅' => 'φ', '𝞆' => 'χ', '𝞇' => 'ψ', '𝞈' => 'ω', '𝞉' => '∂', '𝞊' => 'ε', '𝞋' => 'θ', '𝞌' => 'κ', '𝞍' => 'φ', '𝞎' => 'ρ', '𝞏' => 'π', '𝞐' => 'Α', '𝞑' => 'Β', '𝞒' => 'Γ', '𝞓' => 'Δ', '𝞔' => 'Ε', '𝞕' => 'Ζ', '𝞖' => 'Η', '𝞗' => 'Θ', '𝞘' => 'Ι', '𝞙' => 'Κ', '𝞚' => 'Λ', '𝞛' => 'Μ', '𝞜' => 'Ν', '𝞝' => 'Ξ', '𝞞' => 'Ο', '𝞟' => 'Π', '𝞠' => 'Ρ', '𝞡' => 'Θ', '𝞢' => 'Σ', '𝞣' => 'Τ', '𝞤' => 'Υ', '𝞥' => 'Φ', '𝞦' => 'Χ', '𝞧' => 'Ψ', '𝞨' => 'Ω', '𝞩' => '∇', '𝞪' => 'α', '𝞫' => 'β', '𝞬' => 'γ', '𝞭' => 'δ', '𝞮' => 'ε', '𝞯' => 'ζ', '𝞰' => 'η', '𝞱' => 'θ', '𝞲' => 'ι', '𝞳' => 'κ', '𝞴' => 'λ', '𝞵' => 'μ', '𝞶' => 'ν', '𝞷' => 'ξ', '𝞸' => 'ο', '𝞹' => 'π', '𝞺' => 'ρ', '𝞻' => 'ς', '𝞼' => 'σ', '𝞽' => 'τ', '𝞾' => 'υ', '𝞿' => 'φ', '𝟀' => 'χ', '𝟁' => 'ψ', '𝟂' => 'ω', '𝟃' => '∂', '𝟄' => 'ε', '𝟅' => 'θ', '𝟆' => 'κ', '𝟇' => 'φ', '𝟈' => 'ρ', '𝟉' => 'π', '𝟊' => 'Ϝ', '𝟋' => 'ϝ', '𝟎' => '0', '𝟏' => '1', '𝟐' => '2', '𝟑' => '3', '𝟒' => '4', '𝟓' => '5', '𝟔' => '6', '𝟕' => '7', '𝟖' => '8', '𝟗' => '9', '𝟘' => '0', '𝟙' => '1', '𝟚' => '2', '𝟛' => '3', '𝟜' => '4', '𝟝' => '5', '𝟞' => '6', '𝟟' => '7', '𝟠' => '8', '𝟡' => '9', '𝟢' => '0', '𝟣' => '1', '𝟤' => '2', '𝟥' => '3', '𝟦' => '4', '𝟧' => '5', '𝟨' => '6', '𝟩' => '7', '𝟪' => '8', '𝟫' => '9', '𝟬' => '0', '𝟭' => '1', '𝟮' => '2', '𝟯' => '3', '𝟰' => '4', '𝟱' => '5', '𝟲' => '6', '𝟳' => '7', '𝟴' => '8', '𝟵' => '9', '𝟶' => '0', '𝟷' => '1', '𝟸' => '2', '𝟹' => '3', '𝟺' => '4', '𝟻' => '5', '𝟼' => '6', '𝟽' => '7', '𝟾' => '8', '𝟿' => '9', '𞸀' => 'ا', '𞸁' => 'ب', '𞸂' => 'ج', '𞸃' => 'د', '𞸅' => 'و', '𞸆' => 'ز', '𞸇' => 'ح', '𞸈' => 'ط', '𞸉' => 'ي', '𞸊' => 'ك', '𞸋' => 'ل', '𞸌' => 'م', '𞸍' => 'ن', '𞸎' => 'س', '𞸏' => 'ع', '𞸐' => 'ف', '𞸑' => 'ص', '𞸒' => 'ق', '𞸓' => 'ر', '𞸔' => 'ش', '𞸕' => 'ت', '𞸖' => 'ث', '𞸗' => 'خ', '𞸘' => 'ذ', '𞸙' => 'ض', '𞸚' => 'ظ', '𞸛' => 'غ', '𞸜' => 'ٮ', '𞸝' => 'ں', '𞸞' => 'ڡ', '𞸟' => 'ٯ', '𞸡' => 'ب', '𞸢' => 'ج', '𞸤' => 'ه', '𞸧' => 'ح', '𞸩' => 'ي', '𞸪' => 'ك', '𞸫' => 'ل', '𞸬' => 'م', '𞸭' => 'ن', '𞸮' => 'س', '𞸯' => 'ع', '𞸰' => 'ف', '𞸱' => 'ص', '𞸲' => 'ق', '𞸴' => 'ش', '𞸵' => 'ت', '𞸶' => 'ث', '𞸷' => 'خ', '𞸹' => 'ض', '𞸻' => 'غ', '𞹂' => 'ج', '𞹇' => 'ح', '𞹉' => 'ي', '𞹋' => 'ل', '𞹍' => 'ن', '𞹎' => 'س', '𞹏' => 'ع', '𞹑' => 'ص', '𞹒' => 'ق', '𞹔' => 'ش', '𞹗' => 'خ', '𞹙' => 'ض', '𞹛' => 'غ', '𞹝' => 'ں', '𞹟' => 'ٯ', '𞹡' => 'ب', '𞹢' => 'ج', '𞹤' => 'ه', '𞹧' => 'ح', '𞹨' => 'ط', '𞹩' => 'ي', '𞹪' => 'ك', '𞹬' => 'م', '𞹭' => 'ن', '𞹮' => 'س', '𞹯' => 'ع', '𞹰' => 'ف', '𞹱' => 'ص', '𞹲' => 'ق', '𞹴' => 'ش', '𞹵' => 'ت', '𞹶' => 'ث', '𞹷' => 'خ', '𞹹' => 'ض', '𞹺' => 'ظ', '𞹻' => 'غ', '𞹼' => 'ٮ', '𞹾' => 'ڡ', '𞺀' => 'ا', '𞺁' => 'ب', '𞺂' => 'ج', '𞺃' => 'د', '𞺄' => 'ه', '𞺅' => 'و', '𞺆' => 'ز', '𞺇' => 'ح', '𞺈' => 'ط', '𞺉' => 'ي', '𞺋' => 'ل', '𞺌' => 'م', '𞺍' => 'ن', '𞺎' => 'س', '𞺏' => 'ع', '𞺐' => 'ف', '𞺑' => 'ص', '𞺒' => 'ق', '𞺓' => 'ر', '𞺔' => 'ش', '𞺕' => 'ت', '𞺖' => 'ث', '𞺗' => 'خ', '𞺘' => 'ذ', '𞺙' => 'ض', '𞺚' => 'ظ', '𞺛' => 'غ', '𞺡' => 'ب', '𞺢' => 'ج', '𞺣' => 'د', '𞺥' => 'و', '𞺦' => 'ز', '𞺧' => 'ح', '𞺨' => 'ط', '𞺩' => 'ي', '𞺫' => 'ل', '𞺬' => 'م', '𞺭' => 'ن', '𞺮' => 'س', '𞺯' => 'ع', '𞺰' => 'ف', '𞺱' => 'ص', '𞺲' => 'ق', '𞺳' => 'ر', '𞺴' => 'ش', '𞺵' => 'ت', '𞺶' => 'ث', '𞺷' => 'خ', '𞺸' => 'ذ', '𞺹' => 'ض', '𞺺' => 'ظ', '𞺻' => 'غ', '🄀' => '0.', '🄁' => '0,', '🄂' => '1,', '🄃' => '2,', '🄄' => '3,', '🄅' => '4,', '🄆' => '5,', '🄇' => '6,', '🄈' => '7,', '🄉' => '8,', '🄊' => '9,', '🄐' => '(A)', '🄑' => '(B)', '🄒' => '(C)', '🄓' => '(D)', '🄔' => '(E)', '🄕' => '(F)', '🄖' => '(G)', '🄗' => '(H)', '🄘' => '(I)', '🄙' => '(J)', '🄚' => '(K)', '🄛' => '(L)', '🄜' => '(M)', '🄝' => '(N)', '🄞' => '(O)', '🄟' => '(P)', '🄠' => '(Q)', '🄡' => '(R)', '🄢' => '(S)', '🄣' => '(T)', '🄤' => '(U)', '🄥' => '(V)', '🄦' => '(W)', '🄧' => '(X)', '🄨' => '(Y)', '🄩' => '(Z)', '🄪' => '〔S〕', '🄫' => 'C', '🄬' => 'R', '🄭' => 'CD', '🄮' => 'WZ', '🄰' => 'A', '🄱' => 'B', '🄲' => 'C', '🄳' => 'D', '🄴' => 'E', '🄵' => 'F', '🄶' => 'G', '🄷' => 'H', '🄸' => 'I', '🄹' => 'J', '🄺' => 'K', '🄻' => 'L', '🄼' => 'M', '🄽' => 'N', '🄾' => 'O', '🄿' => 'P', '🅀' => 'Q', '🅁' => 'R', '🅂' => 'S', '🅃' => 'T', '🅄' => 'U', '🅅' => 'V', '🅆' => 'W', '🅇' => 'X', '🅈' => 'Y', '🅉' => 'Z', '🅊' => 'HV', '🅋' => 'MV', '🅌' => 'SD', '🅍' => 'SS', '🅎' => 'PPV', '🅏' => 'WC', '🅪' => 'MC', '🅫' => 'MD', '🅬' => 'MR', '🆐' => 'DJ', '🈀' => 'ほか', '🈁' => 'ココ', '🈂' => 'サ', '🈐' => '手', '🈑' => '字', '🈒' => '双', '🈓' => 'デ', '🈔' => '二', '🈕' => '多', '🈖' => '解', '🈗' => '天', '🈘' => '交', '🈙' => '映', '🈚' => '無', '🈛' => '料', '🈜' => '前', '🈝' => '後', '🈞' => '再', '🈟' => '新', '🈠' => '初', '🈡' => '終', '🈢' => '生', '🈣' => '販', '🈤' => '声', '🈥' => '吹', '🈦' => '演', '🈧' => '投', '🈨' => '捕', '🈩' => '一', '🈪' => '三', '🈫' => '遊', '🈬' => '左', '🈭' => '中', '🈮' => '右', '🈯' => '指', '🈰' => '走', '🈱' => '打', '🈲' => '禁', '🈳' => '空', '🈴' => '合', '🈵' => '満', '🈶' => '有', '🈷' => '月', '🈸' => '申', '🈹' => '割', '🈺' => '営', '🈻' => '配', '🉀' => '〔本〕', '🉁' => '〔三〕', '🉂' => '〔二〕', '🉃' => '〔安〕', '🉄' => '〔点〕', '🉅' => '〔打〕', '🉆' => '〔盗〕', '🉇' => '〔勝〕', '🉈' => '〔敗〕', '🉐' => '得', '🉑' => '可', '🯰' => '0', '🯱' => '1', '🯲' => '2', '🯳' => '3', '🯴' => '4', '🯵' => '5', '🯶' => '6', '🯷' => '7', '🯸' => '8', '🯹' => '9', ); * * 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 (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); } * * 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 { 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 (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); } * * 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 * * 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 * * @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($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 (PHP_VERSION_ID < 70200 && \is_array($var)) { trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); return 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(); } try { $validEncoding = @self::mb_check_encoding('', $encoding); } catch (\ValueError $e) { throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); } // BC for PHP 7.3 and lower if (!$validEncoding) { throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); } 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); } } 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; } } 'i̇', 'µ' => 'μ', 'ſ' => 's', 'ͅ' => 'ι', 'ς' => 'σ', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϵ' => 'ε', 'ẛ' => 'ṡ', 'ι' => 'ι', 'ß' => 'ss', 'ʼn' => 'ʼn', 'ǰ' => 'ǰ', 'ΐ' => 'ΐ', 'ΰ' => 'ΰ', 'և' => 'եւ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẚ' => 'aʾ', 'ẞ' => 'ss', 'ὐ' => 'ὐ', 'ὒ' => 'ὒ', 'ὔ' => 'ὔ', 'ὖ' => 'ὖ', 'ᾀ' => 'ἀι', 'ᾁ' => 'ἁι', 'ᾂ' => 'ἂι', 'ᾃ' => 'ἃι', 'ᾄ' => 'ἄι', 'ᾅ' => 'ἅι', 'ᾆ' => 'ἆι', 'ᾇ' => 'ἇι', 'ᾈ' => 'ἀι', 'ᾉ' => 'ἁι', 'ᾊ' => 'ἂι', 'ᾋ' => 'ἃι', 'ᾌ' => 'ἄι', 'ᾍ' => 'ἅι', 'ᾎ' => 'ἆι', 'ᾏ' => 'ἇι', 'ᾐ' => 'ἠι', 'ᾑ' => 'ἡι', 'ᾒ' => 'ἢι', 'ᾓ' => 'ἣι', 'ᾔ' => 'ἤι', 'ᾕ' => 'ἥι', 'ᾖ' => 'ἦι', 'ᾗ' => 'ἧι', 'ᾘ' => 'ἠι', 'ᾙ' => 'ἡι', 'ᾚ' => 'ἢι', 'ᾛ' => 'ἣι', 'ᾜ' => 'ἤι', 'ᾝ' => 'ἥι', 'ᾞ' => 'ἦι', 'ᾟ' => 'ἧι', 'ᾠ' => 'ὠι', 'ᾡ' => 'ὡι', 'ᾢ' => 'ὢι', 'ᾣ' => 'ὣι', 'ᾤ' => 'ὤι', 'ᾥ' => 'ὥι', 'ᾦ' => 'ὦι', 'ᾧ' => 'ὧι', 'ᾨ' => 'ὠι', 'ᾩ' => 'ὡι', 'ᾪ' => 'ὢι', 'ᾫ' => 'ὣι', 'ᾬ' => 'ὤι', 'ᾭ' => 'ὥι', 'ᾮ' => 'ὦι', 'ᾯ' => 'ὧι', 'ᾲ' => 'ὰι', 'ᾳ' => 'αι', 'ᾴ' => 'άι', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾶι', 'ᾼ' => 'αι', 'ῂ' => 'ὴι', 'ῃ' => 'ηι', 'ῄ' => 'ήι', 'ῆ' => 'ῆ', 'ῇ' => 'ῆι', 'ῌ' => 'ηι', 'ῒ' => 'ῒ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'ῢ' => 'ῢ', 'ῤ' => 'ῤ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'ῲ' => 'ὼι', 'ῳ' => 'ωι', 'ῴ' => 'ώι', 'ῶ' => 'ῶ', 'ῷ' => 'ῶι', 'ῼ' => 'ωι', 'ff' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'st', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ', ]; '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̇', 'IJ' => 'ij', 'Ĵ' => 'ĵ', 'Ķ' => 'ķ', 'Ĺ' => 'ĺ', 'Ļ' => 'ļ', 'Ľ' => 'ľ', 'Ŀ' => 'ŀ', 'Ł' => 'ł', 'Ń' => 'ń', 'Ņ' => 'ņ', 'Ň' => 'ň', 'Ŋ' => 'ŋ', 'Ō' => 'ō', 'Ŏ' => 'ŏ', 'Ő' => 'ő', 'Œ' => 'œ', 'Ŕ' => 'ŕ', 'Ŗ' => 'ŗ', 'Ř' => 'ř', 'Ś' => 'ś', 'Ŝ' => 'ŝ', 'Ş' => 'ş', 'Š' => 'š', 'Ţ' => 'ţ', 'Ť' => 'ť', 'Ŧ' => 'ŧ', 'Ũ' => 'ũ', 'Ū' => 'ū', 'Ŭ' => 'ŭ', 'Ů' => 'ů', 'Ű' => 'ű', 'Ų' => 'ų', 'Ŵ' => 'ŵ', 'Ŷ' => 'ŷ', 'Ÿ' => 'ÿ', 'Ź' => 'ź', 'Ż' => 'ż', 'Ž' => 'ž', 'Ɓ' => 'ɓ', 'Ƃ' => 'ƃ', 'Ƅ' => 'ƅ', 'Ɔ' => 'ɔ', 'Ƈ' => 'ƈ', 'Ɖ' => 'ɖ', 'Ɗ' => 'ɗ', 'Ƌ' => 'ƌ', 'Ǝ' => 'ǝ', 'Ə' => 'ə', 'Ɛ' => 'ɛ', 'Ƒ' => 'ƒ', 'Ɠ' => 'ɠ', 'Ɣ' => 'ɣ', 'Ɩ' => 'ɩ', 'Ɨ' => 'ɨ', 'Ƙ' => 'ƙ', 'Ɯ' => 'ɯ', 'Ɲ' => 'ɲ', 'Ɵ' => 'ɵ', 'Ơ' => 'ơ', 'Ƣ' => 'ƣ', 'Ƥ' => 'ƥ', 'Ʀ' => 'ʀ', 'Ƨ' => 'ƨ', 'Ʃ' => 'ʃ', 'Ƭ' => 'ƭ', 'Ʈ' => 'ʈ', 'Ư' => 'ư', 'Ʊ' => 'ʊ', 'Ʋ' => 'ʋ', 'Ƴ' => 'ƴ', 'Ƶ' => 'ƶ', 'Ʒ' => 'ʒ', 'Ƹ' => 'ƹ', 'Ƽ' => 'ƽ', 'DŽ' => 'dž', 'Dž' => 'dž', 'LJ' => 'lj', 'Lj' => 'lj', 'NJ' => 'nj', 'Nj' => 'nj', 'Ǎ' => 'ǎ', 'Ǐ' => 'ǐ', 'Ǒ' => 'ǒ', 'Ǔ' => 'ǔ', 'Ǖ' => 'ǖ', 'Ǘ' => 'ǘ', 'Ǚ' => 'ǚ', 'Ǜ' => 'ǜ', 'Ǟ' => 'ǟ', 'Ǡ' => 'ǡ', 'Ǣ' => 'ǣ', 'Ǥ' => 'ǥ', 'Ǧ' => 'ǧ', 'Ǩ' => 'ǩ', 'Ǫ' => 'ǫ', 'Ǭ' => 'ǭ', 'Ǯ' => 'ǯ', 'DZ' => 'dz', 'Dz' => 'dz', 'Ǵ' => 'ǵ', 'Ƕ' => 'ƕ', 'Ƿ' => 'ƿ', 'Ǹ' => 'ǹ', 'Ǻ' => 'ǻ', 'Ǽ' => 'ǽ', 'Ǿ' => 'ǿ', 'Ȁ' => 'ȁ', 'Ȃ' => 'ȃ', 'Ȅ' => 'ȅ', 'Ȇ' => 'ȇ', 'Ȉ' => 'ȉ', 'Ȋ' => 'ȋ', 'Ȍ' => 'ȍ', 'Ȏ' => 'ȏ', 'Ȑ' => 'ȑ', 'Ȓ' => 'ȓ', 'Ȕ' => 'ȕ', 'Ȗ' => 'ȗ', 'Ș' => 'ș', 'Ț' => 'ț', 'Ȝ' => 'ȝ', 'Ȟ' => 'ȟ', 'Ƞ' => 'ƞ', 'Ȣ' => 'ȣ', 'Ȥ' => 'ȥ', 'Ȧ' => 'ȧ', 'Ȩ' => 'ȩ', 'Ȫ' => 'ȫ', 'Ȭ' => 'ȭ', 'Ȯ' => 'ȯ', 'Ȱ' => 'ȱ', 'Ȳ' => 'ȳ', 'Ⱥ' => 'ⱥ', 'Ȼ' => 'ȼ', 'Ƚ' => 'ƚ', 'Ⱦ' => 'ⱦ', 'Ɂ' => 'ɂ', 'Ƀ' => 'ƀ', 'Ʉ' => 'ʉ', 'Ʌ' => 'ʌ', 'Ɇ' => 'ɇ', 'Ɉ' => 'ɉ', 'Ɋ' => 'ɋ', 'Ɍ' => 'ɍ', 'Ɏ' => 'ɏ', 'Ͱ' => 'ͱ', 'Ͳ' => 'ͳ', 'Ͷ' => 'ͷ', 'Ϳ' => 'ϳ', 'Ά' => 'ά', 'Έ' => 'έ', 'Ή' => 'ή', 'Ί' => 'ί', 'Ό' => 'ό', 'Ύ' => 'ύ', 'Ώ' => 'ώ', 'Α' => 'α', 'Β' => 'β', 'Γ' => 'γ', 'Δ' => 'δ', 'Ε' => 'ε', 'Ζ' => 'ζ', 'Η' => 'η', 'Θ' => 'θ', 'Ι' => 'ι', 'Κ' => 'κ', 'Λ' => 'λ', 'Μ' => 'μ', 'Ν' => 'ν', 'Ξ' => 'ξ', 'Ο' => 'ο', 'Π' => 'π', 'Ρ' => 'ρ', 'Σ' => 'σ', 'Τ' => 'τ', 'Υ' => 'υ', 'Φ' => 'φ', 'Χ' => 'χ', 'Ψ' => 'ψ', 'Ω' => 'ω', 'Ϊ' => 'ϊ', 'Ϋ' => 'ϋ', 'Ϗ' => 'ϗ', 'Ϙ' => 'ϙ', 'Ϛ' => 'ϛ', 'Ϝ' => 'ϝ', 'Ϟ' => 'ϟ', 'Ϡ' => 'ϡ', 'Ϣ' => 'ϣ', 'Ϥ' => 'ϥ', 'Ϧ' => 'ϧ', 'Ϩ' => 'ϩ', 'Ϫ' => 'ϫ', 'Ϭ' => 'ϭ', 'Ϯ' => 'ϯ', 'ϴ' => 'θ', 'Ϸ' => 'ϸ', 'Ϲ' => 'ϲ', 'Ϻ' => 'ϻ', 'Ͻ' => 'ͻ', 'Ͼ' => 'ͼ', 'Ͽ' => 'ͽ', 'Ѐ' => 'ѐ', 'Ё' => 'ё', 'Ђ' => 'ђ', 'Ѓ' => 'ѓ', 'Є' => 'є', 'Ѕ' => 'ѕ', 'І' => 'і', 'Ї' => 'ї', 'Ј' => 'ј', 'Љ' => 'љ', 'Њ' => 'њ', 'Ћ' => 'ћ', 'Ќ' => 'ќ', 'Ѝ' => 'ѝ', 'Ў' => 'ў', 'Џ' => 'џ', 'А' => 'а', 'Б' => 'б', 'В' => 'в', 'Г' => 'г', 'Д' => 'д', 'Е' => 'е', 'Ж' => 'ж', 'З' => 'з', 'И' => 'и', 'Й' => 'й', 'К' => 'к', 'Л' => 'л', 'М' => 'м', 'Н' => 'н', 'О' => 'о', 'П' => 'п', 'Р' => 'р', 'С' => 'с', 'Т' => 'т', 'У' => 'у', 'Ф' => 'ф', 'Х' => 'х', 'Ц' => 'ц', 'Ч' => 'ч', 'Ш' => 'ш', 'Щ' => 'щ', 'Ъ' => 'ъ', 'Ы' => 'ы', 'Ь' => 'ь', 'Э' => 'э', 'Ю' => 'ю', 'Я' => 'я', 'Ѡ' => 'ѡ', 'Ѣ' => 'ѣ', 'Ѥ' => 'ѥ', 'Ѧ' => 'ѧ', 'Ѩ' => 'ѩ', 'Ѫ' => 'ѫ', 'Ѭ' => 'ѭ', 'Ѯ' => 'ѯ', 'Ѱ' => 'ѱ', 'Ѳ' => 'ѳ', 'Ѵ' => 'ѵ', 'Ѷ' => 'ѷ', 'Ѹ' => 'ѹ', 'Ѻ' => 'ѻ', 'Ѽ' => 'ѽ', 'Ѿ' => 'ѿ', 'Ҁ' => 'ҁ', 'Ҋ' => 'ҋ', 'Ҍ' => 'ҍ', 'Ҏ' => 'ҏ', 'Ґ' => 'ґ', 'Ғ' => 'ғ', 'Ҕ' => 'ҕ', 'Җ' => 'җ', 'Ҙ' => 'ҙ', 'Қ' => 'қ', 'Ҝ' => 'ҝ', 'Ҟ' => 'ҟ', 'Ҡ' => 'ҡ', 'Ң' => 'ң', 'Ҥ' => 'ҥ', 'Ҧ' => 'ҧ', 'Ҩ' => 'ҩ', 'Ҫ' => 'ҫ', 'Ҭ' => 'ҭ', 'Ү' => 'ү', 'Ұ' => 'ұ', 'Ҳ' => 'ҳ', 'Ҵ' => 'ҵ', 'Ҷ' => 'ҷ', 'Ҹ' => 'ҹ', 'Һ' => 'һ', 'Ҽ' => 'ҽ', 'Ҿ' => 'ҿ', 'Ӏ' => 'ӏ', 'Ӂ' => 'ӂ', 'Ӄ' => 'ӄ', 'Ӆ' => 'ӆ', 'Ӈ' => 'ӈ', 'Ӊ' => 'ӊ', 'Ӌ' => 'ӌ', 'Ӎ' => 'ӎ', 'Ӑ' => 'ӑ', 'Ӓ' => 'ӓ', 'Ӕ' => 'ӕ', 'Ӗ' => 'ӗ', 'Ә' => 'ә', 'Ӛ' => 'ӛ', 'Ӝ' => 'ӝ', 'Ӟ' => 'ӟ', 'Ӡ' => 'ӡ', 'Ӣ' => 'ӣ', 'Ӥ' => 'ӥ', 'Ӧ' => 'ӧ', 'Ө' => 'ө', 'Ӫ' => 'ӫ', 'Ӭ' => 'ӭ', 'Ӯ' => 'ӯ', 'Ӱ' => 'ӱ', 'Ӳ' => 'ӳ', 'Ӵ' => 'ӵ', 'Ӷ' => 'ӷ', 'Ӹ' => 'ӹ', 'Ӻ' => 'ӻ', 'Ӽ' => 'ӽ', 'Ӿ' => 'ӿ', 'Ԁ' => 'ԁ', 'Ԃ' => 'ԃ', 'Ԅ' => 'ԅ', 'Ԇ' => 'ԇ', 'Ԉ' => 'ԉ', 'Ԋ' => 'ԋ', 'Ԍ' => 'ԍ', 'Ԏ' => 'ԏ', 'Ԑ' => 'ԑ', 'Ԓ' => 'ԓ', 'Ԕ' => 'ԕ', 'Ԗ' => 'ԗ', 'Ԙ' => 'ԙ', 'Ԛ' => 'ԛ', 'Ԝ' => 'ԝ', 'Ԟ' => 'ԟ', 'Ԡ' => 'ԡ', 'Ԣ' => 'ԣ', 'Ԥ' => 'ԥ', 'Ԧ' => 'ԧ', 'Ԩ' => 'ԩ', 'Ԫ' => 'ԫ', 'Ԭ' => 'ԭ', 'Ԯ' => 'ԯ', 'Ա' => 'ա', 'Բ' => 'բ', 'Գ' => 'գ', 'Դ' => 'դ', 'Ե' => 'ե', 'Զ' => 'զ', 'Է' => 'է', 'Ը' => 'ը', 'Թ' => 'թ', 'Ժ' => 'ժ', 'Ի' => 'ի', 'Լ' => 'լ', 'Խ' => 'խ', 'Ծ' => 'ծ', 'Կ' => 'կ', 'Հ' => 'հ', 'Ձ' => 'ձ', 'Ղ' => 'ղ', 'Ճ' => 'ճ', 'Մ' => 'մ', 'Յ' => 'յ', 'Ն' => 'ն', 'Շ' => 'շ', 'Ո' => 'ո', 'Չ' => 'չ', 'Պ' => 'պ', 'Ջ' => 'ջ', 'Ռ' => 'ռ', 'Ս' => 'ս', 'Վ' => 'վ', 'Տ' => 'տ', 'Ր' => 'ր', 'Ց' => 'ց', 'Ւ' => 'ւ', 'Փ' => 'փ', 'Ք' => 'ք', 'Օ' => 'օ', 'Ֆ' => 'ֆ', 'Ⴀ' => 'ⴀ', 'Ⴁ' => 'ⴁ', 'Ⴂ' => 'ⴂ', 'Ⴃ' => 'ⴃ', 'Ⴄ' => 'ⴄ', 'Ⴅ' => 'ⴅ', 'Ⴆ' => 'ⴆ', 'Ⴇ' => 'ⴇ', 'Ⴈ' => 'ⴈ', 'Ⴉ' => 'ⴉ', 'Ⴊ' => 'ⴊ', 'Ⴋ' => 'ⴋ', 'Ⴌ' => 'ⴌ', 'Ⴍ' => 'ⴍ', 'Ⴎ' => 'ⴎ', 'Ⴏ' => 'ⴏ', 'Ⴐ' => 'ⴐ', 'Ⴑ' => 'ⴑ', 'Ⴒ' => 'ⴒ', 'Ⴓ' => 'ⴓ', 'Ⴔ' => 'ⴔ', 'Ⴕ' => 'ⴕ', 'Ⴖ' => 'ⴖ', 'Ⴗ' => 'ⴗ', 'Ⴘ' => 'ⴘ', 'Ⴙ' => 'ⴙ', 'Ⴚ' => 'ⴚ', 'Ⴛ' => 'ⴛ', 'Ⴜ' => 'ⴜ', 'Ⴝ' => 'ⴝ', 'Ⴞ' => 'ⴞ', 'Ⴟ' => 'ⴟ', 'Ⴠ' => 'ⴠ', 'Ⴡ' => 'ⴡ', 'Ⴢ' => 'ⴢ', 'Ⴣ' => 'ⴣ', 'Ⴤ' => 'ⴤ', 'Ⴥ' => 'ⴥ', 'Ⴧ' => 'ⴧ', 'Ⴭ' => 'ⴭ', 'Ꭰ' => 'ꭰ', 'Ꭱ' => 'ꭱ', 'Ꭲ' => 'ꭲ', 'Ꭳ' => 'ꭳ', 'Ꭴ' => 'ꭴ', 'Ꭵ' => 'ꭵ', 'Ꭶ' => 'ꭶ', 'Ꭷ' => 'ꭷ', 'Ꭸ' => 'ꭸ', 'Ꭹ' => 'ꭹ', 'Ꭺ' => 'ꭺ', 'Ꭻ' => 'ꭻ', 'Ꭼ' => 'ꭼ', 'Ꭽ' => 'ꭽ', 'Ꭾ' => 'ꭾ', 'Ꭿ' => 'ꭿ', 'Ꮀ' => 'ꮀ', 'Ꮁ' => 'ꮁ', 'Ꮂ' => 'ꮂ', 'Ꮃ' => 'ꮃ', 'Ꮄ' => 'ꮄ', 'Ꮅ' => 'ꮅ', 'Ꮆ' => 'ꮆ', 'Ꮇ' => 'ꮇ', 'Ꮈ' => 'ꮈ', 'Ꮉ' => 'ꮉ', 'Ꮊ' => 'ꮊ', 'Ꮋ' => 'ꮋ', 'Ꮌ' => 'ꮌ', 'Ꮍ' => 'ꮍ', 'Ꮎ' => 'ꮎ', 'Ꮏ' => 'ꮏ', 'Ꮐ' => 'ꮐ', 'Ꮑ' => 'ꮑ', 'Ꮒ' => 'ꮒ', 'Ꮓ' => 'ꮓ', 'Ꮔ' => 'ꮔ', 'Ꮕ' => 'ꮕ', 'Ꮖ' => 'ꮖ', 'Ꮗ' => 'ꮗ', 'Ꮘ' => 'ꮘ', 'Ꮙ' => 'ꮙ', 'Ꮚ' => 'ꮚ', 'Ꮛ' => 'ꮛ', 'Ꮜ' => 'ꮜ', 'Ꮝ' => 'ꮝ', 'Ꮞ' => 'ꮞ', 'Ꮟ' => 'ꮟ', 'Ꮠ' => 'ꮠ', 'Ꮡ' => 'ꮡ', 'Ꮢ' => 'ꮢ', 'Ꮣ' => 'ꮣ', 'Ꮤ' => 'ꮤ', 'Ꮥ' => 'ꮥ', 'Ꮦ' => 'ꮦ', 'Ꮧ' => 'ꮧ', 'Ꮨ' => 'ꮨ', 'Ꮩ' => 'ꮩ', 'Ꮪ' => 'ꮪ', 'Ꮫ' => 'ꮫ', 'Ꮬ' => 'ꮬ', 'Ꮭ' => 'ꮭ', 'Ꮮ' => 'ꮮ', 'Ꮯ' => 'ꮯ', 'Ꮰ' => 'ꮰ', 'Ꮱ' => 'ꮱ', 'Ꮲ' => 'ꮲ', 'Ꮳ' => 'ꮳ', 'Ꮴ' => 'ꮴ', 'Ꮵ' => 'ꮵ', 'Ꮶ' => 'ꮶ', 'Ꮷ' => 'ꮷ', 'Ꮸ' => 'ꮸ', 'Ꮹ' => 'ꮹ', 'Ꮺ' => 'ꮺ', 'Ꮻ' => 'ꮻ', 'Ꮼ' => 'ꮼ', 'Ꮽ' => 'ꮽ', 'Ꮾ' => 'ꮾ', 'Ꮿ' => 'ꮿ', 'Ᏸ' => 'ᏸ', 'Ᏹ' => 'ᏹ', 'Ᏺ' => 'ᏺ', 'Ᏻ' => 'ᏻ', 'Ᏼ' => 'ᏼ', 'Ᏽ' => 'ᏽ', 'Ა' => 'ა', 'Ბ' => 'ბ', 'Გ' => 'გ', 'Დ' => 'დ', 'Ე' => 'ე', 'Ვ' => 'ვ', 'Ზ' => 'ზ', 'Თ' => 'თ', 'Ი' => 'ი', 'Კ' => 'კ', 'Ლ' => 'ლ', 'Მ' => 'მ', 'Ნ' => 'ნ', 'Ო' => 'ო', 'Პ' => 'პ', 'Ჟ' => 'ჟ', 'Რ' => 'რ', 'Ს' => 'ს', 'Ტ' => 'ტ', 'Უ' => 'უ', 'Ფ' => 'ფ', 'Ქ' => 'ქ', 'Ღ' => 'ღ', 'Ყ' => 'ყ', 'Შ' => 'შ', 'Ჩ' => 'ჩ', 'Ც' => 'ც', 'Ძ' => 'ძ', 'Წ' => 'წ', 'Ჭ' => 'ჭ', 'Ხ' => 'ხ', 'Ჯ' => 'ჯ', 'Ჰ' => 'ჰ', 'Ჱ' => 'ჱ', 'Ჲ' => 'ჲ', 'Ჳ' => 'ჳ', 'Ჴ' => 'ჴ', 'Ჵ' => 'ჵ', 'Ჶ' => 'ჶ', 'Ჷ' => 'ჷ', 'Ჸ' => 'ჸ', 'Ჹ' => 'ჹ', 'Ჺ' => 'ჺ', 'Ჽ' => 'ჽ', 'Ჾ' => 'ჾ', 'Ჿ' => 'ჿ', 'Ḁ' => 'ḁ', 'Ḃ' => 'ḃ', 'Ḅ' => 'ḅ', 'Ḇ' => 'ḇ', 'Ḉ' => 'ḉ', 'Ḋ' => 'ḋ', 'Ḍ' => 'ḍ', 'Ḏ' => 'ḏ', 'Ḑ' => 'ḑ', 'Ḓ' => 'ḓ', 'Ḕ' => 'ḕ', 'Ḗ' => 'ḗ', 'Ḙ' => 'ḙ', 'Ḛ' => 'ḛ', 'Ḝ' => 'ḝ', 'Ḟ' => 'ḟ', 'Ḡ' => 'ḡ', 'Ḣ' => 'ḣ', 'Ḥ' => 'ḥ', 'Ḧ' => 'ḧ', 'Ḩ' => 'ḩ', 'Ḫ' => 'ḫ', 'Ḭ' => 'ḭ', 'Ḯ' => 'ḯ', 'Ḱ' => 'ḱ', 'Ḳ' => 'ḳ', 'Ḵ' => 'ḵ', 'Ḷ' => 'ḷ', 'Ḹ' => 'ḹ', 'Ḻ' => 'ḻ', 'Ḽ' => 'ḽ', 'Ḿ' => 'ḿ', 'Ṁ' => 'ṁ', 'Ṃ' => 'ṃ', 'Ṅ' => 'ṅ', 'Ṇ' => 'ṇ', 'Ṉ' => 'ṉ', 'Ṋ' => 'ṋ', 'Ṍ' => 'ṍ', 'Ṏ' => 'ṏ', 'Ṑ' => 'ṑ', 'Ṓ' => 'ṓ', 'Ṕ' => 'ṕ', 'Ṗ' => 'ṗ', 'Ṙ' => 'ṙ', 'Ṛ' => 'ṛ', 'Ṝ' => 'ṝ', 'Ṟ' => 'ṟ', 'Ṡ' => 'ṡ', 'Ṣ' => 'ṣ', 'Ṥ' => 'ṥ', 'Ṧ' => 'ṧ', 'Ṩ' => 'ṩ', 'Ṫ' => 'ṫ', 'Ṭ' => 'ṭ', 'Ṯ' => 'ṯ', 'Ṱ' => 'ṱ', 'Ṳ' => 'ṳ', 'Ṵ' => 'ṵ', 'Ṷ' => 'ṷ', 'Ṹ' => 'ṹ', 'Ṻ' => 'ṻ', 'Ṽ' => 'ṽ', 'Ṿ' => 'ṿ', 'Ẁ' => 'ẁ', 'Ẃ' => 'ẃ', 'Ẅ' => 'ẅ', 'Ẇ' => 'ẇ', 'Ẉ' => 'ẉ', 'Ẋ' => 'ẋ', 'Ẍ' => 'ẍ', 'Ẏ' => 'ẏ', 'Ẑ' => 'ẑ', 'Ẓ' => 'ẓ', 'Ẕ' => 'ẕ', 'ẞ' => 'ß', 'Ạ' => 'ạ', 'Ả' => 'ả', 'Ấ' => 'ấ', 'Ầ' => 'ầ', 'Ẩ' => 'ẩ', 'Ẫ' => 'ẫ', 'Ậ' => 'ậ', 'Ắ' => 'ắ', 'Ằ' => 'ằ', 'Ẳ' => 'ẳ', 'Ẵ' => 'ẵ', 'Ặ' => 'ặ', 'Ẹ' => 'ẹ', 'Ẻ' => 'ẻ', 'Ẽ' => 'ẽ', 'Ế' => 'ế', 'Ề' => 'ề', 'Ể' => 'ể', 'Ễ' => 'ễ', 'Ệ' => 'ệ', 'Ỉ' => 'ỉ', 'Ị' => 'ị', 'Ọ' => 'ọ', 'Ỏ' => 'ỏ', 'Ố' => 'ố', 'Ồ' => 'ồ', 'Ổ' => 'ổ', 'Ỗ' => 'ỗ', 'Ộ' => 'ộ', 'Ớ' => 'ớ', 'Ờ' => 'ờ', 'Ở' => 'ở', 'Ỡ' => 'ỡ', 'Ợ' => 'ợ', 'Ụ' => 'ụ', 'Ủ' => 'ủ', 'Ứ' => 'ứ', 'Ừ' => 'ừ', 'Ử' => 'ử', 'Ữ' => 'ữ', 'Ự' => 'ự', 'Ỳ' => 'ỳ', 'Ỵ' => 'ỵ', 'Ỷ' => 'ỷ', 'Ỹ' => 'ỹ', 'Ỻ' => 'ỻ', 'Ỽ' => 'ỽ', 'Ỿ' => 'ỿ', 'Ἀ' => 'ἀ', 'Ἁ' => 'ἁ', 'Ἂ' => 'ἂ', 'Ἃ' => 'ἃ', 'Ἄ' => 'ἄ', 'Ἅ' => 'ἅ', 'Ἆ' => 'ἆ', 'Ἇ' => 'ἇ', 'Ἐ' => 'ἐ', 'Ἑ' => 'ἑ', 'Ἒ' => 'ἒ', 'Ἓ' => 'ἓ', 'Ἔ' => 'ἔ', 'Ἕ' => 'ἕ', 'Ἠ' => 'ἠ', 'Ἡ' => 'ἡ', 'Ἢ' => 'ἢ', 'Ἣ' => 'ἣ', 'Ἤ' => 'ἤ', 'Ἥ' => 'ἥ', 'Ἦ' => 'ἦ', 'Ἧ' => 'ἧ', 'Ἰ' => 'ἰ', 'Ἱ' => 'ἱ', 'Ἲ' => 'ἲ', 'Ἳ' => 'ἳ', 'Ἴ' => 'ἴ', 'Ἵ' => 'ἵ', 'Ἶ' => 'ἶ', 'Ἷ' => 'ἷ', 'Ὀ' => 'ὀ', 'Ὁ' => 'ὁ', 'Ὂ' => 'ὂ', 'Ὃ' => 'ὃ', 'Ὄ' => 'ὄ', 'Ὅ' => 'ὅ', 'Ὑ' => 'ὑ', 'Ὓ' => 'ὓ', 'Ὕ' => 'ὕ', 'Ὗ' => 'ὗ', 'Ὠ' => 'ὠ', 'Ὡ' => 'ὡ', 'Ὢ' => 'ὢ', 'Ὣ' => 'ὣ', 'Ὤ' => 'ὤ', 'Ὥ' => 'ὥ', 'Ὦ' => 'ὦ', 'Ὧ' => 'ὧ', 'ᾈ' => 'ᾀ', 'ᾉ' => 'ᾁ', 'ᾊ' => 'ᾂ', 'ᾋ' => 'ᾃ', 'ᾌ' => 'ᾄ', 'ᾍ' => 'ᾅ', 'ᾎ' => 'ᾆ', 'ᾏ' => 'ᾇ', 'ᾘ' => 'ᾐ', 'ᾙ' => 'ᾑ', 'ᾚ' => 'ᾒ', 'ᾛ' => 'ᾓ', 'ᾜ' => 'ᾔ', 'ᾝ' => 'ᾕ', 'ᾞ' => 'ᾖ', 'ᾟ' => 'ᾗ', 'ᾨ' => 'ᾠ', 'ᾩ' => 'ᾡ', 'ᾪ' => 'ᾢ', 'ᾫ' => 'ᾣ', 'ᾬ' => 'ᾤ', 'ᾭ' => 'ᾥ', 'ᾮ' => 'ᾦ', 'ᾯ' => 'ᾧ', 'Ᾰ' => 'ᾰ', 'Ᾱ' => 'ᾱ', 'Ὰ' => 'ὰ', 'Ά' => 'ά', 'ᾼ' => 'ᾳ', 'Ὲ' => 'ὲ', 'Έ' => 'έ', 'Ὴ' => 'ὴ', 'Ή' => 'ή', 'ῌ' => 'ῃ', 'Ῐ' => 'ῐ', 'Ῑ' => 'ῑ', 'Ὶ' => 'ὶ', 'Ί' => 'ί', 'Ῠ' => 'ῠ', 'Ῡ' => 'ῡ', 'Ὺ' => 'ὺ', 'Ύ' => 'ύ', 'Ῥ' => 'ῥ', 'Ὸ' => 'ὸ', 'Ό' => 'ό', 'Ὼ' => 'ὼ', 'Ώ' => 'ώ', 'ῼ' => 'ῳ', 'Ω' => 'ω', 'K' => 'k', 'Å' => 'å', 'Ⅎ' => 'ⅎ', 'Ⅰ' => 'ⅰ', 'Ⅱ' => 'ⅱ', 'Ⅲ' => 'ⅲ', 'Ⅳ' => 'ⅳ', 'Ⅴ' => 'ⅴ', 'Ⅵ' => 'ⅵ', 'Ⅶ' => 'ⅶ', 'Ⅷ' => 'ⅷ', 'Ⅸ' => 'ⅸ', 'Ⅹ' => 'ⅹ', 'Ⅺ' => 'ⅺ', 'Ⅻ' => 'ⅻ', 'Ⅼ' => 'ⅼ', 'Ⅽ' => 'ⅽ', 'Ⅾ' => 'ⅾ', 'Ⅿ' => 'ⅿ', 'Ↄ' => 'ↄ', 'Ⓐ' => 'ⓐ', 'Ⓑ' => 'ⓑ', 'Ⓒ' => 'ⓒ', 'Ⓓ' => 'ⓓ', 'Ⓔ' => 'ⓔ', 'Ⓕ' => 'ⓕ', 'Ⓖ' => 'ⓖ', 'Ⓗ' => 'ⓗ', 'Ⓘ' => 'ⓘ', 'Ⓙ' => 'ⓙ', 'Ⓚ' => 'ⓚ', 'Ⓛ' => 'ⓛ', 'Ⓜ' => 'ⓜ', 'Ⓝ' => 'ⓝ', 'Ⓞ' => 'ⓞ', 'Ⓟ' => 'ⓟ', 'Ⓠ' => 'ⓠ', 'Ⓡ' => 'ⓡ', 'Ⓢ' => 'ⓢ', 'Ⓣ' => 'ⓣ', 'Ⓤ' => 'ⓤ', 'Ⓥ' => 'ⓥ', 'Ⓦ' => 'ⓦ', 'Ⓧ' => 'ⓧ', 'Ⓨ' => 'ⓨ', 'Ⓩ' => 'ⓩ', 'Ⰰ' => 'ⰰ', 'Ⰱ' => 'ⰱ', 'Ⰲ' => 'ⰲ', 'Ⰳ' => 'ⰳ', 'Ⰴ' => 'ⰴ', 'Ⰵ' => 'ⰵ', 'Ⰶ' => 'ⰶ', 'Ⰷ' => 'ⰷ', 'Ⰸ' => 'ⰸ', 'Ⰹ' => 'ⰹ', 'Ⰺ' => 'ⰺ', 'Ⰻ' => 'ⰻ', 'Ⰼ' => 'ⰼ', 'Ⰽ' => 'ⰽ', 'Ⰾ' => 'ⰾ', 'Ⰿ' => 'ⰿ', 'Ⱀ' => 'ⱀ', 'Ⱁ' => 'ⱁ', 'Ⱂ' => 'ⱂ', 'Ⱃ' => 'ⱃ', 'Ⱄ' => 'ⱄ', 'Ⱅ' => 'ⱅ', 'Ⱆ' => 'ⱆ', 'Ⱇ' => 'ⱇ', 'Ⱈ' => 'ⱈ', 'Ⱉ' => 'ⱉ', 'Ⱊ' => 'ⱊ', 'Ⱋ' => 'ⱋ', 'Ⱌ' => 'ⱌ', 'Ⱍ' => 'ⱍ', 'Ⱎ' => 'ⱎ', 'Ⱏ' => 'ⱏ', 'Ⱐ' => 'ⱐ', 'Ⱑ' => 'ⱑ', 'Ⱒ' => 'ⱒ', 'Ⱓ' => 'ⱓ', 'Ⱔ' => 'ⱔ', 'Ⱕ' => 'ⱕ', 'Ⱖ' => 'ⱖ', 'Ⱗ' => 'ⱗ', 'Ⱘ' => 'ⱘ', 'Ⱙ' => 'ⱙ', 'Ⱚ' => 'ⱚ', 'Ⱛ' => 'ⱛ', 'Ⱜ' => 'ⱜ', 'Ⱝ' => 'ⱝ', 'Ⱞ' => 'ⱞ', 'Ⱡ' => 'ⱡ', 'Ɫ' => 'ɫ', 'Ᵽ' => 'ᵽ', 'Ɽ' => 'ɽ', 'Ⱨ' => 'ⱨ', 'Ⱪ' => 'ⱪ', 'Ⱬ' => 'ⱬ', 'Ɑ' => 'ɑ', 'Ɱ' => 'ɱ', 'Ɐ' => 'ɐ', 'Ɒ' => 'ɒ', 'Ⱳ' => 'ⱳ', 'Ⱶ' => 'ⱶ', 'Ȿ' => 'ȿ', 'Ɀ' => 'ɀ', 'Ⲁ' => 'ⲁ', 'Ⲃ' => 'ⲃ', 'Ⲅ' => 'ⲅ', 'Ⲇ' => 'ⲇ', 'Ⲉ' => 'ⲉ', 'Ⲋ' => 'ⲋ', 'Ⲍ' => 'ⲍ', 'Ⲏ' => 'ⲏ', 'Ⲑ' => 'ⲑ', 'Ⲓ' => 'ⲓ', 'Ⲕ' => 'ⲕ', 'Ⲗ' => 'ⲗ', 'Ⲙ' => 'ⲙ', 'Ⲛ' => 'ⲛ', 'Ⲝ' => 'ⲝ', 'Ⲟ' => 'ⲟ', 'Ⲡ' => 'ⲡ', 'Ⲣ' => 'ⲣ', 'Ⲥ' => 'ⲥ', 'Ⲧ' => 'ⲧ', 'Ⲩ' => 'ⲩ', 'Ⲫ' => 'ⲫ', 'Ⲭ' => 'ⲭ', 'Ⲯ' => 'ⲯ', 'Ⲱ' => 'ⲱ', 'Ⲳ' => 'ⲳ', 'Ⲵ' => 'ⲵ', 'Ⲷ' => 'ⲷ', 'Ⲹ' => 'ⲹ', 'Ⲻ' => 'ⲻ', 'Ⲽ' => 'ⲽ', 'Ⲿ' => 'ⲿ', 'Ⳁ' => 'ⳁ', 'Ⳃ' => 'ⳃ', 'Ⳅ' => 'ⳅ', 'Ⳇ' => 'ⳇ', 'Ⳉ' => 'ⳉ', 'Ⳋ' => 'ⳋ', 'Ⳍ' => 'ⳍ', 'Ⳏ' => 'ⳏ', 'Ⳑ' => 'ⳑ', 'Ⳓ' => 'ⳓ', 'Ⳕ' => 'ⳕ', 'Ⳗ' => 'ⳗ', 'Ⳙ' => 'ⳙ', 'Ⳛ' => 'ⳛ', 'Ⳝ' => 'ⳝ', 'Ⳟ' => 'ⳟ', 'Ⳡ' => 'ⳡ', 'Ⳣ' => 'ⳣ', 'Ⳬ' => 'ⳬ', 'Ⳮ' => 'ⳮ', 'Ⳳ' => 'ⳳ', 'Ꙁ' => 'ꙁ', 'Ꙃ' => 'ꙃ', 'Ꙅ' => 'ꙅ', 'Ꙇ' => 'ꙇ', 'Ꙉ' => 'ꙉ', 'Ꙋ' => 'ꙋ', 'Ꙍ' => 'ꙍ', 'Ꙏ' => 'ꙏ', 'Ꙑ' => 'ꙑ', 'Ꙓ' => 'ꙓ', 'Ꙕ' => 'ꙕ', 'Ꙗ' => 'ꙗ', 'Ꙙ' => 'ꙙ', 'Ꙛ' => 'ꙛ', 'Ꙝ' => 'ꙝ', 'Ꙟ' => 'ꙟ', 'Ꙡ' => 'ꙡ', 'Ꙣ' => 'ꙣ', 'Ꙥ' => 'ꙥ', 'Ꙧ' => 'ꙧ', 'Ꙩ' => 'ꙩ', 'Ꙫ' => 'ꙫ', 'Ꙭ' => 'ꙭ', 'Ꚁ' => 'ꚁ', 'Ꚃ' => 'ꚃ', 'Ꚅ' => 'ꚅ', 'Ꚇ' => 'ꚇ', 'Ꚉ' => 'ꚉ', 'Ꚋ' => 'ꚋ', 'Ꚍ' => 'ꚍ', 'Ꚏ' => 'ꚏ', 'Ꚑ' => 'ꚑ', 'Ꚓ' => 'ꚓ', 'Ꚕ' => 'ꚕ', 'Ꚗ' => 'ꚗ', 'Ꚙ' => 'ꚙ', 'Ꚛ' => 'ꚛ', 'Ꜣ' => 'ꜣ', 'Ꜥ' => 'ꜥ', 'Ꜧ' => 'ꜧ', 'Ꜩ' => 'ꜩ', 'Ꜫ' => 'ꜫ', 'Ꜭ' => 'ꜭ', 'Ꜯ' => 'ꜯ', 'Ꜳ' => 'ꜳ', 'Ꜵ' => 'ꜵ', 'Ꜷ' => 'ꜷ', 'Ꜹ' => 'ꜹ', 'Ꜻ' => 'ꜻ', 'Ꜽ' => 'ꜽ', 'Ꜿ' => 'ꜿ', 'Ꝁ' => 'ꝁ', 'Ꝃ' => 'ꝃ', 'Ꝅ' => 'ꝅ', 'Ꝇ' => 'ꝇ', 'Ꝉ' => 'ꝉ', 'Ꝋ' => 'ꝋ', 'Ꝍ' => 'ꝍ', 'Ꝏ' => 'ꝏ', 'Ꝑ' => 'ꝑ', 'Ꝓ' => 'ꝓ', 'Ꝕ' => 'ꝕ', 'Ꝗ' => 'ꝗ', 'Ꝙ' => 'ꝙ', 'Ꝛ' => 'ꝛ', 'Ꝝ' => 'ꝝ', 'Ꝟ' => 'ꝟ', 'Ꝡ' => 'ꝡ', 'Ꝣ' => 'ꝣ', 'Ꝥ' => 'ꝥ', 'Ꝧ' => 'ꝧ', 'Ꝩ' => 'ꝩ', 'Ꝫ' => 'ꝫ', 'Ꝭ' => 'ꝭ', 'Ꝯ' => 'ꝯ', 'Ꝺ' => 'ꝺ', 'Ꝼ' => 'ꝼ', 'Ᵹ' => 'ᵹ', 'Ꝿ' => 'ꝿ', 'Ꞁ' => 'ꞁ', 'Ꞃ' => 'ꞃ', 'Ꞅ' => 'ꞅ', 'Ꞇ' => 'ꞇ', 'Ꞌ' => 'ꞌ', 'Ɥ' => 'ɥ', 'Ꞑ' => 'ꞑ', 'Ꞓ' => 'ꞓ', 'Ꞗ' => 'ꞗ', 'Ꞙ' => 'ꞙ', 'Ꞛ' => 'ꞛ', 'Ꞝ' => 'ꞝ', 'Ꞟ' => 'ꞟ', 'Ꞡ' => 'ꞡ', 'Ꞣ' => 'ꞣ', 'Ꞥ' => 'ꞥ', 'Ꞧ' => 'ꞧ', 'Ꞩ' => 'ꞩ', 'Ɦ' => 'ɦ', 'Ɜ' => 'ɜ', 'Ɡ' => 'ɡ', 'Ɬ' => 'ɬ', 'Ɪ' => 'ɪ', 'Ʞ' => 'ʞ', 'Ʇ' => 'ʇ', 'Ʝ' => 'ʝ', 'Ꭓ' => 'ꭓ', 'Ꞵ' => 'ꞵ', 'Ꞷ' => 'ꞷ', 'Ꞹ' => 'ꞹ', 'Ꞻ' => 'ꞻ', 'Ꞽ' => 'ꞽ', 'Ꞿ' => 'ꞿ', 'Ꟃ' => 'ꟃ', 'Ꞔ' => 'ꞔ', 'Ʂ' => 'ʂ', 'Ᶎ' => 'ᶎ', 'Ꟈ' => 'ꟈ', 'Ꟊ' => 'ꟊ', 'Ꟶ' => 'ꟶ', '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' => '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', 'ij' => 'IJ', 'ĵ' => 'Ĵ', 'ķ' => 'Ķ', 'ĺ' => 'Ĺ', 'ļ' => 'Ļ', 'ľ' => 'Ľ', 'ŀ' => 'Ŀ', 'ł' => 'Ł', 'ń' => 'Ń', 'ņ' => 'Ņ', 'ň' => 'Ň', 'ŋ' => 'Ŋ', 'ō' => 'Ō', 'ŏ' => 'Ŏ', 'ő' => 'Ő', 'œ' => 'Œ', 'ŕ' => 'Ŕ', 'ŗ' => 'Ŗ', 'ř' => 'Ř', 'ś' => 'Ś', 'ŝ' => 'Ŝ', 'ş' => 'Ş', 'š' => 'Š', 'ţ' => 'Ţ', 'ť' => 'Ť', 'ŧ' => 'Ŧ', 'ũ' => 'Ũ', 'ū' => 'Ū', 'ŭ' => 'Ŭ', 'ů' => 'Ů', 'ű' => 'Ű', 'ų' => 'Ų', 'ŵ' => 'Ŵ', 'ŷ' => 'Ŷ', 'ź' => 'Ź', 'ż' => 'Ż', 'ž' => 'Ž', 'ſ' => 'S', 'ƀ' => 'Ƀ', 'ƃ' => 'Ƃ', 'ƅ' => 'Ƅ', 'ƈ' => 'Ƈ', 'ƌ' => 'Ƌ', 'ƒ' => 'Ƒ', 'ƕ' => 'Ƕ', 'ƙ' => 'Ƙ', 'ƚ' => 'Ƚ', 'ƞ' => 'Ƞ', 'ơ' => 'Ơ', 'ƣ' => 'Ƣ', 'ƥ' => 'Ƥ', 'ƨ' => 'Ƨ', 'ƭ' => 'Ƭ', 'ư' => 'Ư', 'ƴ' => 'Ƴ', 'ƶ' => 'Ƶ', 'ƹ' => 'Ƹ', 'ƽ' => 'Ƽ', 'ƿ' => 'Ƿ', 'Dž' => 'DŽ', 'dž' => 'DŽ', 'Lj' => 'LJ', 'lj' => 'LJ', 'Nj' => 'NJ', 'nj' => 'NJ', 'ǎ' => 'Ǎ', 'ǐ' => 'Ǐ', 'ǒ' => 'Ǒ', 'ǔ' => 'Ǔ', 'ǖ' => 'Ǖ', 'ǘ' => 'Ǘ', 'ǚ' => 'Ǚ', 'ǜ' => 'Ǜ', 'ǝ' => 'Ǝ', 'ǟ' => 'Ǟ', 'ǡ' => 'Ǡ', 'ǣ' => 'Ǣ', 'ǥ' => 'Ǥ', 'ǧ' => 'Ǧ', 'ǩ' => 'Ǩ', 'ǫ' => 'Ǫ', 'ǭ' => 'Ǭ', 'ǯ' => 'Ǯ', 'Dz' => 'DZ', 'dz' => 'DZ', 'ǵ' => 'Ǵ', 'ǹ' => 'Ǹ', 'ǻ' => 'Ǻ', 'ǽ' => 'Ǽ', 'ǿ' => 'Ǿ', 'ȁ' => 'Ȁ', 'ȃ' => 'Ȃ', 'ȅ' => 'Ȅ', 'ȇ' => 'Ȇ', 'ȉ' => 'Ȉ', 'ȋ' => 'Ȋ', 'ȍ' => 'Ȍ', 'ȏ' => 'Ȏ', 'ȑ' => 'Ȑ', 'ȓ' => 'Ȓ', 'ȕ' => 'Ȕ', 'ȗ' => 'Ȗ', 'ș' => 'Ș', 'ț' => 'Ț', 'ȝ' => 'Ȝ', 'ȟ' => 'Ȟ', 'ȣ' => 'Ȣ', 'ȥ' => 'Ȥ', 'ȧ' => 'Ȧ', 'ȩ' => 'Ȩ', 'ȫ' => 'Ȫ', 'ȭ' => 'Ȭ', 'ȯ' => 'Ȯ', 'ȱ' => 'Ȱ', 'ȳ' => 'Ȳ', 'ȼ' => 'Ȼ', 'ȿ' => 'Ȿ', 'ɀ' => 'Ɀ', 'ɂ' => 'Ɂ', 'ɇ' => 'Ɇ', 'ɉ' => 'Ɉ', 'ɋ' => 'Ɋ', 'ɍ' => 'Ɍ', 'ɏ' => 'Ɏ', 'ɐ' => 'Ɐ', 'ɑ' => 'Ɑ', 'ɒ' => 'Ɒ', 'ɓ' => 'Ɓ', 'ɔ' => 'Ɔ', 'ɖ' => 'Ɖ', 'ɗ' => 'Ɗ', 'ə' => 'Ə', 'ɛ' => 'Ɛ', 'ɜ' => 'Ɜ', 'ɠ' => 'Ɠ', 'ɡ' => 'Ɡ', 'ɣ' => 'Ɣ', 'ɥ' => 'Ɥ', 'ɦ' => 'Ɦ', 'ɨ' => 'Ɨ', 'ɩ' => 'Ɩ', 'ɪ' => 'Ɪ', 'ɫ' => 'Ɫ', 'ɬ' => 'Ɬ', 'ɯ' => 'Ɯ', 'ɱ' => 'Ɱ', 'ɲ' => 'Ɲ', 'ɵ' => 'Ɵ', 'ɽ' => 'Ɽ', 'ʀ' => 'Ʀ', 'ʂ' => 'Ʂ', 'ʃ' => 'Ʃ', 'ʇ' => 'Ʇ', 'ʈ' => 'Ʈ', 'ʉ' => 'Ʉ', 'ʊ' => 'Ʊ', 'ʋ' => 'Ʋ', 'ʌ' => 'Ʌ', 'ʒ' => 'Ʒ', 'ʝ' => 'Ʝ', 'ʞ' => 'Ʞ', 'ͅ' => 'Ι', 'ͱ' => 'Ͱ', 'ͳ' => 'Ͳ', 'ͷ' => 'Ͷ', 'ͻ' => 'Ͻ', 'ͼ' => 'Ͼ', 'ͽ' => 'Ͽ', 'ά' => 'Ά', 'έ' => 'Έ', 'ή' => 'Ή', 'ί' => 'Ί', 'α' => 'Α', 'β' => 'Β', 'γ' => 'Γ', 'δ' => 'Δ', 'ε' => 'Ε', 'ζ' => 'Ζ', 'η' => 'Η', 'θ' => 'Θ', 'ι' => 'Ι', 'κ' => 'Κ', 'λ' => 'Λ', 'μ' => 'Μ', 'ν' => 'Ν', 'ξ' => 'Ξ', 'ο' => 'Ο', 'π' => 'Π', 'ρ' => 'Ρ', 'ς' => 'Σ', 'σ' => 'Σ', 'τ' => 'Τ', 'υ' => 'Υ', 'φ' => 'Φ', 'χ' => 'Χ', 'ψ' => 'Ψ', 'ω' => 'Ω', 'ϊ' => 'Ϊ', 'ϋ' => 'Ϋ', 'ό' => 'Ό', 'ύ' => 'Ύ', 'ώ' => 'Ώ', 'ϐ' => 'Β', 'ϑ' => 'Θ', 'ϕ' => 'Φ', 'ϖ' => 'Π', 'ϗ' => 'Ϗ', 'ϙ' => 'Ϙ', 'ϛ' => 'Ϛ', 'ϝ' => 'Ϝ', 'ϟ' => 'Ϟ', 'ϡ' => 'Ϡ', 'ϣ' => 'Ϣ', 'ϥ' => 'Ϥ', 'ϧ' => 'Ϧ', 'ϩ' => 'Ϩ', 'ϫ' => 'Ϫ', 'ϭ' => 'Ϭ', 'ϯ' => 'Ϯ', 'ϰ' => 'Κ', 'ϱ' => 'Ρ', 'ϲ' => 'Ϲ', 'ϳ' => 'Ϳ', 'ϵ' => 'Ε', 'ϸ' => 'Ϸ', 'ϻ' => 'Ϻ', 'а' => 'А', 'б' => 'Б', 'в' => 'В', 'г' => 'Г', 'д' => 'Д', 'е' => 'Е', 'ж' => 'Ж', 'з' => 'З', 'и' => 'И', 'й' => 'Й', 'к' => 'К', 'л' => 'Л', 'м' => 'М', 'н' => 'Н', 'о' => 'О', 'п' => 'П', 'р' => 'Р', 'с' => 'С', 'т' => 'Т', 'у' => 'У', 'ф' => 'Ф', 'х' => 'Х', 'ц' => 'Ц', 'ч' => 'Ч', 'ш' => 'Ш', 'щ' => 'Щ', 'ъ' => 'Ъ', 'ы' => 'Ы', 'ь' => 'Ь', 'э' => 'Э', 'ю' => 'Ю', 'я' => 'Я', 'ѐ' => 'Ѐ', 'ё' => 'Ё', 'ђ' => 'Ђ', 'ѓ' => 'Ѓ', 'є' => 'Є', 'ѕ' => 'Ѕ', 'і' => 'І', 'ї' => 'Ї', 'ј' => 'Ј', 'љ' => 'Љ', 'њ' => 'Њ', 'ћ' => 'Ћ', 'ќ' => 'Ќ', 'ѝ' => 'Ѝ', 'ў' => 'Ў', 'џ' => 'Џ', 'ѡ' => 'Ѡ', 'ѣ' => 'Ѣ', 'ѥ' => 'Ѥ', 'ѧ' => 'Ѧ', 'ѩ' => 'Ѩ', 'ѫ' => 'Ѫ', 'ѭ' => 'Ѭ', 'ѯ' => 'Ѯ', 'ѱ' => 'Ѱ', 'ѳ' => 'Ѳ', 'ѵ' => 'Ѵ', 'ѷ' => 'Ѷ', 'ѹ' => 'Ѹ', 'ѻ' => 'Ѻ', 'ѽ' => 'Ѽ', 'ѿ' => 'Ѿ', 'ҁ' => 'Ҁ', 'ҋ' => 'Ҋ', 'ҍ' => 'Ҍ', 'ҏ' => 'Ҏ', 'ґ' => 'Ґ', 'ғ' => 'Ғ', 'ҕ' => 'Ҕ', 'җ' => 'Җ', 'ҙ' => 'Ҙ', 'қ' => 'Қ', 'ҝ' => 'Ҝ', 'ҟ' => 'Ҟ', 'ҡ' => 'Ҡ', 'ң' => 'Ң', 'ҥ' => 'Ҥ', 'ҧ' => 'Ҧ', 'ҩ' => 'Ҩ', 'ҫ' => 'Ҫ', 'ҭ' => 'Ҭ', 'ү' => 'Ү', 'ұ' => 'Ұ', 'ҳ' => 'Ҳ', 'ҵ' => 'Ҵ', 'ҷ' => 'Ҷ', 'ҹ' => 'Ҹ', 'һ' => 'Һ', 'ҽ' => 'Ҽ', 'ҿ' => 'Ҿ', 'ӂ' => 'Ӂ', 'ӄ' => 'Ӄ', 'ӆ' => 'Ӆ', 'ӈ' => 'Ӈ', 'ӊ' => 'Ӊ', 'ӌ' => 'Ӌ', 'ӎ' => 'Ӎ', 'ӏ' => 'Ӏ', 'ӑ' => 'Ӑ', 'ӓ' => 'Ӓ', 'ӕ' => 'Ӕ', 'ӗ' => 'Ӗ', 'ә' => 'Ә', 'ӛ' => 'Ӛ', 'ӝ' => 'Ӝ', 'ӟ' => 'Ӟ', 'ӡ' => 'Ӡ', 'ӣ' => 'Ӣ', 'ӥ' => 'Ӥ', 'ӧ' => 'Ӧ', 'ө' => 'Ө', 'ӫ' => 'Ӫ', 'ӭ' => 'Ӭ', 'ӯ' => 'Ӯ', 'ӱ' => 'Ӱ', 'ӳ' => 'Ӳ', 'ӵ' => 'Ӵ', 'ӷ' => 'Ӷ', 'ӹ' => 'Ӹ', 'ӻ' => 'Ӻ', 'ӽ' => 'Ӽ', 'ӿ' => 'Ӿ', 'ԁ' => 'Ԁ', 'ԃ' => 'Ԃ', 'ԅ' => 'Ԅ', 'ԇ' => 'Ԇ', 'ԉ' => 'Ԉ', 'ԋ' => 'Ԋ', 'ԍ' => 'Ԍ', 'ԏ' => 'Ԏ', 'ԑ' => 'Ԑ', 'ԓ' => 'Ԓ', 'ԕ' => 'Ԕ', 'ԗ' => 'Ԗ', 'ԙ' => 'Ԙ', 'ԛ' => 'Ԛ', 'ԝ' => 'Ԝ', 'ԟ' => 'Ԟ', 'ԡ' => 'Ԡ', 'ԣ' => 'Ԣ', 'ԥ' => 'Ԥ', 'ԧ' => 'Ԧ', 'ԩ' => 'Ԩ', 'ԫ' => 'Ԫ', 'ԭ' => 'Ԭ', 'ԯ' => 'Ԯ', 'ա' => 'Ա', 'բ' => 'Բ', 'գ' => 'Գ', 'դ' => 'Դ', 'ե' => 'Ե', 'զ' => 'Զ', 'է' => 'Է', 'ը' => 'Ը', 'թ' => 'Թ', 'ժ' => 'Ժ', 'ի' => 'Ի', 'լ' => 'Լ', 'խ' => 'Խ', 'ծ' => 'Ծ', 'կ' => 'Կ', 'հ' => 'Հ', 'ձ' => 'Ձ', 'ղ' => 'Ղ', 'ճ' => 'Ճ', 'մ' => 'Մ', 'յ' => 'Յ', 'ն' => 'Ն', 'շ' => 'Շ', 'ո' => 'Ո', 'չ' => 'Չ', 'պ' => 'Պ', 'ջ' => 'Ջ', 'ռ' => 'Ռ', 'ս' => 'Ս', 'վ' => 'Վ', 'տ' => 'Տ', 'ր' => 'Ր', 'ց' => 'Ց', 'ւ' => 'Ւ', 'փ' => 'Փ', 'ք' => 'Ք', 'օ' => 'Օ', 'ֆ' => 'Ֆ', 'ა' => 'Ა', 'ბ' => 'Ბ', 'გ' => 'Გ', 'დ' => 'Დ', 'ე' => 'Ე', 'ვ' => 'Ვ', 'ზ' => 'Ზ', 'თ' => 'Თ', 'ი' => 'Ი', 'კ' => 'Კ', 'ლ' => 'Ლ', 'მ' => 'Მ', 'ნ' => 'Ნ', 'ო' => 'Ო', 'პ' => 'Პ', 'ჟ' => 'Ჟ', 'რ' => 'Რ', 'ს' => 'Ს', 'ტ' => 'Ტ', 'უ' => 'Უ', 'ფ' => 'Ფ', 'ქ' => 'Ქ', 'ღ' => 'Ღ', 'ყ' => 'Ყ', 'შ' => 'Შ', 'ჩ' => 'Ჩ', 'ც' => 'Ც', 'ძ' => 'Ძ', 'წ' => 'Წ', 'ჭ' => 'Ჭ', 'ხ' => 'Ხ', 'ჯ' => 'Ჯ', 'ჰ' => 'Ჰ', 'ჱ' => 'Ჱ', 'ჲ' => 'Ჲ', 'ჳ' => 'Ჳ', 'ჴ' => 'Ჴ', 'ჵ' => 'Ჵ', 'ჶ' => 'Ჶ', 'ჷ' => 'Ჷ', 'ჸ' => 'Ჸ', 'ჹ' => 'Ჹ', 'ჺ' => 'Ჺ', 'ჽ' => 'Ჽ', 'ჾ' => 'Ჾ', 'ჿ' => 'Ჿ', 'ᏸ' => 'Ᏸ', 'ᏹ' => 'Ᏹ', 'ᏺ' => 'Ᏺ', 'ᏻ' => 'Ᏻ', 'ᏼ' => 'Ᏼ', 'ᏽ' => 'Ᏽ', 'ᲀ' => 'В', 'ᲁ' => 'Д', 'ᲂ' => 'О', 'ᲃ' => 'С', 'ᲄ' => 'Т', 'ᲅ' => 'Т', 'ᲆ' => 'Ъ', 'ᲇ' => 'Ѣ', 'ᲈ' => 'Ꙋ', 'ᵹ' => 'Ᵹ', 'ᵽ' => 'Ᵽ', 'ᶎ' => 'Ᶎ', 'ḁ' => 'Ḁ', 'ḃ' => 'Ḃ', 'ḅ' => 'Ḅ', 'ḇ' => 'Ḇ', 'ḉ' => 'Ḉ', 'ḋ' => 'Ḋ', 'ḍ' => 'Ḍ', 'ḏ' => 'Ḏ', 'ḑ' => 'Ḑ', 'ḓ' => 'Ḓ', 'ḕ' => 'Ḕ', 'ḗ' => 'Ḗ', 'ḙ' => 'Ḙ', 'ḛ' => 'Ḛ', 'ḝ' => 'Ḝ', 'ḟ' => 'Ḟ', 'ḡ' => 'Ḡ', 'ḣ' => 'Ḣ', 'ḥ' => 'Ḥ', 'ḧ' => 'Ḧ', 'ḩ' => 'Ḩ', 'ḫ' => 'Ḫ', 'ḭ' => 'Ḭ', 'ḯ' => 'Ḯ', 'ḱ' => 'Ḱ', 'ḳ' => 'Ḳ', 'ḵ' => 'Ḵ', 'ḷ' => 'Ḷ', 'ḹ' => 'Ḹ', 'ḻ' => 'Ḻ', 'ḽ' => 'Ḽ', 'ḿ' => 'Ḿ', 'ṁ' => 'Ṁ', 'ṃ' => 'Ṃ', 'ṅ' => 'Ṅ', 'ṇ' => 'Ṇ', 'ṉ' => 'Ṉ', 'ṋ' => 'Ṋ', 'ṍ' => 'Ṍ', 'ṏ' => 'Ṏ', 'ṑ' => 'Ṑ', 'ṓ' => 'Ṓ', 'ṕ' => 'Ṕ', 'ṗ' => 'Ṗ', 'ṙ' => 'Ṙ', 'ṛ' => 'Ṛ', 'ṝ' => 'Ṝ', 'ṟ' => 'Ṟ', 'ṡ' => 'Ṡ', 'ṣ' => 'Ṣ', 'ṥ' => 'Ṥ', 'ṧ' => 'Ṧ', 'ṩ' => 'Ṩ', 'ṫ' => 'Ṫ', 'ṭ' => 'Ṭ', 'ṯ' => 'Ṯ', 'ṱ' => 'Ṱ', 'ṳ' => 'Ṳ', 'ṵ' => 'Ṵ', 'ṷ' => 'Ṷ', 'ṹ' => 'Ṹ', 'ṻ' => 'Ṻ', 'ṽ' => 'Ṽ', 'ṿ' => 'Ṿ', 'ẁ' => 'Ẁ', 'ẃ' => 'Ẃ', 'ẅ' => 'Ẅ', 'ẇ' => 'Ẇ', 'ẉ' => 'Ẉ', 'ẋ' => 'Ẋ', 'ẍ' => 'Ẍ', 'ẏ' => 'Ẏ', 'ẑ' => 'Ẑ', 'ẓ' => 'Ẓ', 'ẕ' => 'Ẕ', 'ẛ' => 'Ṡ', 'ạ' => 'Ạ', 'ả' => 'Ả', 'ấ' => 'Ấ', 'ầ' => 'Ầ', 'ẩ' => 'Ẩ', 'ẫ' => 'Ẫ', 'ậ' => 'Ậ', 'ắ' => 'Ắ', 'ằ' => 'Ằ', 'ẳ' => 'Ẳ', 'ẵ' => 'Ẵ', 'ặ' => 'Ặ', 'ẹ' => 'Ẹ', 'ẻ' => 'Ẻ', 'ẽ' => 'Ẽ', 'ế' => 'Ế', 'ề' => 'Ề', 'ể' => 'Ể', 'ễ' => 'Ễ', 'ệ' => 'Ệ', 'ỉ' => 'Ỉ', 'ị' => 'Ị', 'ọ' => 'Ọ', 'ỏ' => 'Ỏ', 'ố' => 'Ố', 'ồ' => 'Ồ', 'ổ' => 'Ổ', 'ỗ' => 'Ỗ', 'ộ' => 'Ộ', 'ớ' => 'Ớ', 'ờ' => 'Ờ', 'ở' => 'Ở', 'ỡ' => 'Ỡ', 'ợ' => 'Ợ', 'ụ' => 'Ụ', 'ủ' => 'Ủ', 'ứ' => 'Ứ', 'ừ' => 'Ừ', 'ử' => 'Ử', 'ữ' => 'Ữ', 'ự' => 'Ự', 'ỳ' => 'Ỳ', 'ỵ' => 'Ỵ', 'ỷ' => 'Ỷ', 'ỹ' => 'Ỹ', 'ỻ' => 'Ỻ', 'ỽ' => 'Ỽ', 'ỿ' => 'Ỿ', 'ἀ' => 'Ἀ', 'ἁ' => 'Ἁ', 'ἂ' => 'Ἂ', 'ἃ' => 'Ἃ', 'ἄ' => 'Ἄ', 'ἅ' => 'Ἅ', 'ἆ' => 'Ἆ', 'ἇ' => 'Ἇ', 'ἐ' => 'Ἐ', 'ἑ' => 'Ἑ', 'ἒ' => 'Ἒ', 'ἓ' => 'Ἓ', 'ἔ' => 'Ἔ', 'ἕ' => 'Ἕ', 'ἠ' => 'Ἠ', 'ἡ' => 'Ἡ', 'ἢ' => 'Ἢ', 'ἣ' => 'Ἣ', 'ἤ' => 'Ἤ', 'ἥ' => 'Ἥ', 'ἦ' => 'Ἦ', 'ἧ' => 'Ἧ', 'ἰ' => 'Ἰ', 'ἱ' => 'Ἱ', 'ἲ' => 'Ἲ', 'ἳ' => 'Ἳ', 'ἴ' => 'Ἴ', 'ἵ' => 'Ἵ', 'ἶ' => 'Ἶ', 'ἷ' => 'Ἷ', 'ὀ' => 'Ὀ', 'ὁ' => 'Ὁ', 'ὂ' => 'Ὂ', 'ὃ' => 'Ὃ', 'ὄ' => 'Ὄ', 'ὅ' => 'Ὅ', 'ὑ' => 'Ὑ', 'ὓ' => 'Ὓ', 'ὕ' => 'Ὕ', 'ὗ' => 'Ὗ', 'ὠ' => 'Ὠ', 'ὡ' => 'Ὡ', 'ὢ' => 'Ὢ', 'ὣ' => 'Ὣ', 'ὤ' => 'Ὤ', 'ὥ' => 'Ὥ', 'ὦ' => 'Ὦ', 'ὧ' => 'Ὧ', 'ὰ' => 'Ὰ', 'ά' => 'Ά', 'ὲ' => 'Ὲ', 'έ' => 'Έ', 'ὴ' => 'Ὴ', 'ή' => 'Ή', 'ὶ' => 'Ὶ', 'ί' => 'Ί', 'ὸ' => 'Ὸ', 'ό' => 'Ό', 'ὺ' => 'Ὺ', 'ύ' => 'Ύ', 'ὼ' => 'Ὼ', 'ώ' => 'Ώ', 'ᾀ' => 'ἈΙ', 'ᾁ' => 'ἉΙ', 'ᾂ' => 'ἊΙ', 'ᾃ' => 'ἋΙ', 'ᾄ' => 'ἌΙ', 'ᾅ' => 'ἍΙ', 'ᾆ' => 'ἎΙ', 'ᾇ' => 'ἏΙ', 'ᾐ' => 'ἨΙ', 'ᾑ' => 'ἩΙ', 'ᾒ' => 'ἪΙ', 'ᾓ' => 'ἫΙ', 'ᾔ' => 'ἬΙ', 'ᾕ' => 'ἭΙ', 'ᾖ' => 'ἮΙ', 'ᾗ' => 'ἯΙ', 'ᾠ' => 'ὨΙ', 'ᾡ' => 'ὩΙ', 'ᾢ' => 'ὪΙ', 'ᾣ' => 'ὫΙ', 'ᾤ' => 'ὬΙ', 'ᾥ' => 'ὭΙ', 'ᾦ' => 'ὮΙ', 'ᾧ' => 'ὯΙ', 'ᾰ' => 'Ᾰ', 'ᾱ' => 'Ᾱ', 'ᾳ' => 'ΑΙ', 'ι' => 'Ι', 'ῃ' => 'ΗΙ', 'ῐ' => 'Ῐ', 'ῑ' => 'Ῑ', 'ῠ' => 'Ῠ', 'ῡ' => 'Ῡ', 'ῥ' => 'Ῥ', 'ῳ' => 'ΩΙ', 'ⅎ' => 'Ⅎ', 'ⅰ' => 'Ⅰ', 'ⅱ' => 'Ⅱ', 'ⅲ' => 'Ⅲ', 'ⅳ' => 'Ⅳ', 'ⅴ' => 'Ⅴ', 'ⅵ' => 'Ⅵ', 'ⅶ' => 'Ⅶ', 'ⅷ' => 'Ⅷ', 'ⅸ' => 'Ⅸ', 'ⅹ' => 'Ⅹ', 'ⅺ' => 'Ⅺ', 'ⅻ' => 'Ⅻ', 'ⅼ' => 'Ⅼ', 'ⅽ' => 'Ⅽ', 'ⅾ' => 'Ⅾ', 'ⅿ' => 'Ⅿ', 'ↄ' => 'Ↄ', 'ⓐ' => 'Ⓐ', 'ⓑ' => 'Ⓑ', 'ⓒ' => 'Ⓒ', 'ⓓ' => 'Ⓓ', 'ⓔ' => 'Ⓔ', 'ⓕ' => 'Ⓕ', 'ⓖ' => 'Ⓖ', 'ⓗ' => 'Ⓗ', 'ⓘ' => 'Ⓘ', 'ⓙ' => 'Ⓙ', 'ⓚ' => 'Ⓚ', 'ⓛ' => 'Ⓛ', 'ⓜ' => 'Ⓜ', 'ⓝ' => 'Ⓝ', 'ⓞ' => 'Ⓞ', 'ⓟ' => 'Ⓟ', 'ⓠ' => 'Ⓠ', 'ⓡ' => 'Ⓡ', 'ⓢ' => 'Ⓢ', 'ⓣ' => 'Ⓣ', 'ⓤ' => 'Ⓤ', 'ⓥ' => 'Ⓥ', 'ⓦ' => 'Ⓦ', 'ⓧ' => 'Ⓧ', 'ⓨ' => 'Ⓨ', 'ⓩ' => 'Ⓩ', 'ⰰ' => 'Ⰰ', 'ⰱ' => 'Ⰱ', 'ⰲ' => 'Ⰲ', 'ⰳ' => 'Ⰳ', 'ⰴ' => 'Ⰴ', 'ⰵ' => 'Ⰵ', 'ⰶ' => 'Ⰶ', 'ⰷ' => 'Ⰷ', 'ⰸ' => 'Ⰸ', 'ⰹ' => 'Ⰹ', 'ⰺ' => 'Ⰺ', 'ⰻ' => 'Ⰻ', 'ⰼ' => 'Ⰼ', 'ⰽ' => 'Ⰽ', 'ⰾ' => 'Ⰾ', 'ⰿ' => 'Ⰿ', 'ⱀ' => 'Ⱀ', 'ⱁ' => 'Ⱁ', 'ⱂ' => 'Ⱂ', 'ⱃ' => 'Ⱃ', 'ⱄ' => 'Ⱄ', 'ⱅ' => 'Ⱅ', 'ⱆ' => 'Ⱆ', 'ⱇ' => 'Ⱇ', 'ⱈ' => 'Ⱈ', 'ⱉ' => 'Ⱉ', 'ⱊ' => 'Ⱊ', 'ⱋ' => 'Ⱋ', 'ⱌ' => 'Ⱌ', 'ⱍ' => 'Ⱍ', 'ⱎ' => 'Ⱎ', 'ⱏ' => 'Ⱏ', 'ⱐ' => 'Ⱐ', 'ⱑ' => 'Ⱑ', 'ⱒ' => 'Ⱒ', 'ⱓ' => 'Ⱓ', 'ⱔ' => 'Ⱔ', 'ⱕ' => 'Ⱕ', 'ⱖ' => 'Ⱖ', 'ⱗ' => 'Ⱗ', 'ⱘ' => 'Ⱘ', 'ⱙ' => 'Ⱙ', 'ⱚ' => 'Ⱚ', 'ⱛ' => 'Ⱛ', 'ⱜ' => 'Ⱜ', 'ⱝ' => 'Ⱝ', 'ⱞ' => 'Ⱞ', 'ⱡ' => 'Ⱡ', 'ⱥ' => 'Ⱥ', 'ⱦ' => 'Ⱦ', 'ⱨ' => 'Ⱨ', 'ⱪ' => 'Ⱪ', 'ⱬ' => 'Ⱬ', 'ⱳ' => 'Ⱳ', 'ⱶ' => 'Ⱶ', 'ⲁ' => 'Ⲁ', 'ⲃ' => 'Ⲃ', 'ⲅ' => 'Ⲅ', 'ⲇ' => 'Ⲇ', 'ⲉ' => 'Ⲉ', 'ⲋ' => 'Ⲋ', 'ⲍ' => 'Ⲍ', 'ⲏ' => 'Ⲏ', 'ⲑ' => 'Ⲑ', 'ⲓ' => 'Ⲓ', 'ⲕ' => 'Ⲕ', 'ⲗ' => 'Ⲗ', 'ⲙ' => 'Ⲙ', 'ⲛ' => 'Ⲛ', 'ⲝ' => 'Ⲝ', 'ⲟ' => 'Ⲟ', 'ⲡ' => 'Ⲡ', 'ⲣ' => 'Ⲣ', 'ⲥ' => 'Ⲥ', 'ⲧ' => 'Ⲧ', 'ⲩ' => 'Ⲩ', 'ⲫ' => 'Ⲫ', 'ⲭ' => 'Ⲭ', 'ⲯ' => 'Ⲯ', 'ⲱ' => 'Ⲱ', 'ⲳ' => 'Ⲳ', 'ⲵ' => 'Ⲵ', 'ⲷ' => 'Ⲷ', 'ⲹ' => 'Ⲹ', 'ⲻ' => 'Ⲻ', 'ⲽ' => 'Ⲽ', 'ⲿ' => 'Ⲿ', 'ⳁ' => 'Ⳁ', 'ⳃ' => 'Ⳃ', 'ⳅ' => 'Ⳅ', 'ⳇ' => 'Ⳇ', 'ⳉ' => 'Ⳉ', 'ⳋ' => 'Ⳋ', 'ⳍ' => 'Ⳍ', 'ⳏ' => 'Ⳏ', 'ⳑ' => 'Ⳑ', 'ⳓ' => 'Ⳓ', 'ⳕ' => 'Ⳕ', 'ⳗ' => 'Ⳗ', 'ⳙ' => 'Ⳙ', 'ⳛ' => 'Ⳛ', 'ⳝ' => 'Ⳝ', 'ⳟ' => 'Ⳟ', 'ⳡ' => 'Ⳡ', 'ⳣ' => 'Ⳣ', 'ⳬ' => 'Ⳬ', 'ⳮ' => 'Ⳮ', 'ⳳ' => 'Ⳳ', 'ⴀ' => 'Ⴀ', 'ⴁ' => 'Ⴁ', 'ⴂ' => 'Ⴂ', 'ⴃ' => 'Ⴃ', 'ⴄ' => 'Ⴄ', 'ⴅ' => 'Ⴅ', 'ⴆ' => 'Ⴆ', 'ⴇ' => 'Ⴇ', 'ⴈ' => 'Ⴈ', 'ⴉ' => 'Ⴉ', 'ⴊ' => 'Ⴊ', 'ⴋ' => 'Ⴋ', 'ⴌ' => 'Ⴌ', 'ⴍ' => 'Ⴍ', 'ⴎ' => 'Ⴎ', 'ⴏ' => 'Ⴏ', 'ⴐ' => 'Ⴐ', 'ⴑ' => 'Ⴑ', 'ⴒ' => 'Ⴒ', 'ⴓ' => 'Ⴓ', 'ⴔ' => 'Ⴔ', 'ⴕ' => 'Ⴕ', 'ⴖ' => 'Ⴖ', 'ⴗ' => 'Ⴗ', 'ⴘ' => 'Ⴘ', 'ⴙ' => 'Ⴙ', 'ⴚ' => 'Ⴚ', 'ⴛ' => 'Ⴛ', 'ⴜ' => 'Ⴜ', 'ⴝ' => 'Ⴝ', 'ⴞ' => 'Ⴞ', 'ⴟ' => 'Ⴟ', 'ⴠ' => 'Ⴠ', 'ⴡ' => 'Ⴡ', 'ⴢ' => 'Ⴢ', 'ⴣ' => 'Ⴣ', 'ⴤ' => 'Ⴤ', 'ⴥ' => 'Ⴥ', 'ⴧ' => 'Ⴧ', 'ⴭ' => 'Ⴭ', 'ꙁ' => 'Ꙁ', 'ꙃ' => 'Ꙃ', 'ꙅ' => 'Ꙅ', 'ꙇ' => 'Ꙇ', 'ꙉ' => 'Ꙉ', 'ꙋ' => 'Ꙋ', 'ꙍ' => 'Ꙍ', 'ꙏ' => 'Ꙏ', 'ꙑ' => 'Ꙑ', 'ꙓ' => 'Ꙓ', 'ꙕ' => 'Ꙕ', 'ꙗ' => 'Ꙗ', 'ꙙ' => 'Ꙙ', 'ꙛ' => 'Ꙛ', 'ꙝ' => 'Ꙝ', 'ꙟ' => 'Ꙟ', 'ꙡ' => 'Ꙡ', 'ꙣ' => 'Ꙣ', 'ꙥ' => 'Ꙥ', 'ꙧ' => 'Ꙧ', 'ꙩ' => 'Ꙩ', 'ꙫ' => 'Ꙫ', 'ꙭ' => 'Ꙭ', 'ꚁ' => 'Ꚁ', 'ꚃ' => 'Ꚃ', 'ꚅ' => 'Ꚅ', 'ꚇ' => 'Ꚇ', 'ꚉ' => 'Ꚉ', 'ꚋ' => 'Ꚋ', 'ꚍ' => 'Ꚍ', 'ꚏ' => 'Ꚏ', 'ꚑ' => 'Ꚑ', 'ꚓ' => 'Ꚓ', 'ꚕ' => 'Ꚕ', 'ꚗ' => 'Ꚗ', 'ꚙ' => 'Ꚙ', 'ꚛ' => 'Ꚛ', 'ꜣ' => 'Ꜣ', 'ꜥ' => 'Ꜥ', 'ꜧ' => 'Ꜧ', 'ꜩ' => 'Ꜩ', 'ꜫ' => 'Ꜫ', 'ꜭ' => 'Ꜭ', 'ꜯ' => 'Ꜯ', 'ꜳ' => 'Ꜳ', 'ꜵ' => 'Ꜵ', 'ꜷ' => 'Ꜷ', 'ꜹ' => 'Ꜹ', 'ꜻ' => 'Ꜻ', 'ꜽ' => 'Ꜽ', 'ꜿ' => 'Ꜿ', 'ꝁ' => 'Ꝁ', 'ꝃ' => 'Ꝃ', 'ꝅ' => 'Ꝅ', 'ꝇ' => 'Ꝇ', 'ꝉ' => 'Ꝉ', 'ꝋ' => 'Ꝋ', 'ꝍ' => 'Ꝍ', 'ꝏ' => 'Ꝏ', 'ꝑ' => 'Ꝑ', 'ꝓ' => 'Ꝓ', 'ꝕ' => 'Ꝕ', 'ꝗ' => 'Ꝗ', 'ꝙ' => 'Ꝙ', 'ꝛ' => 'Ꝛ', 'ꝝ' => 'Ꝝ', 'ꝟ' => 'Ꝟ', 'ꝡ' => 'Ꝡ', 'ꝣ' => 'Ꝣ', 'ꝥ' => 'Ꝥ', 'ꝧ' => 'Ꝧ', 'ꝩ' => 'Ꝩ', 'ꝫ' => 'Ꝫ', 'ꝭ' => 'Ꝭ', 'ꝯ' => 'Ꝯ', 'ꝺ' => 'Ꝺ', 'ꝼ' => 'Ꝼ', 'ꝿ' => 'Ꝿ', 'ꞁ' => 'Ꞁ', 'ꞃ' => 'Ꞃ', 'ꞅ' => 'Ꞅ', 'ꞇ' => 'Ꞇ', 'ꞌ' => 'Ꞌ', 'ꞑ' => 'Ꞑ', 'ꞓ' => 'Ꞓ', 'ꞔ' => 'Ꞔ', 'ꞗ' => 'Ꞗ', 'ꞙ' => 'Ꞙ', 'ꞛ' => 'Ꞛ', 'ꞝ' => 'Ꞝ', 'ꞟ' => 'Ꞟ', 'ꞡ' => 'Ꞡ', 'ꞣ' => 'Ꞣ', 'ꞥ' => 'Ꞥ', 'ꞧ' => 'Ꞧ', 'ꞩ' => 'Ꞩ', 'ꞵ' => 'Ꞵ', 'ꞷ' => 'Ꞷ', 'ꞹ' => 'Ꞹ', 'ꞻ' => 'Ꞻ', 'ꞽ' => 'Ꞽ', 'ꞿ' => 'Ꞿ', 'ꟃ' => 'Ꟃ', 'ꟈ' => 'Ꟈ', 'ꟊ' => 'Ꟊ', 'ꟶ' => 'Ꟶ', 'ꭓ' => 'Ꭓ', 'ꭰ' => 'Ꭰ', 'ꭱ' => 'Ꭱ', 'ꭲ' => 'Ꭲ', 'ꭳ' => 'Ꭳ', 'ꭴ' => 'Ꭴ', 'ꭵ' => 'Ꭵ', 'ꭶ' => 'Ꭶ', 'ꭷ' => 'Ꭷ', 'ꭸ' => 'Ꭸ', 'ꭹ' => 'Ꭹ', 'ꭺ' => 'Ꭺ', 'ꭻ' => 'Ꭻ', 'ꭼ' => 'Ꭼ', 'ꭽ' => 'Ꭽ', 'ꭾ' => 'Ꭾ', 'ꭿ' => 'Ꭿ', 'ꮀ' => 'Ꮀ', 'ꮁ' => 'Ꮁ', 'ꮂ' => 'Ꮂ', 'ꮃ' => 'Ꮃ', 'ꮄ' => 'Ꮄ', 'ꮅ' => 'Ꮅ', 'ꮆ' => 'Ꮆ', 'ꮇ' => 'Ꮇ', 'ꮈ' => 'Ꮈ', 'ꮉ' => 'Ꮉ', 'ꮊ' => 'Ꮊ', 'ꮋ' => 'Ꮋ', 'ꮌ' => 'Ꮌ', 'ꮍ' => 'Ꮍ', 'ꮎ' => 'Ꮎ', 'ꮏ' => 'Ꮏ', 'ꮐ' => 'Ꮐ', 'ꮑ' => 'Ꮑ', 'ꮒ' => 'Ꮒ', 'ꮓ' => 'Ꮓ', 'ꮔ' => 'Ꮔ', 'ꮕ' => 'Ꮕ', 'ꮖ' => 'Ꮖ', 'ꮗ' => 'Ꮗ', 'ꮘ' => 'Ꮘ', 'ꮙ' => 'Ꮙ', 'ꮚ' => 'Ꮚ', 'ꮛ' => 'Ꮛ', 'ꮜ' => 'Ꮜ', 'ꮝ' => 'Ꮝ', 'ꮞ' => 'Ꮞ', 'ꮟ' => 'Ꮟ', 'ꮠ' => 'Ꮠ', 'ꮡ' => 'Ꮡ', 'ꮢ' => 'Ꮢ', 'ꮣ' => 'Ꮣ', 'ꮤ' => 'Ꮤ', 'ꮥ' => 'Ꮥ', 'ꮦ' => 'Ꮦ', 'ꮧ' => 'Ꮧ', 'ꮨ' => 'Ꮨ', 'ꮩ' => 'Ꮩ', 'ꮪ' => 'Ꮪ', 'ꮫ' => 'Ꮫ', 'ꮬ' => 'Ꮬ', 'ꮭ' => 'Ꮭ', 'ꮮ' => 'Ꮮ', 'ꮯ' => 'Ꮯ', 'ꮰ' => 'Ꮰ', 'ꮱ' => 'Ꮱ', 'ꮲ' => 'Ꮲ', 'ꮳ' => 'Ꮳ', 'ꮴ' => 'Ꮴ', 'ꮵ' => 'Ꮵ', 'ꮶ' => 'Ꮶ', 'ꮷ' => 'Ꮷ', 'ꮸ' => 'Ꮸ', 'ꮹ' => 'Ꮹ', 'ꮺ' => 'Ꮺ', 'ꮻ' => 'Ꮻ', 'ꮼ' => 'Ꮼ', 'ꮽ' => 'Ꮽ', 'ꮾ' => 'Ꮾ', 'ꮿ' => 'Ꮿ', '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', '𐐨' => '𐐀', '𐐩' => '𐐁', '𐐪' => '𐐂', '𐐫' => '𐐃', '𐐬' => '𐐄', '𐐭' => '𐐅', '𐐮' => '𐐆', '𐐯' => '𐐇', '𐐰' => '𐐈', '𐐱' => '𐐉', '𐐲' => '𐐊', '𐐳' => '𐐋', '𐐴' => '𐐌', '𐐵' => '𐐍', '𐐶' => '𐐎', '𐐷' => '𐐏', '𐐸' => '𐐐', '𐐹' => '𐐑', '𐐺' => '𐐒', '𐐻' => '𐐓', '𐐼' => '𐐔', '𐐽' => '𐐕', '𐐾' => '𐐖', '𐐿' => '𐐗', '𐑀' => '𐐘', '𐑁' => '𐐙', '𐑂' => '𐐚', '𐑃' => '𐐛', '𐑄' => '𐐜', '𐑅' => '𐐝', '𐑆' => '𐐞', '𐑇' => '𐐟', '𐑈' => '𐐠', '𐑉' => '𐐡', '𐑊' => '𐐢', '𐑋' => '𐐣', '𐑌' => '𐐤', '𐑍' => '𐐥', '𐑎' => '𐐦', '𐑏' => '𐐧', '𐓘' => '𐒰', '𐓙' => '𐒱', '𐓚' => '𐒲', '𐓛' => '𐒳', '𐓜' => '𐒴', '𐓝' => '𐒵', '𐓞' => '𐒶', '𐓟' => '𐒷', '𐓠' => '𐒸', '𐓡' => '𐒹', '𐓢' => '𐒺', '𐓣' => '𐒻', '𐓤' => '𐒼', '𐓥' => '𐒽', '𐓦' => '𐒾', '𐓧' => '𐒿', '𐓨' => '𐓀', '𐓩' => '𐓁', '𐓪' => '𐓂', '𐓫' => '𐓃', '𐓬' => '𐓄', '𐓭' => '𐓅', '𐓮' => '𐓆', '𐓯' => '𐓇', '𐓰' => '𐓈', '𐓱' => '𐓉', '𐓲' => '𐓊', '𐓳' => '𐓋', '𐓴' => '𐓌', '𐓵' => '𐓍', '𐓶' => '𐓎', '𐓷' => '𐓏', '𐓸' => '𐓐', '𐓹' => '𐓑', '𐓺' => '𐓒', '𐓻' => '𐓓', '𐳀' => '𐲀', '𐳁' => '𐲁', '𐳂' => '𐲂', '𐳃' => '𐲃', '𐳄' => '𐲄', '𐳅' => '𐲅', '𐳆' => '𐲆', '𐳇' => '𐲇', '𐳈' => '𐲈', '𐳉' => '𐲉', '𐳊' => '𐲊', '𐳋' => '𐲋', '𐳌' => '𐲌', '𐳍' => '𐲍', '𐳎' => '𐲎', '𐳏' => '𐲏', '𐳐' => '𐲐', '𐳑' => '𐲑', '𐳒' => '𐲒', '𐳓' => '𐲓', '𐳔' => '𐲔', '𐳕' => '𐲕', '𐳖' => '𐲖', '𐳗' => '𐲗', '𐳘' => '𐲘', '𐳙' => '𐲙', '𐳚' => '𐲚', '𐳛' => '𐲛', '𐳜' => '𐲜', '𐳝' => '𐲝', '𐳞' => '𐲞', '𐳟' => '𐲟', '𐳠' => '𐲠', '𐳡' => '𐲡', '𐳢' => '𐲢', '𐳣' => '𐲣', '𐳤' => '𐲤', '𐳥' => '𐲥', '𐳦' => '𐲦', '𐳧' => '𐲧', '𐳨' => '𐲨', '𐳩' => '𐲩', '𐳪' => '𐲪', '𐳫' => '𐲫', '𐳬' => '𐲬', '𐳭' => '𐲭', '𐳮' => '𐲮', '𐳯' => '𐲯', '𐳰' => '𐲰', '𐳱' => '𐲱', '𐳲' => '𐲲', '𑣀' => '𑢠', '𑣁' => '𑢡', '𑣂' => '𑢢', '𑣃' => '𑢣', '𑣄' => '𑢤', '𑣅' => '𑢥', '𑣆' => '𑢦', '𑣇' => '𑢧', '𑣈' => '𑢨', '𑣉' => '𑢩', '𑣊' => '𑢪', '𑣋' => '𑢫', '𑣌' => '𑢬', '𑣍' => '𑢭', '𑣎' => '𑢮', '𑣏' => '𑢯', '𑣐' => '𑢰', '𑣑' => '𑢱', '𑣒' => '𑢲', '𑣓' => '𑢳', '𑣔' => '𑢴', '𑣕' => '𑢵', '𑣖' => '𑢶', '𑣗' => '𑢷', '𑣘' => '𑢸', '𑣙' => '𑢹', '𑣚' => '𑢺', '𑣛' => '𑢻', '𑣜' => '𑢼', '𑣝' => '𑢽', '𑣞' => '𑢾', '𑣟' => '𑢿', '𖹠' => '𖹀', '𖹡' => '𖹁', '𖹢' => '𖹂', '𖹣' => '𖹃', '𖹤' => '𖹄', '𖹥' => '𖹅', '𖹦' => '𖹆', '𖹧' => '𖹇', '𖹨' => '𖹈', '𖹩' => '𖹉', '𖹪' => '𖹊', '𖹫' => '𖹋', '𖹬' => '𖹌', '𖹭' => '𖹍', '𖹮' => '𖹎', '𖹯' => '𖹏', '𖹰' => '𖹐', '𖹱' => '𖹑', '𖹲' => '𖹒', '𖹳' => '𖹓', '𖹴' => '𖹔', '𖹵' => '𖹕', '𖹶' => '𖹖', '𖹷' => '𖹗', '𖹸' => '𖹘', '𖹹' => '𖹙', '𖹺' => '𖹚', '𖹻' => '𖹛', '𖹼' => '𖹜', '𖹽' => '𖹝', '𖹾' => '𖹞', '𖹿' => '𖹟', '𞤢' => '𞤀', '𞤣' => '𞤁', '𞤤' => '𞤂', '𞤥' => '𞤃', '𞤦' => '𞤄', '𞤧' => '𞤅', '𞤨' => '𞤆', '𞤩' => '𞤇', '𞤪' => '𞤈', '𞤫' => '𞤉', '𞤬' => '𞤊', '𞤭' => '𞤋', '𞤮' => '𞤌', '𞤯' => '𞤍', '𞤰' => '𞤎', '𞤱' => '𞤏', '𞤲' => '𞤐', '𞤳' => '𞤑', '𞤴' => '𞤒', '𞤵' => '𞤓', '𞤶' => '𞤔', '𞤷' => '𞤕', '𞤸' => '𞤖', '𞤹' => '𞤗', '𞤺' => '𞤘', '𞤻' => '𞤙', '𞤼' => '𞤚', '𞤽' => '𞤛', '𞤾' => '𞤜', '𞤿' => '𞤝', '𞥀' => '𞤞', '𞥁' => '𞤟', '𞥂' => '𞤠', '𞥃' => '𞤡', 'ß' => 'SS', 'ff' => 'FF', 'fi' => 'FI', 'fl' => 'FL', 'ffi' => 'FFI', 'ffl' => 'FFL', 'ſt' => 'ST', 'st' => 'ST', 'և' => 'ԵՒ', 'ﬓ' => 'ՄՆ', 'ﬔ' => 'ՄԵ', 'ﬕ' => 'ՄԻ', 'ﬖ' => 'ՎՆ', 'ﬗ' => 'ՄԽ', 'ʼn' => 'ʼN', 'ΐ' => 'Ϊ́', 'ΰ' => 'Ϋ́', 'ǰ' => 'J̌', 'ẖ' => 'H̱', 'ẗ' => 'T̈', 'ẘ' => 'W̊', 'ẙ' => 'Y̊', 'ẚ' => 'Aʾ', 'ὐ' => 'Υ̓', 'ὒ' => 'Υ̓̀', 'ὔ' => 'Υ̓́', 'ὖ' => 'Υ̓͂', 'ᾶ' => 'Α͂', 'ῆ' => 'Η͂', 'ῒ' => 'Ϊ̀', 'ΐ' => 'Ϊ́', 'ῖ' => 'Ι͂', 'ῗ' => 'Ϊ͂', 'ῢ' => 'Ϋ̀', 'ΰ' => 'Ϋ́', 'ῤ' => 'Ρ̓', 'ῦ' => 'Υ͂', 'ῧ' => 'Ϋ͂', 'ῶ' => 'Ω͂', 'ᾈ' => 'ἈΙ', 'ᾉ' => 'ἉΙ', 'ᾊ' => 'ἊΙ', 'ᾋ' => 'ἋΙ', 'ᾌ' => 'ἌΙ', 'ᾍ' => 'ἍΙ', 'ᾎ' => 'ἎΙ', 'ᾏ' => 'ἏΙ', 'ᾘ' => 'ἨΙ', 'ᾙ' => 'ἩΙ', 'ᾚ' => 'ἪΙ', 'ᾛ' => 'ἫΙ', 'ᾜ' => 'ἬΙ', 'ᾝ' => 'ἭΙ', 'ᾞ' => 'ἮΙ', 'ᾟ' => 'ἯΙ', 'ᾨ' => 'ὨΙ', 'ᾩ' => 'ὩΙ', 'ᾪ' => 'ὪΙ', 'ᾫ' => 'ὫΙ', 'ᾬ' => 'ὬΙ', 'ᾭ' => 'ὭΙ', 'ᾮ' => 'ὮΙ', 'ᾯ' => 'ὯΙ', 'ᾼ' => 'ΑΙ', 'ῌ' => 'ΗΙ', 'ῼ' => 'ΩΙ', 'ᾲ' => 'ᾺΙ', 'ᾴ' => 'ΆΙ', 'ῂ' => 'ῊΙ', 'ῄ' => 'ΉΙ', 'ῲ' => 'ῺΙ', 'ῴ' => 'ΏΙ', 'ᾷ' => 'Α͂Ι', 'ῇ' => 'Η͂Ι', 'ῷ' => 'Ω͂Ι', ); * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Php72 as p; if (\PHP_VERSION_ID >= 70200) { return; } if (!defined('PHP_FLOAT_DIG')) { define('PHP_FLOAT_DIG', 15); } if (!defined('PHP_FLOAT_EPSILON')) { define('PHP_FLOAT_EPSILON', 2.2204460492503E-16); } if (!defined('PHP_FLOAT_MIN')) { define('PHP_FLOAT_MIN', 2.2250738585072E-308); } if (!defined('PHP_FLOAT_MAX')) { define('PHP_FLOAT_MAX', 1.7976931348623157E+308); } if (!defined('PHP_OS_FAMILY')) { define('PHP_OS_FAMILY', p\Php72::php_os_family()); } if ('\\' === \DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) { function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); } } if (!function_exists('stream_isatty')) { function stream_isatty($stream) { return p\Php72::stream_isatty($stream); } } if (!function_exists('utf8_encode')) { function utf8_encode($string) { return p\Php72::utf8_encode($string); } } if (!function_exists('utf8_decode')) { function utf8_decode($string) { return p\Php72::utf8_decode($string); } } if (!function_exists('spl_object_id')) { function spl_object_id($object) { return p\Php72::spl_object_id($object); } } if (!function_exists('mb_ord')) { function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); } } if (!function_exists('mb_chr')) { function mb_chr($codepoint, $encoding = null) { return p\Php72::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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Php72; /** * @author Nicolas Grekas * @author Dariusz Rumiński * * @internal */ final class Php72 { private static $hashMask; public static function utf8_encode($s) { $s .= $s; $len = \strlen($s); for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { switch (true) { case $s[$i] < "\x80": $s[$j] = $s[$i]; break; case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break; } } return substr($s, 0, $j); } public static function utf8_decode($s) { $s = (string) $s; $len = \strlen($s); for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { switch ($s[$i] & "\xF0") { case "\xC0": case "\xD0": $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F"); $s[$j] = $c < 256 ? \chr($c) : '?'; break; case "\xF0": ++$i; // no break case "\xE0": $s[$j] = '?'; $i += 2; break; default: $s[$j] = $s[$i]; } } return substr($s, 0, $j); } public static function php_os_family() { if ('\\' === \DIRECTORY_SEPARATOR) { return 'Windows'; } $map = [ 'Darwin' => 'Darwin', 'DragonFly' => 'BSD', 'FreeBSD' => 'BSD', 'NetBSD' => 'BSD', 'OpenBSD' => 'BSD', 'Linux' => 'Linux', 'SunOS' => 'Solaris', ]; return $map[\PHP_OS] ?? 'Unknown'; } public static function spl_object_id($object) { if (null === self::$hashMask) { self::initHashMask(); } if (null === $hash = spl_object_hash($object)) { return; } // On 32-bit systems, PHP_INT_SIZE is 4, return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1)); } public static function sapi_windows_vt100_support($stream, $enable = null) { if (!\is_resource($stream)) { trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING); return false; } $meta = stream_get_meta_data($stream); if ('STDIO' !== $meta['stream_type']) { trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING); return false; } // We cannot actually disable vt100 support if it is set if (false === $enable || !self::stream_isatty($stream)) { return false; } // The native function does not apply to stdin $meta = array_map('strtolower', $meta); $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; return !$stdin && (false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM') || 'Hyper' === getenv('TERM_PROGRAM')); } public static function stream_isatty($stream) { if (!\is_resource($stream)) { trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING); return false; } if ('\\' === \DIRECTORY_SEPARATOR) { $stat = @fstat($stream); // Check if formatted mode is S_IFCHR return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; } return \function_exists('posix_isatty') && @posix_isatty($stream); } private static function initHashMask() { $obj = (object) []; self::$hashMask = -1; // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush']; foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) { if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { $frame['line'] = 0; break; } } if (!empty($frame['line'])) { ob_start(); debug_zval_dump($obj); self::$hashMask = (int) substr(ob_get_clean(), 17); } self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1)); } 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 = $encoding ?? mb_internal_encoding()) { $s = mb_convert_encoding($s, $encoding, 'UTF-8'); } return $s; } public static function mb_ord($s, $encoding = null) { if (null === $encoding) { $s = mb_convert_encoding($s, 'UTF-8'); } elseif ('UTF-8' !== $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; } } * * 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 */ interface ExceptionInterface extends \Throwable { } * * 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 */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } * * 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 */ class LogicException extends \LogicException implements ExceptionInterface { } * * 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 */ 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; } } * * 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 */ 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(); } } * * 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 */ 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)), }; } } * * 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 */ final class RunProcessFailedException extends RuntimeException { public function __construct(ProcessFailedException $exception, public readonly RunProcessContext $context) { parent::__construct($exception->getMessage(), $exception->getCode()); } } * * 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 */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } * * 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 * @author Johannes M. Schmitt */ class ExecutableFinder { private array $suffixes = ['.exe', '.bat', '.cmd', '.com']; /** * 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 { $dirs = array_merge( explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), $extraDirs ); $suffixes = ['']; if ('\\' === \DIRECTORY_SEPARATOR) { $pathExt = getenv('PATHEXT'); $suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes); } foreach ($suffixes as $suffix) { foreach ($dirs as $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; } } } $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v'; if (\function_exists('exec') && ($executablePath = strtok(@exec($command.' '.escapeshellarg($name)), \PHP_EOL)) && @is_executable($executablePath)) { return $executablePath; } return $default; } } * * 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 * * @implements \IteratorAggregate */ 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)); } } } } * * 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 */ 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(); } } * * 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 */ 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); } } * * 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 */ 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())); } } } * * 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 * @author Johannes M. Schmitt */ 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)) { $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v'; if (\function_exists('exec') && $php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) { if (!is_executable($php)) { return false; } } else { 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; } } * * 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(''); * $p->run(); * print $p->getOutput()."\n"; * * @author Fabien Potencier */ 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); } } * * 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: * * 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 * @author Partially copied and heavily inspired from composer/xdebug-handler by John Stevenson */ 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)) { $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; } } * * 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 * * @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. */ protected function hasSystemCallBeenInterrupted(): bool { $lastError = $this->lastError; $this->lastError = null; // stream_select returns false when the `select` system call is interrupted by an incoming signal return null !== $lastError && false !== stripos($lastError, 'interrupted system call'); } /** * Unblocks streams. */ protected function unblock(): void { if (!$this->blocked) { return; } foreach ($this->pipes as $pipe) { stream_set_blocking($pipe, 0); } if (\is_resource($this->input)) { stream_set_blocking($this->input, 0); } $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, 0); } 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; } } * * 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 * * @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; } * * 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 * * @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 __sleep(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } public function __wakeup(): 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'], ['pty'], ]; } 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; } } * * 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 * * @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 __sleep(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } public function __wakeup(): 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 = []; } } * * 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 * @author Romain Neutron * * @implements \IteratorAggregate */ 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 __sleep(): array { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } /** * @return void */ public function __wakeup() { 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 (!\is_resource($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 * * @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 $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)); } /** * 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; } $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 (\is_resource($this->process)) { proc_close($this->process); } $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 ); $cmd = '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); } } * * 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ň */ 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; } } * * 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 */ #[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] final class Required { } * * 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\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberTrait; /** * For use as the return value for {@see ServiceSubscriberInterface}. * * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) * * Use with {@see ServiceSubscriberTrait} to mark a method's return type * as a subscribed service. * * @author Kevin Bond */ #[\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]; } } * * 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(); } * * 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 * @author Nicolas Grekas */ trait ServiceLocatorTrait { private array $factories; private array $loading = []; private array $providedTypes; /** * @param array $factories */ public function __construct(array $factories) { $this->factories = $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 { }; } } * * 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 * @author Mateusz Sip * * @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 The provided service types, keyed by service names */ public function getProvidedServices(): array; } * * 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 */ 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; } * * 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 * method return types. Service ids are available as "ClassName::methodName". * * @author Kevin Bond */ trait ServiceSubscriberTrait { /** @var ContainerInterface */ protected $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 = $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; } } * * 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 { } } * * 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 { 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'); }, ]); if (!$this->getExpectedException()) { $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'); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; /** * Represents a string of abstract characters. * * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). * This class is the abstract type to use as a type-hint when the logic you want to * implement doesn't care about the exact variant it deals with. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ abstract class AbstractString implements \Stringable, \JsonSerializable { public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER; public const PREG_SET_ORDER = \PREG_SET_ORDER; public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE; public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL; public const PREG_SPLIT = 0; public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY; public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; protected string $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; 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 $cut = true): static { $stringLength = $this->length(); if ($stringLength <= $length) { return clone $this; } $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0; if ($length < $ellipsisLength) { $ellipsisLength = 0; } if (!$cut) { if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { return clone $this; } $length += $ellipsisLength; } $str = $this->slice(0, $length - $ellipsisLength); return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; } 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; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; /** * Represents a string of abstract Unicode characters. * * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). * This class is the abstract type to use as a type-hint when the logic you want to * implement is Unicode-aware but doesn't care about code points vs grapheme clusters. * * @author Nicolas Grekas * * @throws ExceptionInterface */ abstract class AbstractUnicodeString extends AbstractString { public const NFC = \Normalizer::NFC; public const NFD = \Normalizer::NFD; public const NFKC = \Normalizer::NFKC; public const NFKD = \Normalizer::NFKD; // all ASCII letters sorted by typical frequency of occurrence private const ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; // the subset of folded case mappings that is not in lower case mappings private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ']; private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ']; // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆']; private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; private static 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 { $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); } return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); }, $s); } } $str->string .= $s; return $str; } public function camel(): static { $str = clone $this; $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/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, $this->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; } 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; } 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; } 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; } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; /** * Represents a binary-safe string of bytes. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class ByteString extends AbstractString { private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; public function __construct(string $string = '') { $this->string = $string; } /* * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03) * * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16 * * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE). * * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) */ public static function fromRandom(int $length = 16, string $alphabet = null): self { if ($length <= 0) { throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length)); } $alphabet ??= self::ALPHABET_ALPHANUMERIC; $alphabetSize = \strlen($alphabet); $bits = (int) ceil(log($alphabetSize, 2.0)); if ($bits <= 0 || $bits > 56) { throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); } $ret = ''; while ($length > 0) { $urandomLength = (int) ceil(2 * $length * $bits / 8.0); $data = random_bytes($urandomLength); $unpackedData = 0; $unpackedBits = 0; for ($i = 0; $i < $urandomLength && $length > 0; ++$i) { // Unpack 8 bits $unpackedData = ($unpackedData << 8) | \ord($data[$i]); $unpackedBits += 8; // While we have enough bits to select a character from the alphabet, keep // consuming the random data for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) { $index = ($unpackedData & ((1 << $bits) - 1)); $unpackedData >>= $bits; // Unfortunately, the alphabet size is not necessarily a power of two. // Worst case, it is 2^k + 1, which means we need (k+1) bits and we // have around a 50% chance of missing as k gets larger if ($index < $alphabetSize) { $ret .= $alphabet[$index]; --$length; } } } } return new static($ret); } public function bytesAt(int $offset): array { $str = $this->string[$offset] ?? ''; return '' === $str ? [] : [\ord($str)]; } public function append(string ...$suffix): 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 = (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); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; /** * Represents a string of Unicode code points encoded as UTF-8. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class CodePointString extends AbstractUnicodeString { public function __construct(string $string = '') { if ('' !== $string && !preg_match('//u', $string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $this->string = $string; } public function append(string ...$suffix): 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)); } } * * 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 { } * * 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 { } * * 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 { } * * 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 // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['a', 1, true, true, ['on', 'um']], // nebulae (nebula) ['ea', 2, true, true, 'a'], // services (service) ['secivres', 8, true, true, 'service'], // mice (mouse), lice (louse) ['eci', 3, false, true, 'ouse'], // geese (goose) ['esee', 4, false, true, 'oose'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['i', 1, true, true, 'us'], // men (man), women (woman) ['nem', 3, true, true, 'man'], // children (child) ['nerdlihc', 8, true, true, 'child'], // oxen (ox) ['nexo', 4, false, false, 'ox'], // indices (index), appendices (appendix), prices (price) ['seci', 4, false, true, ['ex', 'ix', 'ice']], // codes (code) ['sedoc', 5, false, true, 'code'], // selfies (selfie) ['seifles', 7, true, true, 'selfie'], // zombies (zombie) ['seibmoz', 7, true, true, 'zombie'], // movies (movie) ['seivom', 6, true, true, 'movie'], // names (name) ['seman', 5, true, false, 'name'], // conspectuses (conspectus), prospectuses (prospectus) ['sesutcep', 8, true, true, 'pectus'], // feet (foot) ['teef', 4, true, true, 'foot'], // geese (goose) ['eseeg', 5, true, true, 'goose'], // teeth (tooth) ['hteet', 5, true, true, 'tooth'], // news (news) ['swen', 4, true, true, 'news'], // series (series) ['seires', 6, true, true, 'series'], // babies (baby) ['sei', 3, false, true, 'y'], // accesses (access), addresses (address), kisses (kiss) ['sess', 4, true, false, 'ss'], // statuses (status) ['sesutats', 8, true, true, 'status'], // analyses (analysis), ellipses (ellipsis), fungi (fungus), // neuroses (neurosis), theses (thesis), emphases (emphasis), // oases (oasis), crises (crisis), houses (house), bases (base), // atlases (atlas) ['ses', 3, true, true, ['s', 'se', 'sis']], // objectives (objective), alternative (alternatives) ['sevit', 5, true, true, 'tive'], // drives (drive) ['sevird', 6, false, true, 'drive'], // lives (life), wives (wife) ['sevi', 4, false, true, 'ife'], // moves (move) ['sevom', 5, true, true, 'move'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) ['sev', 3, true, true, ['f', 've', 'ff']], // axes (axis), axes (ax), axes (axe) ['sexa', 4, false, false, ['ax', 'axe', 'axis']], // indexes (index), matrixes (matrix) ['sex', 3, true, false, 'x'], // quizzes (quiz) ['sezz', 4, true, false, 'z'], // bureaus (bureau) ['suae', 4, false, true, 'eau'], // fees (fee), trees (tree), employees (employee) ['see', 3, true, true, 'ee'], // edges (edge) ['segd', 4, true, true, 'dge'], // roses (rose), garages (garage), cassettes (cassette), // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), // shoes (shoe) ['se', 2, true, true, ['', 'e']], // status (status) ['sutats', 6, true, true, 'status'], // tags (tag) ['s', 1, true, true, ''], // chateaux (chateau) ['xuae', 4, false, true, 'eau'], // people (person) ['elpoep', 6, true, true, 'person'], ]; /** * Map English singular to plural suffixes. * * @see http://english-zone.com/spelling/plurals.html */ private const SINGULAR_MAP = [ // First entry: singular suffix, reversed // Second entry: length of singular suffix // Third entry: Whether the suffix may succeed a vowel // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: plural suffix, normal // criterion (criteria) ['airetirc', 8, false, false, 'criterion'], // nebulae (nebula) ['aluben', 6, false, false, 'nebulae'], // children (child) ['dlihc', 5, true, true, 'children'], // prices (price) ['eci', 3, false, true, 'ices'], // services (service) ['ecivres', 7, true, true, 'services'], // lives (life), wives (wife) ['efi', 3, false, true, 'ives'], // selfies (selfie) ['eifles', 6, true, true, 'selfies'], // movies (movie) ['eivom', 5, true, true, 'movies'], // lice (louse) ['esuol', 5, false, true, 'lice'], // mice (mouse) ['esuom', 5, false, true, 'mice'], // geese (goose) ['esoo', 4, false, true, 'eese'], // houses (house), bases (base) ['es', 2, true, true, 'ses'], // geese (goose) ['esoog', 5, true, true, 'geese'], // caves (cave) ['ev', 2, true, true, 'ves'], // drives (drive) ['evird', 5, false, true, 'drives'], // objectives (objective), alternative (alternatives) ['evit', 4, true, true, 'tives'], // moves (move) ['evom', 4, true, true, 'moves'], // staves (staff) ['ffats', 5, true, true, 'staves'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) ['ff', 2, true, true, 'ffs'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) ['f', 1, true, true, ['fs', 'ves']], // arches (arch) ['hc', 2, true, true, 'ches'], // bushes (bush) ['hs', 2, true, true, 'shes'], // teeth (tooth) ['htoot', 5, true, true, 'teeth'], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['mu', 2, true, true, 'a'], // men (man), women (woman) ['nam', 3, true, true, 'men'], // people (person) ['nosrep', 6, true, true, ['persons', 'people']], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['noi', 3, true, true, 'ions'], // coupon (coupons) ['nop', 3, true, true, 'pons'], // seasons (season), treasons (treason), poisons (poison), lessons (lesson) ['nos', 3, true, true, 'sons'], // icons (icon) ['noc', 3, true, true, 'cons'], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['no', 2, true, true, 'a'], // echoes (echo) ['ohce', 4, true, true, 'echoes'], // heroes (hero) ['oreh', 4, true, true, 'heroes'], // atlases (atlas) ['salta', 5, true, true, 'atlases'], // irises (iris) ['siri', 4, true, true, 'irises'], // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) // theses (thesis), emphases (emphasis), oases (oasis), // crises (crisis) ['sis', 3, true, true, 'ses'], // accesses (access), addresses (address), kisses (kiss) ['ss', 2, true, false, 'sses'], // syllabi (syllabus) ['suballys', 8, true, true, 'syllabi'], // buses (bus) ['sub', 3, true, true, 'buses'], // circuses (circus) ['suc', 3, true, true, 'cuses'], // status (status) ['sutats', 6, true, true, ['status', 'statuses']], // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, true, true, 'pectuses'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['su', 2, true, true, 'i'], // news (news) ['swen', 4, true, true, 'news'], // feet (foot) ['toof', 4, true, true, 'feet'], // chateaux (chateau), bureaus (bureau) ['uae', 3, false, true, ['eaus', 'eaux']], // oxen (ox) ['xo', 2, false, false, 'oxen'], // hoaxes (hoax) ['xaoh', 4, true, false, 'hoaxes'], // indices (index) ['xedni', 5, false, true, ['indicies', 'indexes']], // boxes (box) ['xo', 2, false, true, 'oxes'], // indexes (index), matrixes (matrix) ['x', 1, true, false, ['cies', 'xes']], // appendices (appendix) ['xi', 2, false, true, 'ices'], // babies (baby) ['y', 1, false, true, 'ies'], // quizzes (quiz) ['ziuq', 4, true, false, 'quizzes'], // waltzes (waltz) ['z', 1, true, true, 'zes'], ]; /** * A list of words which should not be inflected, reversed. */ private const UNINFLECTED = [ '', // data 'atad', // deer 'reed', // 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', ]; 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']; } } * * 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); } } * * 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; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; /** * A string whose value is computed lazily by a callback. * * @author Nicolas Grekas */ class LazyString implements \Stringable, \JsonSerializable { private \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 = self::getPrettyName($callback); $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 (str_contains($r->name, '{closure}') || !$class = $r->getClosureCalledClass()) { return $r->name; } $class = $class->name; $method = $r->name; } else { $class = get_debug_type($callback); $method = '__invoke'; } return $class.'::'.$method; } } * * 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); } } * * 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\Intl\Transliterator\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 */ 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 ?string $defaultLocale; 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(string $defaultLocale = null, array|\Closure $symbolsMap = null) { $this->defaultLocale = $defaultLocale; $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/intl" package is not installed. Try running "composer require symfony/intl".', __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)); } } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Slugger; use Symfony\Component\String\AbstractUnicodeString; /** * Creates a URL-friendly slug from a given string. * * @author Titouan Galopin */ interface SluggerInterface { /** * Creates a slug for the given string and locale, using appropriate transliteration when needed. */ public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString; } * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; /** * Represents a string of Unicode grapheme clusters encoded as UTF-8. * * A letter followed by combining characters (accents typically) form what Unicode defines * as a grapheme cluster: a character as humans mean it in written texts. This class knows * about the concept and won't split a letter apart from its combining accents. It also * ensures all string comparisons happen on their canonically-composed representation, * ignoring e.g. the order in which accents are listed when a letter has many of them. * * @see https://unicode.org/reports/tr15/ * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class UnicodeString extends AbstractUnicodeString { public function __construct(string $string = '') { 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 ?? 2147483647)) : $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; } } _initNeverAllowedStr(); $this->_initNeverAllowedRegex(); } /** * Compact any exploded words. * *

*
* INFO: This corrects words like: j a v a s c r i p t *
* These words are compacted back to their correct state. *

* * @param string $str * * @return string */ private function _compact_exploded_javascript($str) { static $WORDS_CACHE; $WORDS_CACHE['chunk'] = []; $WORDS_CACHE['split'] = []; $words = [ 'javascript', '', '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( '#(?[^\p{L}]|^)(?' . \str_replace( ['#', '.'], ['\#', '\.'], $WORDS_CACHE['chunk'][$word] ) . ')(?[^\p{L}@.!?\' ]|$)#ius', function ($matches) { return $this->_compact_exploded_words_callback($matches); }, $str ); } return $str; } /** * Compact exploded words. * *

*
* INFO: Callback method for xss_clean() to remove whitespace from things like 'j a v a s c r i p t'. *

* * @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*([\"'])(?[^\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(['<', '>'], [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], ['<', '>'], $urlPartClean); $str = \str_ireplace($matches['attr'], $urlPartClean, $str); } } } } } if ($needProtection) { $str = \str_replace(['<', '>'], [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], ['<', '>'], $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> */ 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. * *

*
* INFO: clean-up also some string, if there is no html-tag *

* * @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 = '(?[^\p{L}@.!?>]|^)(?:' . \implode('|', $events) . ')(?\(.*?\)|.*?>|(?:\s|\[.*?\])*?=(?:\s|\[.*?\])*?|(?:\s|\[.*?\])*?=(?:\s|\[.*?\])*?|[^\p{L}]*?=[^\p{L}]*?|[^\p{L}]*?=[^\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('/(?&[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 = [ '�' => '', '�' => '', '' => '', '' => '', '>⃒' => '', '' => '', '' => '', '­' => '', '­' => '', '­' => '', ':' => ':', ':' => ':', ':' => ':', '(' => '(', '(' => '(', '(' => '(', ')' => ')', ')' => ')', ')' => ')', '?' => '?', '?' => '?', '?' => '?', '/' => '/', '/' => '/', '/' => '/', ''' => '\'', ''' => '\'', ''' => '\'', ''' => '\'', ''' => '\'', '\' => '\'', '\' => '\\', '\' => '\\', ',' => ',', ',' => ',', ',' => ',', '.' => '.', '.' => '.', '"' => '"', '"' => '"', '"' => '"', '"' => '"', '`' => '`', '`' => '`', '`' => '`', '`' => '`', '.' => '.', '=' => '=', '=' => '=', '=' => '=', '&newline;' => "\n", ' ' => "\n", ' ' => "\n", '&tab;' => "\t", ' ' => "\t", ' ' => "\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 */ 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, ' '<?', '?>' => '?>', ' '<![CDATA[', ' '<!ENTITY', ' '<!DOCTYPE', ' '<!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\=(?[\'|"]).*\.js(?:\g{wrapper})' => $this->_replacement, // comments '' => '<!--$1-->', '