From cb11c3a54e9bcd93d0a6a1278543df7783bac652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Sun, 23 Jun 2024 22:59:18 +0200 Subject: [PATCH] Explorations of Site Transfer Protocol --- transfer-protocol/.phpunit.result.cache | 1 + transfer-protocol/README.md | 6 + transfer-protocol/bootstrap.php | 25 + transfer-protocol/composer.json | 17 + transfer-protocol/composer.lock | 388 + transfer-protocol/iter.php | 32 + transfer-protocol/married.html | 319 + transfer-protocol/phpunit.xml | 7 + transfer-protocol/rewrite-urls.php | 170 + transfer-protocol/run-tests.sh | 4 + .../src/WP_Block_Markup_Processor.php | 243 + .../src/WP_Block_Markup_Url_Processor.php | 208 + transfer-protocol/tests/UrlParserTests.php | 133 + .../tests/WP_Block_Markup_Processor_Tests.php | 114 + .../WP_Block_Markup_Url_Processor_Tests.php | 99 + transfer-protocol/tests/urltestdata.json | 9801 +++++++++++++++++ transfer-protocol/vendor/autoload.php | 12 + .../vendor/brick/math/CHANGELOG.md | 415 + transfer-protocol/vendor/brick/math/LICENSE | 20 + .../vendor/brick/math/SECURITY.md | 17 + .../vendor/brick/math/composer.json | 35 + .../vendor/brick/math/src/BigDecimal.php | 895 ++ .../vendor/brick/math/src/BigInteger.php | 1184 ++ .../vendor/brick/math/src/BigNumber.php | 572 + .../vendor/brick/math/src/BigRational.php | 523 + .../src/Exception/DivisionByZeroException.php | 41 + .../Exception/IntegerOverflowException.php | 27 + .../math/src/Exception/MathException.php | 14 + .../src/Exception/NegativeNumberException.php | 12 + .../src/Exception/NumberFormatException.php | 35 + .../Exception/RoundingNecessaryException.php | 21 + .../brick/math/src/Internal/Calculator.php | 756 ++ .../Internal/Calculator/BcMathCalculator.php | 116 + .../src/Internal/Calculator/GmpCalculator.php | 156 + .../Internal/Calculator/NativeCalculator.php | 634 ++ .../vendor/brick/math/src/RoundingMode.php | 107 + .../vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 352 + transfer-protocol/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_files.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 17 + .../vendor/composer/autoload_real.php | 57 + .../vendor/composer/autoload_static.php | 88 + .../vendor/composer/installed.json | 393 + .../vendor/composer/installed.php | 77 + .../vendor/composer/platform_check.php | 26 + transfer-protocol/vendor/psr/log/LICENSE | 19 + transfer-protocol/vendor/psr/log/README.md | 58 + .../vendor/psr/log/composer.json | 26 + .../vendor/psr/log/src/AbstractLogger.php | 15 + .../psr/log/src/InvalidArgumentException.php | 7 + .../vendor/psr/log/src/LogLevel.php | 18 + .../psr/log/src/LoggerAwareInterface.php | 18 + .../vendor/psr/log/src/LoggerAwareTrait.php | 26 + .../vendor/psr/log/src/LoggerInterface.php | 125 + .../vendor/psr/log/src/LoggerTrait.php | 142 + .../vendor/psr/log/src/NullLogger.php | 30 + .../vendor/rowbot/idna/.gitattributes | 2 + .../rowbot/idna/.github/workflows/tests.yml | 272 + .../vendor/rowbot/idna/.gitignore | 7 + .../vendor/rowbot/idna/.phpcs.xml | 14 + .../vendor/rowbot/idna/CHANGELOG.md | 47 + transfer-protocol/vendor/rowbot/idna/LICENSE | 21 + .../vendor/rowbot/idna/README.md | 347 + .../vendor/rowbot/idna/bin/Builder.php | 90 + .../rowbot/idna/bin/IdnaDataBuilder.php | 129 + .../vendor/rowbot/idna/bin/RegexBuilder.php | 209 + .../rowbot/idna/bin/ViramaDataBuilder.php | 47 + .../rowbot/idna/bin/generateDataFiles.php | 17 + .../vendor/rowbot/idna/composer.json | 41 + .../vendor/rowbot/idna/phpstan.neon | 16 + .../vendor/rowbot/idna/phpunit.xml | 23 + .../idna/resources/DisallowedRanges.php | 361 + .../vendor/rowbot/idna/resources/Regex.php | 32 + .../rowbot/idna/resources/deviation.php | 8 + .../rowbot/idna/resources/disallowed.php | 2715 +++++ .../idna/resources/disallowed_STD3_mapped.php | 308 + .../idna/resources/disallowed_STD3_valid.php | 71 + .../vendor/rowbot/idna/resources/ignored.php | 274 + .../vendor/rowbot/idna/resources/mapped.php | 5877 ++++++++++ .../vendor/rowbot/idna/resources/virama.php | 67 + .../vendor/rowbot/idna/src/CodePoint.php | 139 + .../rowbot/idna/src/CodePointStatus.php | 106 + .../vendor/rowbot/idna/src/DomainInfo.php | 82 + .../vendor/rowbot/idna/src/Idna.php | 268 + .../vendor/rowbot/idna/src/IdnaResult.php | 55 + .../vendor/rowbot/idna/src/LabelValidator.php | 237 + .../vendor/rowbot/idna/tests/IdnaV2Test.php | 258 + .../rowbot/idna/tests/IdnaV2TestCase.php | 216 + .../vendor/rowbot/punycode/.gitattributes | 2 + .../punycode/.github/workflows/tests.yml | 176 + .../vendor/rowbot/punycode/.gitignore | 6 + .../vendor/rowbot/punycode/.phpcs.xml | 9 + .../vendor/rowbot/punycode/CHANGELOG.md | 32 + .../vendor/rowbot/punycode/LICENSE | 21 + .../vendor/rowbot/punycode/README.md | 83 + .../vendor/rowbot/punycode/composer.json | 38 + .../vendor/rowbot/punycode/phpstan.neon | 8 + .../vendor/rowbot/punycode/phpunit.xml | 20 + .../src/Exception/InvalidInputException.php | 9 + .../Exception/OutputSizeExceededException.php | 9 + .../src/Exception/OverflowException.php | 9 + .../src/Exception/PunycodeException.php | 11 + .../vendor/rowbot/punycode/src/Punycode.php | 446 + .../rowbot/punycode/tests/PunycodeTest.php | 211 + .../rowbot/url/.github/workflows/coverage.yml | 57 + .../rowbot/url/.github/workflows/tests.yml | 70 + .../vendor/rowbot/url/.gitignore | 6 + .../vendor/rowbot/url/.phpcs.xml | 199 + .../vendor/rowbot/url/CHANGELOG.md | 302 + transfer-protocol/vendor/rowbot/url/LICENSE | 21 + transfer-protocol/vendor/rowbot/url/README.md | 254 + .../vendor/rowbot/url/composer.json | 52 + .../vendor/rowbot/url/phpstan.neon | 23 + .../vendor/rowbot/url/phpunit.xml | 19 + .../rowbot/url/src/APIParserErrorType.php | 14 + .../vendor/rowbot/url/src/APIParserResult.php | 18 + .../vendor/rowbot/url/src/BasicURLParser.php | 135 + .../rowbot/url/src/Component/AbstractPath.php | 69 + .../url/src/Component/Host/AbstractHost.php | 23 + .../url/src/Component/Host/HostInterface.php | 38 + .../url/src/Component/Host/HostParser.php | 198 + .../url/src/Component/Host/IPv4Address.php | 37 + .../src/Component/Host/IPv4AddressParser.php | 270 + .../url/src/Component/Host/IPv6Address.php | 37 + .../src/Component/Host/IPv6AddressParser.php | 337 + .../Component/Host/Math/BrickMathAdapter.php | 93 + .../Host/Math/Exception/MathException.php | 11 + .../Component/Host/Math/NativeIntAdapter.php | 81 + .../src/Component/Host/Math/NumberFactory.php | 27 + .../Component/Host/Math/NumberInterface.php | 44 + .../url/src/Component/Host/NullHost.php | 26 + .../Serializer/HostSerializerInterface.php | 15 + .../Host/Serializer/IPv4AddressSerializer.php | 57 + .../Host/Serializer/IPv6AddressSerializer.php | 121 + .../Host/Serializer/StringHostSerializer.php | 25 + .../url/src/Component/Host/StringHost.php | 37 + .../rowbot/url/src/Component/OpaqueOrigin.php | 41 + .../rowbot/url/src/Component/OpaquePath.php | 40 + .../url/src/Component/PathInterface.php | 30 + .../rowbot/url/src/Component/PathList.php | 46 + .../rowbot/url/src/Component/PathSegment.php | 33 + .../rowbot/url/src/Component/QueryList.php | 339 + .../rowbot/url/src/Component/Scheme.php | 75 + .../rowbot/url/src/Component/TupleOrigin.php | 88 + .../rowbot/url/src/Exception/TypeError.php | 9 + .../rowbot/url/src/Exception/URLException.php | 11 + .../UnsupportedOperationException.php | 9 + .../vendor/rowbot/url/src/Origin.php | 34 + .../vendor/rowbot/url/src/ParserContext.php | 88 + .../vendor/rowbot/url/src/ParserState.php | 80 + .../url/src/State/AbstractHostState.php | 145 + .../rowbot/url/src/State/AuthorityState.php | 129 + .../rowbot/url/src/State/FileHostState.php | 100 + .../rowbot/url/src/State/FileSlashState.php | 59 + .../vendor/rowbot/url/src/State/FileState.php | 108 + .../rowbot/url/src/State/FragmentState.php | 54 + .../vendor/rowbot/url/src/State/HostState.php | 9 + .../rowbot/url/src/State/HostnameState.php | 9 + .../rowbot/url/src/State/NoSchemeState.php | 55 + .../rowbot/url/src/State/OpaquePathState.php | 77 + .../url/src/State/PathOrAuthorityState.php | 30 + .../rowbot/url/src/State/PathStartState.php | 79 + .../vendor/rowbot/url/src/State/PathState.php | 153 + .../vendor/rowbot/url/src/State/PortState.php | 92 + .../rowbot/url/src/State/QueryState.php | 93 + .../url/src/State/RelativeSlashState.php | 56 + .../rowbot/url/src/State/RelativeState.php | 88 + .../rowbot/url/src/State/SchemeStartState.php | 43 + .../rowbot/url/src/State/SchemeState.php | 150 + .../SpecialAuthorityIgnoreSlashesState.php | 33 + .../State/SpecialAuthoritySlashesState.php | 37 + .../State/SpecialRelativeOrAuthorityState.php | 36 + .../vendor/rowbot/url/src/State/State.php | 12 + .../rowbot/url/src/State/StatusCode.php | 13 + .../url/src/String/AbstractStringBuffer.php | 71 + .../url/src/String/AbstractStringList.php | 103 + .../url/src/String/AbstractUSVString.php | 154 + .../rowbot/url/src/String/CodePoint.php | 86 + .../rowbot/url/src/String/EncodeSet.php | 17 + .../String/Exception/EncodingException.php | 11 + .../src/String/Exception/RegexException.php | 11 + .../Exception/UndefinedIndexException.php | 11 + .../rowbot/url/src/String/PercentEncoder.php | 261 + .../rowbot/url/src/String/StringBuffer.php | 34 + .../url/src/String/StringBufferInterface.php | 42 + .../src/String/StringIteratorInterface.php | 32 + .../rowbot/url/src/String/StringList.php | 12 + .../url/src/String/StringListInterface.php | 36 + .../url/src/String/USVStringInterface.php | 53 + .../rowbot/url/src/String/Utf8String.php | 48 + .../url/src/String/Utf8StringIterator.php | 79 + .../rowbot/url/src/Support/EncodingHelper.php | 38 + .../vendor/rowbot/url/src/URL.php | 405 + .../vendor/rowbot/url/src/URLRecord.php | 228 + .../vendor/rowbot/url/src/URLSearchParams.php | 414 + .../rowbot/url/tests/EncodingHelperTest.php | 22 + .../rowbot/url/tests/HostParserTest.php | 59 + .../url/tests/Math/BrickMathAdapterTest.php | 36 + .../rowbot/url/tests/Math/MathTestCase.php | 115 + .../url/tests/Math/NativeIntAdapterTest.php | 36 + .../vendor/rowbot/url/tests/NullHostTest.php | 28 + .../vendor/rowbot/url/tests/OriginTest.php | 212 + .../vendor/rowbot/url/tests/PathTest.php | 54 + .../vendor/rowbot/url/tests/QueryListTest.php | 22 + .../rowbot/url/tests/QueryStateTest.php | 47 + .../vendor/rowbot/url/tests/SchemeTest.php | 45 + .../vendor/rowbot/url/tests/StringsTest.php | 120 + .../vendor/rowbot/url/tests/URLRecordTest.php | 48 + .../rowbot/url/tests/URLSearchParamsTest.php | 119 + .../vendor/rowbot/url/tests/URLTest.php | 124 + .../url/tests/ValidationErrorLogger.php | 21 + .../rowbot/url/tests/WhatWg/FailureTest.php | 42 + .../url/tests/WhatWg/PercentEncodingTest.php | 68 + .../url/tests/WhatWg/ToASCIIWindowTest.php | 55 + .../url/tests/WhatWg/URLConstructorTest.php | 63 + .../url/tests/WhatWg/URLEncodedParserTest.php | 75 + .../rowbot/url/tests/WhatWg/URLOriginTest.php | 28 + .../WhatWg/URLSearchParamsAppendTest.php | 48 + .../WhatWg/URLSearchParamsConstructorTest.php | 275 + .../WhatWg/URLSearchParamsDeleteTest.php | 87 + .../WhatWg/URLSearchParamsForeachTest.php | 102 + .../WhatWg/URLSearchParamsGetAllTest.php | 42 + .../tests/WhatWg/URLSearchParamsGetTest.php | 37 + .../tests/WhatWg/URLSearchParamsHasTest.php | 51 + .../tests/WhatWg/URLSearchParamsSetTest.php | 63 + .../tests/WhatWg/URLSearchParamsSizeTest.php | 63 + .../tests/WhatWg/URLSearchParamsSortTest.php | 108 + .../WhatWg/URLSearchParamsStringifierTest.php | 175 + .../url/tests/WhatWg/URLSearchParamsTest.php | 87 + .../url/tests/WhatWg/URLSettersTest.php | 39 + .../tests/WhatWg/URLStaticsCanParseTest.php | 24 + .../rowbot/url/tests/WhatWg/URLToJSONTest.php | 24 + .../url/tests/WhatWg/WhatwgTestCase.php | 62 + .../symfony/polyfill-intl-normalizer/LICENSE | 19 + .../polyfill-intl-normalizer/Normalizer.php | 310 + .../polyfill-intl-normalizer/README.md | 14 + .../Resources/stubs/Normalizer.php | 17 + .../unidata/canonicalComposition.php | 945 ++ .../unidata/canonicalDecomposition.php | 2065 ++++ .../Resources/unidata/combiningClass.php | 876 ++ .../unidata/compatibilityDecomposition.php | 3695 +++++++ .../polyfill-intl-normalizer/bootstrap.php | 23 + .../polyfill-intl-normalizer/bootstrap80.php | 19 + .../polyfill-intl-normalizer/composer.json | 36 + 247 files changed, 50912 insertions(+) create mode 100644 transfer-protocol/.phpunit.result.cache create mode 100644 transfer-protocol/README.md create mode 100644 transfer-protocol/bootstrap.php create mode 100644 transfer-protocol/composer.json create mode 100644 transfer-protocol/composer.lock create mode 100644 transfer-protocol/iter.php create mode 100644 transfer-protocol/married.html create mode 100644 transfer-protocol/phpunit.xml create mode 100644 transfer-protocol/rewrite-urls.php create mode 100644 transfer-protocol/run-tests.sh create mode 100644 transfer-protocol/src/WP_Block_Markup_Processor.php create mode 100644 transfer-protocol/src/WP_Block_Markup_Url_Processor.php create mode 100644 transfer-protocol/tests/UrlParserTests.php create mode 100644 transfer-protocol/tests/WP_Block_Markup_Processor_Tests.php create mode 100644 transfer-protocol/tests/WP_Block_Markup_Url_Processor_Tests.php create mode 100644 transfer-protocol/tests/urltestdata.json create mode 100644 transfer-protocol/vendor/autoload.php create mode 100644 transfer-protocol/vendor/brick/math/CHANGELOG.md create mode 100644 transfer-protocol/vendor/brick/math/LICENSE create mode 100644 transfer-protocol/vendor/brick/math/SECURITY.md create mode 100644 transfer-protocol/vendor/brick/math/composer.json create mode 100644 transfer-protocol/vendor/brick/math/src/BigDecimal.php create mode 100644 transfer-protocol/vendor/brick/math/src/BigInteger.php create mode 100644 transfer-protocol/vendor/brick/math/src/BigNumber.php create mode 100644 transfer-protocol/vendor/brick/math/src/BigRational.php create mode 100644 transfer-protocol/vendor/brick/math/src/Exception/DivisionByZeroException.php create mode 100644 transfer-protocol/vendor/brick/math/src/Exception/IntegerOverflowException.php create mode 100644 transfer-protocol/vendor/brick/math/src/Exception/MathException.php create mode 100644 transfer-protocol/vendor/brick/math/src/Exception/NegativeNumberException.php create mode 100644 transfer-protocol/vendor/brick/math/src/Exception/NumberFormatException.php create mode 100644 transfer-protocol/vendor/brick/math/src/Exception/RoundingNecessaryException.php create mode 100644 transfer-protocol/vendor/brick/math/src/Internal/Calculator.php create mode 100644 transfer-protocol/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php create mode 100644 transfer-protocol/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php create mode 100644 transfer-protocol/vendor/brick/math/src/Internal/Calculator/NativeCalculator.php create mode 100644 transfer-protocol/vendor/brick/math/src/RoundingMode.php create mode 100644 transfer-protocol/vendor/composer/ClassLoader.php create mode 100644 transfer-protocol/vendor/composer/InstalledVersions.php create mode 100644 transfer-protocol/vendor/composer/LICENSE create mode 100644 transfer-protocol/vendor/composer/autoload_classmap.php create mode 100644 transfer-protocol/vendor/composer/autoload_files.php create mode 100644 transfer-protocol/vendor/composer/autoload_namespaces.php create mode 100644 transfer-protocol/vendor/composer/autoload_psr4.php create mode 100644 transfer-protocol/vendor/composer/autoload_real.php create mode 100644 transfer-protocol/vendor/composer/autoload_static.php create mode 100644 transfer-protocol/vendor/composer/installed.json create mode 100644 transfer-protocol/vendor/composer/installed.php create mode 100644 transfer-protocol/vendor/composer/platform_check.php create mode 100644 transfer-protocol/vendor/psr/log/LICENSE create mode 100644 transfer-protocol/vendor/psr/log/README.md create mode 100644 transfer-protocol/vendor/psr/log/composer.json create mode 100644 transfer-protocol/vendor/psr/log/src/AbstractLogger.php create mode 100644 transfer-protocol/vendor/psr/log/src/InvalidArgumentException.php create mode 100644 transfer-protocol/vendor/psr/log/src/LogLevel.php create mode 100644 transfer-protocol/vendor/psr/log/src/LoggerAwareInterface.php create mode 100644 transfer-protocol/vendor/psr/log/src/LoggerAwareTrait.php create mode 100644 transfer-protocol/vendor/psr/log/src/LoggerInterface.php create mode 100644 transfer-protocol/vendor/psr/log/src/LoggerTrait.php create mode 100644 transfer-protocol/vendor/psr/log/src/NullLogger.php create mode 100755 transfer-protocol/vendor/rowbot/idna/.gitattributes create mode 100644 transfer-protocol/vendor/rowbot/idna/.github/workflows/tests.yml create mode 100755 transfer-protocol/vendor/rowbot/idna/.gitignore create mode 100644 transfer-protocol/vendor/rowbot/idna/.phpcs.xml create mode 100644 transfer-protocol/vendor/rowbot/idna/CHANGELOG.md create mode 100755 transfer-protocol/vendor/rowbot/idna/LICENSE create mode 100644 transfer-protocol/vendor/rowbot/idna/README.md create mode 100644 transfer-protocol/vendor/rowbot/idna/bin/Builder.php create mode 100755 transfer-protocol/vendor/rowbot/idna/bin/IdnaDataBuilder.php create mode 100644 transfer-protocol/vendor/rowbot/idna/bin/RegexBuilder.php create mode 100644 transfer-protocol/vendor/rowbot/idna/bin/ViramaDataBuilder.php create mode 100755 transfer-protocol/vendor/rowbot/idna/bin/generateDataFiles.php create mode 100755 transfer-protocol/vendor/rowbot/idna/composer.json create mode 100644 transfer-protocol/vendor/rowbot/idna/phpstan.neon create mode 100644 transfer-protocol/vendor/rowbot/idna/phpunit.xml create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/DisallowedRanges.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/Regex.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/deviation.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/disallowed.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_mapped.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_valid.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/ignored.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/mapped.php create mode 100644 transfer-protocol/vendor/rowbot/idna/resources/virama.php create mode 100644 transfer-protocol/vendor/rowbot/idna/src/CodePoint.php create mode 100755 transfer-protocol/vendor/rowbot/idna/src/CodePointStatus.php create mode 100644 transfer-protocol/vendor/rowbot/idna/src/DomainInfo.php create mode 100644 transfer-protocol/vendor/rowbot/idna/src/Idna.php create mode 100644 transfer-protocol/vendor/rowbot/idna/src/IdnaResult.php create mode 100644 transfer-protocol/vendor/rowbot/idna/src/LabelValidator.php create mode 100755 transfer-protocol/vendor/rowbot/idna/tests/IdnaV2Test.php create mode 100644 transfer-protocol/vendor/rowbot/idna/tests/IdnaV2TestCase.php create mode 100755 transfer-protocol/vendor/rowbot/punycode/.gitattributes create mode 100644 transfer-protocol/vendor/rowbot/punycode/.github/workflows/tests.yml create mode 100755 transfer-protocol/vendor/rowbot/punycode/.gitignore create mode 100644 transfer-protocol/vendor/rowbot/punycode/.phpcs.xml create mode 100755 transfer-protocol/vendor/rowbot/punycode/CHANGELOG.md create mode 100755 transfer-protocol/vendor/rowbot/punycode/LICENSE create mode 100644 transfer-protocol/vendor/rowbot/punycode/README.md create mode 100755 transfer-protocol/vendor/rowbot/punycode/composer.json create mode 100644 transfer-protocol/vendor/rowbot/punycode/phpstan.neon create mode 100644 transfer-protocol/vendor/rowbot/punycode/phpunit.xml create mode 100644 transfer-protocol/vendor/rowbot/punycode/src/Exception/InvalidInputException.php create mode 100644 transfer-protocol/vendor/rowbot/punycode/src/Exception/OutputSizeExceededException.php create mode 100755 transfer-protocol/vendor/rowbot/punycode/src/Exception/OverflowException.php create mode 100755 transfer-protocol/vendor/rowbot/punycode/src/Exception/PunycodeException.php create mode 100755 transfer-protocol/vendor/rowbot/punycode/src/Punycode.php create mode 100644 transfer-protocol/vendor/rowbot/punycode/tests/PunycodeTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/.github/workflows/coverage.yml create mode 100644 transfer-protocol/vendor/rowbot/url/.github/workflows/tests.yml create mode 100644 transfer-protocol/vendor/rowbot/url/.gitignore create mode 100644 transfer-protocol/vendor/rowbot/url/.phpcs.xml create mode 100644 transfer-protocol/vendor/rowbot/url/CHANGELOG.md create mode 100644 transfer-protocol/vendor/rowbot/url/LICENSE create mode 100644 transfer-protocol/vendor/rowbot/url/README.md create mode 100644 transfer-protocol/vendor/rowbot/url/composer.json create mode 100644 transfer-protocol/vendor/rowbot/url/phpstan.neon create mode 100644 transfer-protocol/vendor/rowbot/url/phpunit.xml create mode 100644 transfer-protocol/vendor/rowbot/url/src/APIParserErrorType.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/APIParserResult.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/BasicURLParser.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/AbstractPath.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/AbstractHost.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/HostInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/HostParser.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4Address.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4AddressParser.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6Address.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6AddressParser.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/BrickMathAdapter.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/Exception/MathException.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/NativeIntAdapter.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/NumberFactory.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/NumberInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/NullHost.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/HostSerializerInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/IPv4AddressSerializer.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/IPv6AddressSerializer.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/StringHostSerializer.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Host/StringHost.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/OpaqueOrigin.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/OpaquePath.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/PathInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/PathList.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/PathSegment.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/QueryList.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/Scheme.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Component/TupleOrigin.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Exception/TypeError.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Exception/URLException.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Exception/UnsupportedOperationException.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Origin.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/ParserContext.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/ParserState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/AbstractHostState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/AuthorityState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/FileHostState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/FileSlashState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/FileState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/FragmentState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/HostState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/HostnameState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/NoSchemeState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/OpaquePathState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/PathOrAuthorityState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/PathStartState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/PathState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/PortState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/QueryState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/RelativeSlashState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/RelativeState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/SchemeStartState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/SchemeState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthorityIgnoreSlashesState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthoritySlashesState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/SpecialRelativeOrAuthorityState.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/State.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/State/StatusCode.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/AbstractStringBuffer.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/AbstractStringList.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/AbstractUSVString.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/CodePoint.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/EncodeSet.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/Exception/EncodingException.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/Exception/RegexException.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/Exception/UndefinedIndexException.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/PercentEncoder.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/StringBuffer.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/StringBufferInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/StringIteratorInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/StringList.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/StringListInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/USVStringInterface.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/Utf8String.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/String/Utf8StringIterator.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/Support/EncodingHelper.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/URL.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/URLRecord.php create mode 100644 transfer-protocol/vendor/rowbot/url/src/URLSearchParams.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/EncodingHelperTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/HostParserTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/Math/BrickMathAdapterTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/Math/MathTestCase.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/Math/NativeIntAdapterTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/NullHostTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/OriginTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/PathTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/QueryListTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/QueryStateTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/SchemeTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/StringsTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/URLRecordTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/URLSearchParamsTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/URLTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/ValidationErrorLogger.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/FailureTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/PercentEncodingTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/ToASCIIWindowTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLConstructorTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLEncodedParserTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLOriginTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsAppendTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsConstructorTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsDeleteTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsForeachTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetAllTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsHasTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSetTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSizeTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSortTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsStringifierTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSettersTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLStaticsCanParseTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLToJSONTest.php create mode 100644 transfer-protocol/vendor/rowbot/url/tests/WhatWg/WhatwgTestCase.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/LICENSE create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Normalizer.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/README.md create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php create mode 100644 transfer-protocol/vendor/symfony/polyfill-intl-normalizer/composer.json diff --git a/transfer-protocol/.phpunit.result.cache b/transfer-protocol/.phpunit.result.cache new file mode 100644 index 0000000..378e246 --- /dev/null +++ b/transfer-protocol/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":1,"defects":{"UrlParserTests::testParseUrl#HTTP scheme":7,"UrlParserTests::testParseUrl#Non-ASCII hostname":7,"UrlParserTests::testParseUrl#Slash in the hostname":7,"UrlParserTests::testParseUrl#non-protocol characters in the front":7,"UrlParserTests::testParsesIpUrl":7,"UrlParserTests::test_invalidates_non_urls#Invalid scheme":7,"UrlParserTests::test_invalidates_non_urls#Missing scheme-suffix":7,"UrlParserTests::test_invalidates_non_urls#Broken scheme-suffix":7,"UrlParserTests::test_invalidates_non_urls#Non-ASCII hostname":7,"UrlParserTests::test_invalidates_non_urls#Missing port number":7,"UrlParserTests::test_parse_url#0":7,"UrlParserTests::test_parse_url#1":8,"UrlParserTests::test_parse_url#2":8,"UrlParserTests::test_parse_url#3":8,"UrlParserTests::test_parse_url#4":8,"UrlParserTests::test_parse_url#5":8,"UrlParserTests::test_parse_url#11":7,"UrlParserTests::test_parse_url#296":7,"UrlParserTests::test_parse_url#69":7,"UrlParserTests::test_parse_url#96":7,"UrlParserTests::test_parse_url#97":7,"UrlParserTests::test_parse_url#98":7,"UrlParserTests::test_parse_url#99":7,"UrlParserTests::test_parse_url#100":7,"UrlParserTests::test_parse_url#101":7,"UrlParserTests::test_parse_url#102":7,"UrlParserTests::test_parse_url#103":7,"UrlParserTests::test_parse_url#104":7,"UrlParserTests::test_parse_url#105":7,"UrlParserTests::test_parse_url#106":7,"UrlParserTests::test_parse_url#107":7,"UrlParserTests::test_parse_url#108":7,"UrlParserTests::test_parse_url#109":7,"UrlParserTests::test_parse_url#110":7,"UrlParserTests::test_parse_url#111":7,"UrlParserTests::test_parse_url#112":7,"UrlParserTests::test_parse_url#113":7,"UrlParserTests::test_parse_url#114":7,"UrlParserTests::test_parse_url#115":7,"UrlParserTests::test_parse_url#116":7,"UrlParserTests::test_parse_url#117":7,"UrlParserTests::test_parse_url#118":7,"UrlParserTests::test_parse_url#119":7,"UrlParserTests::test_parse_url#186":7,"UrlParserTests::test_parse_url#232":7,"UrlParserTests::test_parse_url#233":7,"UrlParserTests::test_parse_url#234":7,"UrlParserTests::test_parse_url#235":7,"UrlParserTests::test_parse_url#236":7,"UrlParserTests::test_parse_url#289":7,"UrlParserTests::test_parse_url#297":7,"UrlParserTests::test_parse_url#298":7,"UrlParserTests::test_parse_url#299":7,"UrlParserTests::test_parse_url#300":7,"UrlParserTests::test_parse_url#301":7,"UrlParserTests::test_parse_url#333":7,"UrlParserTests::test_parse_url#334":7,"UrlParserTests::test_parse_url#336":7,"UrlParserTests::test_parse_url#337":7,"UrlParserTests::test_parse_url#338":7,"UrlParserTests::test_parse_url#339":7,"UrlParserTests::test_parse_url#340":7,"UrlParserTests::test_parse_url#341":7,"UrlParserTests::test_parse_url#342":7,"UrlParserTests::test_parse_url#343":7,"UrlParserTests::test_parse_url#344":7,"UrlParserTests::test_parse_url#345":7,"UrlParserTests::test_parse_url#346":7,"UrlParserTests::test_parse_url#347":7,"UrlParserTests::test_parse_url#348":7,"UrlParserTests::test_parse_url#349":7,"UrlParserTests::test_parse_url#350":7,"UrlParserTests::test_parse_url#351":7,"UrlParserTests::test_parse_url#352":7,"UrlParserTests::test_parse_url#353":7,"UrlParserTests::test_parse_url#354":7,"UrlParserTests::test_parse_url#355":7,"UrlParserTests::test_parse_url#356":7,"UrlParserTests::test_parse_url#357":7,"UrlParserTests::test_parse_url#358":7,"UrlParserTests::test_parse_url#359":7,"UrlParserTests::test_parse_url#360":7,"UrlParserTests::test_parse_url#361":7,"UrlParserTests::test_parse_url#362":7,"UrlParserTests::test_parse_url#363":7,"UrlParserTests::test_parse_url#364":7,"UrlParserTests::test_parse_url#365":7,"UrlParserTests::test_parse_url#366":7,"UrlParserTests::test_parse_url#367":7,"UrlParserTests::test_parse_url#368":7,"UrlParserTests::test_parse_url#369":7,"UrlParserTests::test_parse_url#370":7,"UrlParserTests::test_parse_url#371":7,"UrlParserTests::test_parse_url#372":7,"UrlParserTests::test_parse_url#373":7,"UrlParserTests::test_parse_url#374":7,"UrlParserTests::test_parse_url#375":7,"UrlParserTests::test_parse_url#376":7,"UrlParserTests::test_parse_url#377":7,"UrlParserTests::test_parse_url#378":7,"UrlParserTests::test_parse_url#379":7,"UrlParserTests::test_parse_url#380":7,"UrlParserTests::test_parse_url#381":7,"UrlParserTests::test_parse_url#382":7,"UrlParserTests::test_parse_url#383":7,"UrlParserTests::test_parse_url#384":7,"UrlParserTests::test_parse_url#385":7,"UrlParserTests::test_parse_url#386":7,"UrlParserTests::test_parse_url#387":7,"UrlParserTests::test_parse_url#388":7,"UrlParserTests::test_parse_url#389":7,"UrlParserTests::test_parse_url#390":7,"UrlParserTests::test_parse_url#391":7,"UrlParserTests::test_parse_url#392":7,"UrlParserTests::test_parse_url#393":7,"UrlParserTests::test_parse_url#394":7,"UrlParserTests::test_parse_url#395":7,"UrlParserTests::test_parse_url#396":7,"UrlParserTests::test_parse_url#397":7,"UrlParserTests::test_parse_url#398":7,"UrlParserTests::test_parse_url#399":7,"UrlParserTests::test_parse_url#400":7,"UrlParserTests::test_parse_url#401":7,"UrlParserTests::test_parse_url#402":7,"UrlParserTests::test_parse_url#403":7,"UrlParserTests::test_parse_url#404":7,"UrlParserTests::test_parse_url#405":7,"UrlParserTests::test_parse_url#406":7,"UrlParserTests::test_parse_url#407":7,"UrlParserTests::test_parse_url#408":7,"UrlParserTests::test_parse_url#409":7,"UrlParserTests::test_parse_url#410":7,"UrlParserTests::test_parse_url#411":7,"UrlParserTests::test_parse_url#412":7,"UrlParserTests::test_parse_url#413":7,"UrlParserTests::test_parse_url#414":7,"UrlParserTests::test_parse_url#415":7,"UrlParserTests::test_parse_url#416":7,"UrlParserTests::test_parse_url#423":7,"UrlParserTests::test_parse_url#424":7,"UrlParserTests::test_parse_url#425":7,"UrlParserTests::test_parse_url#426":7,"UrlParserTests::test_parse_url#427":7,"UrlParserTests::test_parse_url#440":7,"UrlParserTests::test_parse_url#441":7,"UrlParserTests::test_parse_url#442":7,"UrlParserTests::test_parse_url#443":7,"UrlParserTests::test_parse_url#444":7,"UrlParserTests::test_parse_url#445":7,"UrlParserTests::test_parse_url#446":7,"UrlParserTests::test_parse_url#447":7,"UrlParserTests::test_parse_url#448":7,"UrlParserTests::test_parse_url#449":7,"UrlParserTests::test_parse_url#450":7,"UrlParserTests::test_parse_url#451":7,"UrlParserTests::test_parse_url#452":7,"UrlParserTests::test_parse_url#453":7,"UrlParserTests::test_parse_url#454":7,"UrlParserTests::test_parse_url#455":7,"UrlParserTests::test_parse_url#456":7,"UrlParserTests::test_parse_url#457":7,"UrlParserTests::test_parse_url#465":7,"UrlParserTests::test_parse_url#470":7,"UrlParserTests::test_parse_url#471":7,"UrlParserTests::test_parse_url#472":7,"UrlParserTests::test_parse_url#473":7,"UrlParserTests::test_parse_url#474":7,"UrlParserTests::test_parse_url#475":7,"UrlParserTests::test_parse_url#476":7,"UrlParserTests::test_parse_url#477":7,"UrlParserTests::test_parse_url#478":7,"UrlParserTests::test_parse_url#479":7,"UrlParserTests::test_parse_url#480":7,"UrlParserTests::test_parse_url#481":7,"UrlParserTests::test_parse_url#482":7,"UrlParserTests::test_parse_url#483":7,"UrlParserTests::test_parse_url#484":7,"UrlParserTests::test_parse_url#485":7,"UrlParserTests::test_parse_url#486":7,"UrlParserTests::test_parse_url#487":7,"UrlParserTests::test_parse_url#488":7,"UrlParserTests::test_parse_url#489":7,"UrlParserTests::test_parse_url#490":7,"UrlParserTests::test_parse_url#491":7,"UrlParserTests::test_parse_url#492":7,"UrlParserTests::test_parse_url#493":7,"UrlParserTests::test_parse_url#494":7,"UrlParserTests::test_parse_url#495":7,"UrlParserTests::test_parse_url#496":7,"UrlParserTests::test_parse_url#512":7,"UrlParserTests::test_parse_url#513":7,"UrlParserTests::test_parse_url#514":7,"UrlParserTests::test_parse_url#515":7,"UrlParserTests::test_parse_url#516":7,"UrlParserTests::test_parse_url#517":7,"UrlParserTests::test_parse_url#518":7,"UrlParserTests::test_parse_url#519":7,"UrlParserTests::test_parse_url#520":7,"UrlParserTests::test_parse_url#521":7,"UrlParserTests::test_parse_url#522":7,"UrlParserTests::test_parse_url#523":7,"UrlParserTests::test_parse_url#524":7,"UrlParserTests::test_parse_url#525":7,"UrlParserTests::test_parse_url#526":7,"UrlParserTests::test_parse_url#527":7,"UrlParserTests::test_parse_url#528":7,"UrlParserTests::test_parse_url#529":7,"UrlParserTests::test_parse_url#530":7,"UrlParserTests::test_parse_url#556":7,"UrlParserTests::test_parse_url#557":7,"UrlParserTests::test_parse_url#558":7,"UrlParserTests::test_parse_url#559":7,"UrlParserTests::test_parse_url#560":7,"UrlParserTests::test_parse_url#561":7,"UrlParserTests::test_parse_url#562":7,"UrlParserTests::test_parse_url#563":7,"UrlParserTests::test_parse_url#564":7,"UrlParserTests::test_parse_url#565":7,"UrlParserTests::test_parse_url#566":7,"UrlParserTests::test_parse_invalid_url#0":7,"UrlParserTests::test_parse_invalid_url#1":7,"UrlParserTests::test_parse_invalid_url#2":7,"UrlParserTests::test_parse_invalid_url#3":7,"UrlParserTests::test_parse_invalid_url#4":7,"UrlParserTests::test_parse_invalid_url#5":7,"UrlParserTests::test_parse_invalid_url#6":7,"UrlParserTests::test_parse_invalid_url#7":7,"UrlParserTests::test_parse_invalid_url#8":7,"UrlParserTests::test_parse_invalid_url#9":7,"UrlParserTests::test_parse_invalid_url#10":7,"UrlParserTests::test_parse_invalid_url#11":7,"UrlParserTests::test_parse_invalid_url#12":7,"UrlParserTests::test_parse_invalid_url#13":7,"UrlParserTests::test_parse_invalid_url#14":7,"UrlParserTests::test_parse_invalid_url#15":7,"UrlParserTests::test_parse_invalid_url#16":7,"UrlParserTests::test_parse_invalid_url#17":7,"UrlParserTests::test_parse_invalid_url#18":7,"UrlParserTests::test_parse_invalid_url#19":7,"UrlParserTests::test_parse_invalid_url#20":7,"UrlParserTests::test_parse_invalid_url#21":7,"UrlParserTests::test_parse_invalid_url#22":7,"UrlParserTests::test_parse_invalid_url#23":7,"UrlParserTests::test_parse_invalid_url#24":7,"UrlParserTests::test_parse_invalid_url#25":7,"UrlParserTests::test_parse_invalid_url#26":7,"UrlParserTests::test_parse_invalid_url#27":7,"UrlParserTests::test_parse_invalid_url#28":7,"UrlParserTests::test_parse_invalid_url#29":7,"UrlParserTests::test_parse_invalid_url#30":7,"UrlParserTests::test_parse_invalid_url#31":7,"UrlParserTests::test_parse_invalid_url#32":7,"UrlParserTests::test_parse_invalid_url#33":7,"UrlParserTests::test_parse_invalid_url#34":7,"UrlParserTests::test_parse_invalid_url#35":7,"UrlParserTests::test_parse_invalid_url#36":7,"UrlParserTests::test_parse_invalid_url#37":7,"UrlParserTests::test_parse_invalid_url#38":7,"UrlParserTests::test_parse_invalid_url#39":7,"UrlParserTests::test_parse_invalid_url#40":7,"UrlParserTests::test_parse_invalid_url#41":7,"UrlParserTests::test_parse_invalid_url#42":7,"UrlParserTests::test_parse_invalid_url#43":7,"UrlParserTests::test_parse_invalid_url#44":7,"UrlParserTests::test_parse_invalid_url#45":7,"UrlParserTests::test_parse_invalid_url#46":7,"UrlParserTests::test_parse_invalid_url#47":7,"UrlParserTests::test_parse_invalid_url#48":7,"UrlParserTests::test_parse_invalid_url#49":7,"UrlParserTests::test_parse_invalid_url#50":7,"UrlParserTests::test_parse_invalid_url#51":7,"UrlParserTests::test_parse_invalid_url#52":7,"UrlParserTests::test_parse_invalid_url#53":7,"UrlParserTests::test_parse_invalid_url#54":7,"UrlParserTests::test_parse_invalid_url#55":7,"UrlParserTests::test_parse_invalid_url#56":7,"UrlParserTests::test_parse_invalid_url#57":7,"UrlParserTests::test_parse_invalid_url#58":7,"UrlParserTests::test_parse_invalid_url#59":7,"UrlParserTests::test_parse_invalid_url#60":7,"UrlParserTests::test_parse_invalid_url#61":7,"UrlParserTests::test_parse_invalid_url#62":7,"UrlParserTests::test_parse_invalid_url#63":7,"UrlParserTests::test_parse_invalid_url#64":7,"UrlParserTests::test_parse_invalid_url#65":7,"UrlParserTests::test_parse_invalid_url#66":7,"UrlParserTests::test_parse_invalid_url#67":7,"UrlParserTests::test_parse_invalid_url#68":7,"UrlParserTests::test_parse_invalid_url#69":7,"UrlParserTests::test_parse_invalid_url#70":7,"UrlParserTests::test_parse_invalid_url#71":7,"UrlParserTests::test_parse_invalid_url#72":7,"UrlParserTests::test_parse_invalid_url#73":7,"UrlParserTests::test_parse_invalid_url#74":7,"UrlParserTests::test_parse_invalid_url#75":7,"UrlParserTests::test_parse_invalid_url#76":7,"UrlParserTests::test_parse_invalid_url#77":7,"UrlParserTests::test_parse_invalid_url#78":7,"UrlParserTests::test_parse_invalid_url#79":7,"UrlParserTests::test_parse_invalid_url#80":7,"UrlParserTests::test_parse_invalid_url#81":7,"UrlParserTests::test_parse_invalid_url#82":7,"UrlParserTests::test_parse_invalid_url#83":7,"UrlParserTests::test_parse_invalid_url#84":7,"UrlParserTests::test_parse_invalid_url#85":7,"UrlParserTests::test_parse_invalid_url#86":7,"UrlParserTests::test_parse_invalid_url#87":7,"UrlParserTests::test_parse_invalid_url#88":7,"UrlParserTests::test_parse_invalid_url#89":7,"UrlParserTests::test_parse_invalid_url#90":7,"UrlParserTests::test_parse_invalid_url#91":7,"UrlParserTests::test_parse_invalid_url#92":7,"UrlParserTests::test_parse_invalid_url#93":7,"UrlParserTests::test_parse_invalid_url#94":7,"UrlParserTests::test_parse_invalid_url#95":7,"UrlParserTests::test_parse_invalid_url#96":7,"UrlParserTests::test_parse_invalid_url#97":7,"UrlParserTests::test_parse_invalid_url#98":7,"UrlParserTests::test_parse_invalid_url#99":7,"UrlParserTests::test_parse_invalid_url#100":7,"UrlParserTests::test_parse_invalid_url#101":7,"UrlParserTests::test_parse_invalid_url#102":7,"UrlParserTests::test_parse_invalid_url#103":7,"UrlParserTests::test_parse_invalid_url#104":7,"UrlParserTests::test_parse_invalid_url#105":7,"UrlParserTests::test_parse_invalid_url#106":7,"UrlParserTests::test_parse_invalid_url#107":7,"UrlParserTests::test_parse_invalid_url#108":7,"UrlParserTests::test_parse_invalid_url#109":7,"UrlParserTests::test_parse_invalid_url#110":7,"UrlParserTests::test_parse_invalid_url#111":7,"UrlParserTests::test_parse_invalid_url#112":7,"UrlParserTests::test_parse_invalid_url#113":7,"UrlParserTests::test_parse_invalid_url#114":7,"UrlParserTests::test_parse_invalid_url#115":7,"UrlParserTests::test_parse_invalid_url#116":7,"UrlParserTests::test_parse_invalid_url#117":7,"UrlParserTests::test_parse_invalid_url#118":7,"UrlParserTests::test_parse_invalid_url#119":7,"UrlParserTests::test_parse_invalid_url#120":7,"UrlParserTests::test_parse_invalid_url#121":7,"UrlParserTests::test_parse_invalid_url#122":7,"UrlParserTests::test_parse_invalid_url#123":7,"UrlParserTests::test_parse_invalid_url#124":7,"UrlParserTests::test_parse_invalid_url#125":7,"UrlParserTests::test_parse_invalid_url#126":7,"UrlParserTests::test_parse_invalid_url#127":7,"UrlParserTests::test_parse_invalid_url#128":7,"UrlParserTests::test_parse_invalid_url#129":7,"UrlParserTests::test_parse_invalid_url#130":7,"UrlParserTests::test_parse_invalid_url#131":7,"UrlParserTests::test_parse_invalid_url#132":7,"UrlParserTests::test_parse_invalid_url#133":7,"UrlParserTests::test_parse_invalid_url#134":7,"UrlParserTests::test_parse_invalid_url#135":7,"UrlParserTests::test_parse_invalid_url#136":7,"UrlParserTests::test_parse_invalid_url#137":7,"UrlParserTests::test_parse_invalid_url#138":7,"UrlParserTests::test_parse_invalid_url#139":7,"UrlParserTests::test_parse_invalid_url#140":7,"UrlParserTests::test_parse_invalid_url#141":7,"UrlParserTests::test_parse_invalid_url#142":7,"UrlParserTests::test_parse_invalid_url#143":7,"UrlParserTests::test_parse_invalid_url#144":7,"UrlParserTests::test_parse_invalid_url#145":7,"UrlParserTests::test_parse_invalid_url#146":7,"UrlParserTests::test_parse_invalid_url#147":7,"UrlParserTests::test_parse_invalid_url#148":7,"UrlParserTests::test_parse_invalid_url#149":7,"UrlParserTests::test_parse_invalid_url#150":7,"UrlParserTests::test_parse_invalid_url#151":7,"UrlParserTests::test_parse_invalid_url#152":7,"UrlParserTests::test_parse_invalid_url#153":7,"UrlParserTests::test_parse_invalid_url#154":7,"UrlParserTests::test_parse_invalid_url#155":7,"UrlParserTests::test_parse_invalid_url#156":7,"UrlParserTests::test_parse_invalid_url#157":7,"UrlParserTests::test_parse_invalid_url#158":7,"UrlParserTests::test_parse_invalid_url#159":7,"UrlParserTests::test_parse_invalid_url#160":7,"UrlParserTests::test_parse_invalid_url#161":7,"UrlParserTests::test_parse_invalid_url#162":7,"UrlParserTests::test_parse_invalid_url#163":7,"UrlParserTests::test_parse_invalid_url#164":7,"UrlParserTests::test_parse_invalid_url#165":7,"UrlParserTests::test_parse_invalid_url#166":7,"UrlParserTests::test_parse_invalid_url#167":7,"UrlParserTests::test_parse_invalid_url#168":7,"UrlParserTests::test_parse_invalid_url#169":7,"UrlParserTests::test_parse_invalid_url#170":7,"UrlParserTests::test_parse_invalid_url#171":7,"UrlParserTests::test_parse_invalid_url#172":7,"UrlParserTests::test_parse_invalid_url#173":7,"UrlParserTests::test_parse_invalid_url#174":7,"UrlParserTests::test_parse_invalid_url#175":7,"UrlParserTests::test_parse_invalid_url#176":7,"UrlParserTests::test_parse_invalid_url#177":7,"UrlParserTests::test_parse_invalid_url#178":7,"UrlParserTests::test_parse_invalid_url#179":7,"UrlParserTests::test_parse_invalid_url#180":7,"UrlParserTests::test_parse_invalid_url#181":7,"UrlParserTests::test_parse_invalid_url#182":7,"UrlParserTests::test_parse_invalid_url#183":7,"UrlParserTests::test_parse_invalid_url#184":7,"UrlParserTests::test_parse_invalid_url#185":7,"UrlParserTests::test_parse_invalid_url#186":7,"UrlParserTests::test_parse_invalid_url#187":7,"UrlParserTests::test_parse_invalid_url#188":7,"UrlParserTests::test_parse_invalid_url#189":7,"UrlParserTests::test_parse_invalid_url#190":7,"UrlParserTests::test_parse_invalid_url#191":7,"UrlParserTests::test_parse_invalid_url#192":7,"UrlParserTests::test_parse_invalid_url#193":7,"UrlParserTests::test_parse_invalid_url#194":7,"UrlParserTests::test_parse_invalid_url#195":7,"UrlParserTests::test_parse_invalid_url#196":7,"UrlParserTests::test_parse_invalid_url#197":7,"UrlParserTests::test_parse_invalid_url#198":7,"UrlParserTests::test_parse_invalid_url#199":7,"UrlParserTests::test_parse_invalid_url#200":7,"UrlParserTests::test_parse_invalid_url#201":7,"UrlParserTests::test_parse_invalid_url#202":7,"UrlParserTests::test_parse_invalid_url#203":7,"UrlParserTests::test_parse_invalid_url#204":7,"UrlParserTests::test_parse_invalid_url#205":7,"UrlParserTests::test_parse_invalid_url#206":7,"UrlParserTests::test_parse_invalid_url#207":7,"UrlParserTests::test_parse_invalid_url#208":7,"UrlParserTests::test_parse_invalid_url#209":7,"UrlParserTests::test_parse_invalid_url#210":7,"UrlParserTests::test_parse_invalid_url#211":7,"UrlParserTests::test_parse_invalid_url#212":7,"UrlParserTests::test_parse_invalid_url#213":7,"UrlParserTests::test_parse_invalid_url#214":7,"UrlParserTests::test_parse_invalid_url#215":7,"UrlParserTests::test_parse_invalid_url#216":7,"UrlParserTests::test_parse_invalid_url#217":7,"UrlParserTests::test_parse_invalid_url#218":7,"UrlParserTests::test_parse_invalid_url#219":7,"UrlParserTests::test_parse_invalid_url#220":7,"UrlParserTests::test_parse_invalid_url#221":7,"UrlParserTests::test_parse_invalid_url#222":7,"UrlParserTests::test_parse_invalid_url#223":7,"UrlParserTests::test_parse_invalid_url#224":7,"UrlParserTests::test_parse_invalid_url#225":7,"UrlParserTests::test_parse_invalid_url#226":7,"UrlParserTests::test_parse_invalid_url#227":7,"UrlParserTests::test_parse_invalid_url#228":7,"UrlParserTests::test_parse_invalid_url#229":7,"UrlParserTests::test_parse_invalid_url#230":7,"UrlParserTests::test_parse_invalid_url#231":7,"UrlParserTests::test_parse_invalid_url#232":7,"UrlParserTests::test_parse_invalid_url#233":7,"UrlParserTests::test_parse_invalid_url#234":7,"UrlParserTests::test_parse_invalid_url#235":7,"UrlParserTests::test_parse_invalid_url#236":7,"UrlParserTests::test_parse_invalid_url#237":7,"UrlParserTests::test_parse_invalid_url#238":7,"UrlParserTests::test_parse_invalid_url#239":7,"UrlParserTests::test_parse_invalid_url#240":7,"UrlParserTests::test_parse_invalid_url#241":7,"UrlParserTests::test_parse_invalid_url#242":7,"UrlParserTests::test_parse_invalid_url#243":7,"UrlParserTests::test_parse_invalid_url#244":7,"UrlParserTests::test_parse_invalid_url#245":7,"UrlParserTests::test_parse_invalid_url#246":7,"UrlParserTests::test_parse_invalid_url#247":7,"UrlParserTests::test_parse_invalid_url#248":7,"UrlParserTests::test_parse_invalid_url#249":7,"UrlParserTests::test_parse_invalid_url#250":7,"UrlParserTests::test_parse_invalid_url#251":7,"UrlParserTests::test_parse_invalid_url#252":7,"UrlParserTests::test_parse_invalid_url#253":7,"UrlParserTests::test_parse_invalid_url#254":7,"UrlParserTests::test_parse_invalid_url#255":7,"UrlParserTests::test_parse_invalid_url#256":7,"UrlParserTests::test_parse_invalid_url#257":7,"UrlParserTests::test_parse_invalid_url#258":7,"UrlParserTests::test_parse_invalid_url#259":7,"UrlParserTests::test_parse_invalid_url#260":7,"UrlParserTests::test_parse_invalid_url#261":7,"UrlParserTests::test_parse_invalid_url#262":7,"UrlParserTests::test_parse_invalid_url#263":7,"UrlParserTests::test_parse_invalid_url#264":7,"UrlParserTests::test_parse_invalid_url#265":7,"UrlParserTests::test_parse_invalid_url#266":7,"UrlParserTests::test_parse_invalid_url#267":7,"UrlParserTests::test_parse_invalid_url#268":7,"UrlParserTests::test_parse_invalid_url#269":7,"UrlParserTests::test_parse_invalid_url#270":7,"UrlParserTests::test_parse_invalid_url#271":7,"UrlParserTests::test_parse_invalid_url#272":7,"UrlParserTests::test_parse_invalid_url#273":7,"UrlParserTests::test_parse_invalid_url#274":7,"UrlParserTests::test_parse_invalid_url#275":7,"UrlParserTests::test_parse_invalid_url#276":7,"UrlParserTests::test_parse_invalid_url#277":7,"UrlParserTests::test_parse_invalid_url#278":7,"UrlParserTests::test_parse_invalid_url#279":7,"UrlParserTests::test_parse_invalid_url#280":7,"UrlParserTests::test_parse_invalid_url#281":7,"UrlParserTests::test_parse_invalid_url#282":7,"UrlParserTests::test_parse_invalid_url#283":7,"UrlParserTests::test_parse_invalid_url#284":7,"UrlParserTests::test_parse_invalid_url#285":7,"UrlParserTests::test_parse_invalid_url#286":7,"UrlParserTests::test_parse_invalid_url#287":7,"UrlParserTests::test_parse_invalid_url#288":7,"UrlParserTests::test_parse_invalid_url#289":7,"UrlParserTests::test_parse_invalid_url#290":7,"UrlParserTests::test_parse_invalid_url#291":7,"UrlParserTests::test_parse_invalid_url#292":7,"UrlParserTests::test_parse_invalid_url#293":7,"UrlParserTests::test_parse_invalid_url#294":7,"UrlParserTests::test_parse_invalid_url#295":7,"UrlParserTests::test_parse_invalid_url#296":7,"UrlParserTests::test_parse_invalid_url#297":7,"UrlParserTests::test_parse_invalid_url#298":7,"UrlParserTests::test_parse_invalid_url#299":7,"UrlParserTests::test_parse_invalid_url#300":7,"UrlParserTests::test_parse_invalid_url#301":7,"UrlParserTests::test_parse_invalid_url#302":7,"UrlParserTests::test_parse_invalid_url#303":7,"UrlParserTests::test_parse_invalid_url#304":7,"UrlParserTests::test_parse_invalid_url#305":7,"UrlParserTests::test_parse_invalid_url#306":7,"UrlParserTests::test_parse_invalid_url#307":7,"UrlParserTests::test_parse_invalid_url#308":7,"UrlParserTests::test_parse_invalid_url#309":7,"UrlParserTests::test_parse_invalid_url#310":7,"UrlParserTests::test_parse_invalid_url#311":7,"UrlParserTests::test_parse_invalid_url#312":7,"UrlParserTests::test_parse_invalid_url#313":7,"UrlParserTests::test_parse_invalid_url#314":7,"UrlParserTests::test_parse_invalid_url#315":7,"UrlParserTests::test_parse_invalid_url#316":7,"UrlParserTests::test_parse_invalid_url#317":7,"UrlParserTests::test_parse_invalid_url#318":7,"UrlParserTests::test_parse_invalid_url#319":7,"UrlParserTests::test_parse_invalid_url#320":7,"UrlParserTests::test_parse_invalid_url#321":7,"UrlParserTests::test_parse_invalid_url#322":7,"UrlParserTests::test_parse_invalid_url#323":7,"UrlParserTests::test_parse_invalid_url#324":7,"UrlParserTests::test_parse_invalid_url#325":7,"UrlParserTests::test_parse_invalid_url#326":7,"UrlParserTests::test_parse_invalid_url#327":7,"UrlParserTests::test_parse_invalid_url#328":7,"UrlParserTests::test_parse_invalid_url#329":7,"UrlParserTests::test_parse_invalid_url#330":7,"UrlParserTests::test_parse_invalid_url#331":7,"UrlParserTests::test_parse_invalid_url#332":7,"UrlParserTests::test_parse_invalid_url#333":7,"UrlParserTests::test_parse_invalid_url#334":7,"UrlParserTests::test_parse_invalid_url#335":7,"UrlParserTests::test_parse_invalid_url#336":7,"UrlParserTests::test_parse_invalid_url#337":7,"UrlParserTests::test_parse_invalid_url#338":7,"UrlParserTests::test_parse_invalid_url#339":7,"UrlParserTests::test_parse_invalid_url#340":7,"UrlParserTests::test_parse_invalid_url#341":7,"UrlParserTests::test_parse_invalid_url#342":7,"UrlParserTests::test_parse_invalid_url#343":7,"UrlParserTests::test_parse_invalid_url#344":7,"UrlParserTests::test_parse_invalid_url#345":7,"UrlParserTests::test_parse_invalid_url#346":7,"UrlParserTests::test_parse_invalid_url#347":7,"UrlParserTests::test_parse_invalid_url#348":7,"UrlParserTests::test_parse_invalid_url#349":7,"UrlParserTests::test_parse_invalid_url#350":7,"UrlParserTests::test_parse_invalid_url#351":7,"UrlParserTests::test_parse_invalid_url#352":7,"UrlParserTests::test_parse_invalid_url#353":7,"UrlParserTests::test_parse_invalid_url#354":7,"UrlParserTests::test_parse_invalid_url#355":7,"UrlParserTests::test_parse_invalid_url#356":7,"UrlParserTests::test_parse_invalid_url#357":7,"UrlParserTests::test_parse_invalid_url#358":7,"UrlParserTests::test_parse_invalid_url#359":7,"UrlParserTests::test_parse_invalid_url#360":7,"UrlParserTests::test_parse_invalid_url#361":7,"UrlParserTests::test_parse_invalid_url#362":7,"UrlParserTests::test_parse_invalid_url#363":7,"UrlParserTests::test_parse_invalid_url#364":7,"UrlParserTests::test_parse_invalid_url#365":7,"UrlParserTests::test_parse_invalid_url#366":7,"UrlParserTests::test_parse_invalid_url#367":7,"UrlParserTests::test_parse_invalid_url#368":7,"UrlParserTests::test_parse_invalid_url#369":7,"UrlParserTests::test_parse_invalid_url#370":7,"UrlParserTests::test_parse_invalid_url#371":7,"UrlParserTests::test_parse_invalid_url#372":7,"UrlParserTests::test_parse_invalid_url#373":7,"UrlParserTests::test_parse_invalid_url#374":7,"UrlParserTests::test_parse_invalid_url#375":7,"UrlParserTests::test_parse_invalid_url#376":7,"UrlParserTests::test_parse_invalid_url#377":7,"UrlParserTests::test_parse_invalid_url#378":7,"UrlParserTests::test_parse_invalid_url#379":7,"UrlParserTests::test_parse_invalid_url#380":7,"UrlParserTests::test_parse_invalid_url#381":7,"UrlParserTests::test_parse_invalid_url#382":7,"UrlParserTests::test_parse_invalid_url#383":7,"UrlParserTests::test_parse_invalid_url#384":7,"UrlParserTests::test_parse_invalid_url#385":7,"UrlParserTests::test_parse_invalid_url#386":7,"UrlParserTests::test_parse_invalid_url#387":7,"UrlParserTests::test_parse_invalid_url#388":7,"UrlParserTests::test_parse_invalid_url#389":7,"UrlParserTests::test_parse_invalid_url#390":7,"UrlParserTests::test_parse_invalid_url#391":7,"UrlParserTests::test_parse_invalid_url#392":7,"UrlParserTests::test_parse_invalid_url#393":7,"UrlParserTests::test_parse_invalid_url#394":7,"UrlParserTests::test_parse_invalid_url#395":7,"UrlParserTests::test_parse_invalid_url#396":7,"UrlParserTests::test_parse_invalid_url#397":7,"UrlParserTests::test_parse_invalid_url#398":7,"UrlParserTests::test_parse_invalid_url#399":7,"UrlParserTests::test_parse_invalid_url#400":7,"UrlParserTests::test_parse_invalid_url#401":7,"UrlParserTests::test_parse_invalid_url#402":7,"UrlParserTests::test_parse_invalid_url#403":7,"UrlParserTests::test_parse_invalid_url#404":7,"UrlParserTests::test_parse_invalid_url#405":7,"UrlParserTests::test_parse_invalid_url#406":7,"UrlParserTests::test_parse_invalid_url#407":7,"UrlParserTests::test_parse_invalid_url#408":7,"UrlParserTests::test_parse_invalid_url#409":7,"UrlParserTests::test_parse_invalid_url#410":7,"UrlParserTests::test_parse_invalid_url#411":7,"UrlParserTests::test_parse_invalid_url#412":7,"UrlParserTests::test_parse_invalid_url#413":7,"UrlParserTests::test_parse_invalid_url#414":7,"UrlParserTests::test_parse_invalid_url#415":7,"UrlParserTests::test_parse_invalid_url#416":7,"UrlParserTests::test_parse_invalid_url#417":7,"UrlParserTests::test_parse_invalid_url#418":7,"UrlParserTests::test_parse_invalid_url#419":7,"UrlParserTests::test_parse_invalid_url#420":7,"UrlParserTests::test_parse_invalid_url#421":7,"UrlParserTests::test_parse_invalid_url#422":7,"UrlParserTests::test_parse_invalid_url#423":7,"UrlParserTests::test_parse_invalid_url#424":7,"UrlParserTests::test_parse_invalid_url#425":7,"UrlParserTests::test_parse_invalid_url#426":7,"UrlParserTests::test_parse_invalid_url#427":7,"UrlParserTests::test_parse_invalid_url#428":7,"UrlParserTests::test_parse_invalid_url#429":7,"UrlParserTests::test_parse_invalid_url#430":7,"UrlParserTests::test_parse_invalid_url#431":7,"UrlParserTests::test_parse_invalid_url#432":7,"UrlParserTests::test_parse_invalid_url#433":7,"UrlParserTests::test_parse_invalid_url#434":7,"UrlParserTests::test_parse_invalid_url#435":7,"UrlParserTests::test_parse_invalid_url#436":7,"UrlParserTests::test_parse_invalid_url#437":7,"UrlParserTests::test_parse_invalid_url#438":7,"UrlParserTests::test_parse_invalid_url#439":7,"UrlParserTests::test_parse_invalid_url#440":7,"UrlParserTests::test_parse_invalid_url#441":7,"UrlParserTests::test_parse_invalid_url#442":7,"UrlParserTests::test_parse_invalid_url#443":7,"UrlParserTests::test_parse_invalid_url#444":7,"UrlParserTests::test_parse_invalid_url#445":7,"UrlParserTests::test_parse_invalid_url#446":7,"UrlParserTests::test_parse_invalid_url#447":7,"UrlParserTests::test_parse_invalid_url#448":7,"UrlParserTests::test_parse_invalid_url#449":7,"UrlParserTests::test_parse_invalid_url#450":7,"UrlParserTests::test_parse_invalid_url#451":7,"UrlParserTests::test_parse_invalid_url#452":7,"UrlParserTests::test_parse_invalid_url#453":7,"UrlParserTests::test_parse_invalid_url#454":7,"UrlParserTests::test_parse_invalid_url#455":7,"UrlParserTests::test_parse_invalid_url#456":7,"UrlParserTests::test_parse_invalid_url#457":7,"UrlParserTests::test_parse_invalid_url#458":7,"UrlParserTests::test_parse_invalid_url#459":7,"UrlParserTests::test_parse_invalid_url#460":7,"UrlParserTests::test_parse_invalid_url#461":7,"UrlParserTests::test_parse_invalid_url#462":7,"UrlParserTests::test_parse_invalid_url#463":7,"UrlParserTests::test_parse_invalid_url#464":7,"UrlParserTests::test_parse_invalid_url#465":7,"UrlParserTests::test_parse_invalid_url#466":7,"UrlParserTests::test_parse_invalid_url#467":7,"UrlParserTests::test_parse_invalid_url#468":7,"UrlParserTests::test_parse_invalid_url#469":7,"UrlParserTests::test_parse_invalid_url#470":7,"UrlParserTests::test_parse_invalid_url#471":7,"UrlParserTests::test_parse_invalid_url#472":7,"UrlParserTests::test_parse_invalid_url#473":7,"UrlParserTests::test_parse_invalid_url#474":7,"UrlParserTests::test_parse_invalid_url#475":7,"UrlParserTests::test_parse_invalid_url#476":7,"UrlParserTests::test_parse_invalid_url#477":7,"UrlParserTests::test_parse_invalid_url#478":7,"UrlParserTests::test_parse_invalid_url#479":7,"UrlParserTests::test_parse_invalid_url#480":7,"UrlParserTests::test_parse_invalid_url#481":7,"UrlParserTests::test_parse_invalid_url#482":7,"UrlParserTests::test_parse_invalid_url#483":7,"UrlParserTests::test_parse_invalid_url#484":7,"UrlParserTests::test_parse_invalid_url#485":7,"UrlParserTests::test_parse_invalid_url#486":7,"UrlParserTests::test_parse_invalid_url#487":7,"UrlParserTests::test_parse_invalid_url#488":7,"UrlParserTests::test_parse_invalid_url#489":7,"UrlParserTests::test_parse_invalid_url#490":7,"UrlParserTests::test_parse_invalid_url#491":7,"UrlParserTests::test_parse_invalid_url#492":7,"UrlParserTests::test_parse_invalid_url#493":7,"UrlParserTests::test_parse_invalid_url#494":7,"UrlParserTests::test_parse_invalid_url#495":7,"UrlParserTests::test_parse_invalid_url#496":7,"UrlParserTests::test_parse_invalid_url#497":7,"UrlParserTests::test_parse_invalid_url#498":7,"UrlParserTests::test_parse_invalid_url#499":7,"UrlParserTests::test_parse_invalid_url#500":7,"UrlParserTests::test_parse_invalid_url#501":7,"UrlParserTests::test_parse_invalid_url#502":7,"UrlParserTests::test_parse_invalid_url#503":7,"UrlParserTests::test_parse_invalid_url#504":7,"UrlParserTests::test_parse_invalid_url#505":7,"UrlParserTests::test_parse_invalid_url#506":7,"UrlParserTests::test_parse_invalid_url#507":7,"UrlParserTests::test_parse_invalid_url#508":7,"UrlParserTests::test_parse_invalid_url#509":7,"UrlParserTests::test_parse_invalid_url#510":7,"UrlParserTests::test_parse_invalid_url#511":7,"UrlParserTests::test_parse_invalid_url#512":7,"UrlParserTests::test_parse_invalid_url#513":7,"UrlParserTests::test_parse_invalid_url#514":7,"UrlParserTests::test_parse_invalid_url#515":7,"UrlParserTests::test_parse_invalid_url#516":7,"UrlParserTests::test_parse_invalid_url#517":7,"UrlParserTests::test_parse_invalid_url#518":7,"UrlParserTests::test_parse_invalid_url#519":7,"UrlParserTests::test_parse_invalid_url#520":7,"UrlParserTests::test_parse_invalid_url#521":7,"UrlParserTests::test_parse_invalid_url#522":7,"UrlParserTests::test_parse_invalid_url#523":7,"UrlParserTests::test_parse_invalid_url#524":7,"UrlParserTests::test_parse_invalid_url#525":7,"UrlParserTests::test_parse_invalid_url#526":7,"UrlParserTests::test_parse_invalid_url#527":7,"UrlParserTests::test_parse_invalid_url#528":7,"UrlParserTests::test_parse_invalid_url#529":7,"UrlParserTests::test_parse_invalid_url#530":7,"UrlParserTests::test_parse_invalid_url#531":7,"UrlParserTests::test_parse_invalid_url#532":7,"UrlParserTests::test_parse_invalid_url#533":7,"UrlParserTests::test_parse_invalid_url#534":7,"UrlParserTests::test_parse_invalid_url#535":7,"UrlParserTests::test_parse_invalid_url#536":7,"UrlParserTests::test_parse_invalid_url#537":7,"UrlParserTests::test_parse_invalid_url#538":7,"UrlParserTests::test_parse_invalid_url#539":7,"UrlParserTests::test_parse_invalid_url#540":7,"UrlParserTests::test_parse_invalid_url#541":7,"UrlParserTests::test_parse_invalid_url#542":7,"UrlParserTests::test_parse_invalid_url#543":7,"UrlParserTests::test_parse_invalid_url#544":7,"UrlParserTests::test_parse_invalid_url#545":7,"UrlParserTests::test_parse_invalid_url#546":7,"UrlParserTests::test_parse_invalid_url#547":7,"UrlParserTests::test_parse_invalid_url#548":7,"UrlParserTests::test_parse_invalid_url#549":7,"UrlParserTests::test_parse_invalid_url#550":7,"UrlParserTests::test_parse_invalid_url#551":7,"UrlParserTests::test_parse_invalid_url#552":7,"UrlParserTests::test_parse_invalid_url#553":7,"UrlParserTests::test_parse_invalid_url#554":7,"UrlParserTests::test_parse_invalid_url#555":7,"UrlParserTests::test_parse_invalid_url#556":7,"UrlParserTests::test_parse_invalid_url#557":7,"UrlParserTests::test_parse_invalid_url#558":7,"UrlParserTests::test_parse_invalid_url#559":7,"UrlParserTests::test_parse_invalid_url#560":7,"UrlParserTests::test_parse_invalid_url#561":7,"UrlParserTests::test_parse_invalid_url#562":7,"UrlParserTests::test_parse_invalid_url#563":7,"UrlParserTests::test_parse_invalid_url#564":7,"UrlParserTests::test_parse_invalid_url#565":7,"UrlParserTests::test_parse_invalid_url#566":7,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener without attributes":7,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with attributes":7,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with lots of whitespace around attributes":7,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with object and array attributes":7,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Opener with a line break before whitespace":7,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Block name including !":7,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Block name including a whitespace":7,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#No namespace in the block name":7,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Non-object attributes":7,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Invalid JSON as attributes \u2013 Double }} ":7,"WP_Block_Markup_Processor_Tests::test_find_block_closers#Closer without attributes":7,"WP_Block_Markup_Processor_Tests::test_find_block_closers#Closer without the trailing whitespace":7,"WP_Block_Markup_Processor_Tests::test_find_block_closers#Closer with a lot of trailing whitespace":7,"WP_Post_Import_Processor_Test::test_next_url_finds_the_url#In the tag":8,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In the tag":7,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_urls_in_multiple_tags":7,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In block attributes":7,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In the second block attribute, when it contains just the URL":7,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In the first block attribute, when it contains just the URL":7},"times":{"UrlParsingTests::testParseUrl":0.006,"UrlParserTests::testParseUrl":0.001,"UrlParserTests::testParseUrl#HTTP scheme":0.007,"UrlParserTests::testParseUrl#Non-ASCII hostname":0.001,"UrlParserTests::testParseUrl#Slash in the hostname":0.003,"UrlParserTests::testParseUrl#non-protocol characters in the front":0.003,"UrlParserTests::testParsesSimpleUrl":0.008,"UrlParserTests::testParsesIpUrl":0.003,"UrlParserTests::test_invalidates_non_urls#Invalid scheme":0.003,"UrlParserTests::test_invalidates_non_urls#Missing scheme-suffix":0,"UrlParserTests::test_invalidates_non_urls#Broken scheme-suffix":0,"UrlParserTests::test_invalidates_non_urls#Non-ASCII hostname":0,"UrlParserTests::test_invalidates_non_urls#Missing port number":0,"UrlParserTests::test_invalidates_non_urls#Too-high port number":0,"UrlParserTests::test_parse_url#0":0.008,"UrlParserTests::test_parse_url#1":0.001,"UrlParserTests::test_parse_url#2":0,"UrlParserTests::test_parse_url#3":0,"UrlParserTests::test_parse_url#4":0,"UrlParserTests::test_parse_url#5":0,"UrlParserTests::test_parse_url#6":0,"UrlParserTests::test_parse_url#7":0,"UrlParserTests::test_parse_url#8":0,"UrlParserTests::test_parse_url#9":0,"UrlParserTests::test_parse_url#10":0,"UrlParserTests::test_parse_url#11":0,"UrlParserTests::test_parse_url#12":0,"UrlParserTests::test_parse_url#13":0,"UrlParserTests::test_parse_url#14":0,"UrlParserTests::test_parse_url#15":0,"UrlParserTests::test_parse_url#16":0,"UrlParserTests::test_parse_url#17":0,"UrlParserTests::test_parse_url#18":0,"UrlParserTests::test_parse_url#19":0,"UrlParserTests::test_parse_url#20":0,"UrlParserTests::test_parse_url#21":0,"UrlParserTests::test_parse_url#22":0,"UrlParserTests::test_parse_url#23":0,"UrlParserTests::test_parse_url#24":0,"UrlParserTests::test_parse_url#25":0,"UrlParserTests::test_parse_url#26":0,"UrlParserTests::test_parse_url#27":0,"UrlParserTests::test_parse_url#28":0,"UrlParserTests::test_parse_url#29":0,"UrlParserTests::test_parse_url#30":0,"UrlParserTests::test_parse_url#31":0,"UrlParserTests::test_parse_url#32":0,"UrlParserTests::test_parse_url#33":0,"UrlParserTests::test_parse_url#34":0,"UrlParserTests::test_parse_url#35":0,"UrlParserTests::test_parse_url#36":0,"UrlParserTests::test_parse_url#37":0,"UrlParserTests::test_parse_url#38":0,"UrlParserTests::test_parse_url#39":0,"UrlParserTests::test_parse_url#40":0,"UrlParserTests::test_parse_url#41":0,"UrlParserTests::test_parse_url#42":0,"UrlParserTests::test_parse_url#43":0,"UrlParserTests::test_parse_url#44":0,"UrlParserTests::test_parse_url#45":0,"UrlParserTests::test_parse_url#46":0,"UrlParserTests::test_parse_url#47":0,"UrlParserTests::test_parse_url#48":0,"UrlParserTests::test_parse_url#49":0,"UrlParserTests::test_parse_url#50":0,"UrlParserTests::test_parse_url#51":0,"UrlParserTests::test_parse_url#52":0,"UrlParserTests::test_parse_url#53":0,"UrlParserTests::test_parse_url#54":0,"UrlParserTests::test_parse_url#55":0,"UrlParserTests::test_parse_url#56":0,"UrlParserTests::test_parse_url#57":0,"UrlParserTests::test_parse_url#58":0,"UrlParserTests::test_parse_url#59":0,"UrlParserTests::test_parse_url#60":0,"UrlParserTests::test_parse_url#61":0.001,"UrlParserTests::test_parse_url#62":0,"UrlParserTests::test_parse_url#63":0,"UrlParserTests::test_parse_url#64":0,"UrlParserTests::test_parse_url#65":0,"UrlParserTests::test_parse_url#66":0,"UrlParserTests::test_parse_url#67":0,"UrlParserTests::test_parse_url#68":0,"UrlParserTests::test_parse_url#69":0,"UrlParserTests::test_parse_url#70":0,"UrlParserTests::test_parse_url#71":0,"UrlParserTests::test_parse_url#72":0,"UrlParserTests::test_parse_url#73":0,"UrlParserTests::test_parse_url#74":0,"UrlParserTests::test_parse_url#75":0,"UrlParserTests::test_parse_url#76":0,"UrlParserTests::test_parse_url#77":0,"UrlParserTests::test_parse_url#78":0,"UrlParserTests::test_parse_url#79":0,"UrlParserTests::test_parse_url#80":0,"UrlParserTests::test_parse_url#81":0,"UrlParserTests::test_parse_url#82":0,"UrlParserTests::test_parse_url#83":0,"UrlParserTests::test_parse_url#84":0,"UrlParserTests::test_parse_url#85":0,"UrlParserTests::test_parse_url#86":0,"UrlParserTests::test_parse_url#87":0,"UrlParserTests::test_parse_url#88":0,"UrlParserTests::test_parse_url#89":0,"UrlParserTests::test_parse_url#90":0,"UrlParserTests::test_parse_url#91":0,"UrlParserTests::test_parse_url#92":0,"UrlParserTests::test_parse_url#93":0,"UrlParserTests::test_parse_url#94":0,"UrlParserTests::test_parse_url#95":0,"UrlParserTests::test_parse_url#96":0,"UrlParserTests::test_parse_url#97":0,"UrlParserTests::test_parse_url#98":0,"UrlParserTests::test_parse_url#99":0,"UrlParserTests::test_parse_url#100":0,"UrlParserTests::test_parse_url#101":0,"UrlParserTests::test_parse_url#102":0,"UrlParserTests::test_parse_url#103":0,"UrlParserTests::test_parse_url#104":0,"UrlParserTests::test_parse_url#105":0,"UrlParserTests::test_parse_url#106":0,"UrlParserTests::test_parse_url#107":0,"UrlParserTests::test_parse_url#108":0,"UrlParserTests::test_parse_url#109":0,"UrlParserTests::test_parse_url#110":0,"UrlParserTests::test_parse_url#111":0,"UrlParserTests::test_parse_url#112":0,"UrlParserTests::test_parse_url#113":0,"UrlParserTests::test_parse_url#114":0,"UrlParserTests::test_parse_url#115":0,"UrlParserTests::test_parse_url#116":0,"UrlParserTests::test_parse_url#117":0,"UrlParserTests::test_parse_url#118":0,"UrlParserTests::test_parse_url#119":0,"UrlParserTests::test_parse_url#120":0,"UrlParserTests::test_parse_url#121":0,"UrlParserTests::test_parse_url#122":0,"UrlParserTests::test_parse_url#123":0,"UrlParserTests::test_parse_url#124":0,"UrlParserTests::test_parse_url#125":0,"UrlParserTests::test_parse_url#126":0,"UrlParserTests::test_parse_url#127":0,"UrlParserTests::test_parse_url#128":0,"UrlParserTests::test_parse_url#129":0,"UrlParserTests::test_parse_url#130":0,"UrlParserTests::test_parse_url#131":0,"UrlParserTests::test_parse_url#132":0,"UrlParserTests::test_parse_url#133":0,"UrlParserTests::test_parse_url#134":0,"UrlParserTests::test_parse_url#135":0,"UrlParserTests::test_parse_url#136":0,"UrlParserTests::test_parse_url#137":0,"UrlParserTests::test_parse_url#138":0,"UrlParserTests::test_parse_url#139":0,"UrlParserTests::test_parse_url#140":0,"UrlParserTests::test_parse_url#141":0,"UrlParserTests::test_parse_url#142":0,"UrlParserTests::test_parse_url#143":0,"UrlParserTests::test_parse_url#144":0,"UrlParserTests::test_parse_url#145":0,"UrlParserTests::test_parse_url#146":0,"UrlParserTests::test_parse_url#147":0,"UrlParserTests::test_parse_url#148":0,"UrlParserTests::test_parse_url#149":0,"UrlParserTests::test_parse_url#150":0,"UrlParserTests::test_parse_url#151":0,"UrlParserTests::test_parse_url#152":0,"UrlParserTests::test_parse_url#153":0,"UrlParserTests::test_parse_url#154":0,"UrlParserTests::test_parse_url#155":0,"UrlParserTests::test_parse_url#156":0,"UrlParserTests::test_parse_url#157":0,"UrlParserTests::test_parse_url#158":0,"UrlParserTests::test_parse_url#159":0,"UrlParserTests::test_parse_url#160":0.001,"UrlParserTests::test_parse_url#161":0,"UrlParserTests::test_parse_url#162":0,"UrlParserTests::test_parse_url#163":0,"UrlParserTests::test_parse_url#164":0,"UrlParserTests::test_parse_url#165":0,"UrlParserTests::test_parse_url#166":0,"UrlParserTests::test_parse_url#167":0,"UrlParserTests::test_parse_url#168":0,"UrlParserTests::test_parse_url#169":0,"UrlParserTests::test_parse_url#170":0,"UrlParserTests::test_parse_url#171":0,"UrlParserTests::test_parse_url#172":0,"UrlParserTests::test_parse_url#173":0,"UrlParserTests::test_parse_url#174":0,"UrlParserTests::test_parse_url#175":0,"UrlParserTests::test_parse_url#176":0,"UrlParserTests::test_parse_url#177":0,"UrlParserTests::test_parse_url#178":0,"UrlParserTests::test_parse_url#179":0,"UrlParserTests::test_parse_url#180":0,"UrlParserTests::test_parse_url#181":0.001,"UrlParserTests::test_parse_url#182":0,"UrlParserTests::test_parse_url#183":0,"UrlParserTests::test_parse_url#184":0,"UrlParserTests::test_parse_url#185":0,"UrlParserTests::test_parse_url#186":0,"UrlParserTests::test_parse_url#187":0,"UrlParserTests::test_parse_url#188":0,"UrlParserTests::test_parse_url#189":0,"UrlParserTests::test_parse_url#190":0,"UrlParserTests::test_parse_url#191":0,"UrlParserTests::test_parse_url#192":0,"UrlParserTests::test_parse_url#193":0,"UrlParserTests::test_parse_url#194":0,"UrlParserTests::test_parse_url#195":0,"UrlParserTests::test_parse_url#196":0,"UrlParserTests::test_parse_url#197":0,"UrlParserTests::test_parse_url#198":0,"UrlParserTests::test_parse_url#199":0,"UrlParserTests::test_parse_url#200":0,"UrlParserTests::test_parse_url#201":0,"UrlParserTests::test_parse_url#202":0,"UrlParserTests::test_parse_url#203":0,"UrlParserTests::test_parse_url#204":0,"UrlParserTests::test_parse_url#205":0,"UrlParserTests::test_parse_url#206":0,"UrlParserTests::test_parse_url#207":0,"UrlParserTests::test_parse_url#208":0,"UrlParserTests::test_parse_url#209":0,"UrlParserTests::test_parse_url#210":0,"UrlParserTests::test_parse_url#211":0,"UrlParserTests::test_parse_url#212":0,"UrlParserTests::test_parse_url#213":0,"UrlParserTests::test_parse_url#214":0,"UrlParserTests::test_parse_url#215":0,"UrlParserTests::test_parse_url#216":0,"UrlParserTests::test_parse_url#217":0,"UrlParserTests::test_parse_url#218":0,"UrlParserTests::test_parse_url#219":0,"UrlParserTests::test_parse_url#220":0,"UrlParserTests::test_parse_url#221":0,"UrlParserTests::test_parse_url#222":0,"UrlParserTests::test_parse_url#223":0,"UrlParserTests::test_parse_url#224":0,"UrlParserTests::test_parse_url#225":0,"UrlParserTests::test_parse_url#226":0,"UrlParserTests::test_parse_url#227":0,"UrlParserTests::test_parse_url#228":0,"UrlParserTests::test_parse_url#229":0,"UrlParserTests::test_parse_url#230":0,"UrlParserTests::test_parse_url#231":0,"UrlParserTests::test_parse_url#232":0,"UrlParserTests::test_parse_url#233":0,"UrlParserTests::test_parse_url#234":0,"UrlParserTests::test_parse_url#235":0,"UrlParserTests::test_parse_url#236":0,"UrlParserTests::test_parse_url#237":0,"UrlParserTests::test_parse_url#238":0,"UrlParserTests::test_parse_url#239":0,"UrlParserTests::test_parse_url#240":0,"UrlParserTests::test_parse_url#241":0,"UrlParserTests::test_parse_url#242":0,"UrlParserTests::test_parse_url#243":0.001,"UrlParserTests::test_parse_url#244":0,"UrlParserTests::test_parse_url#245":0,"UrlParserTests::test_parse_url#246":0,"UrlParserTests::test_parse_url#247":0,"UrlParserTests::test_parse_url#248":0,"UrlParserTests::test_parse_url#249":0,"UrlParserTests::test_parse_url#250":0,"UrlParserTests::test_parse_url#251":0,"UrlParserTests::test_parse_url#252":0,"UrlParserTests::test_parse_url#253":0,"UrlParserTests::test_parse_url#254":0,"UrlParserTests::test_parse_url#255":0,"UrlParserTests::test_parse_url#256":0,"UrlParserTests::test_parse_url#257":0,"UrlParserTests::test_parse_url#258":0,"UrlParserTests::test_parse_url#259":0,"UrlParserTests::test_parse_url#260":0,"UrlParserTests::test_parse_url#261":0,"UrlParserTests::test_parse_url#262":0,"UrlParserTests::test_parse_url#263":0,"UrlParserTests::test_parse_url#264":0,"UrlParserTests::test_parse_url#265":0,"UrlParserTests::test_parse_url#266":0,"UrlParserTests::test_parse_url#267":0,"UrlParserTests::test_parse_url#268":0,"UrlParserTests::test_parse_url#269":0,"UrlParserTests::test_parse_url#270":0,"UrlParserTests::test_parse_url#271":0,"UrlParserTests::test_parse_url#272":0,"UrlParserTests::test_parse_url#273":0,"UrlParserTests::test_parse_url#274":0,"UrlParserTests::test_parse_url#275":0,"UrlParserTests::test_parse_url#276":0,"UrlParserTests::test_parse_url#277":0,"UrlParserTests::test_parse_url#278":0,"UrlParserTests::test_parse_url#279":0,"UrlParserTests::test_parse_url#280":0,"UrlParserTests::test_parse_url#281":0,"UrlParserTests::test_parse_url#282":0,"UrlParserTests::test_parse_url#283":0,"UrlParserTests::test_parse_url#284":0,"UrlParserTests::test_parse_url#285":0,"UrlParserTests::test_parse_url#286":0,"UrlParserTests::test_parse_url#287":0,"UrlParserTests::test_parse_url#288":0,"UrlParserTests::test_parse_url#289":0,"UrlParserTests::test_parse_url#290":0,"UrlParserTests::test_parse_url#291":0,"UrlParserTests::test_parse_url#292":0,"UrlParserTests::test_parse_url#293":0,"UrlParserTests::test_parse_url#294":0,"UrlParserTests::test_parse_url#295":0,"UrlParserTests::test_parse_url#296":0,"UrlParserTests::test_parse_url#297":0,"UrlParserTests::test_parse_url#298":0,"UrlParserTests::test_parse_url#299":0,"UrlParserTests::test_parse_url#300":0,"UrlParserTests::test_parse_url#301":0,"UrlParserTests::test_parse_url#302":0,"UrlParserTests::test_parse_url#303":0,"UrlParserTests::test_parse_url#304":0,"UrlParserTests::test_parse_url#305":0,"UrlParserTests::test_parse_url#306":0,"UrlParserTests::test_parse_url#307":0,"UrlParserTests::test_parse_url#308":0,"UrlParserTests::test_parse_url#309":0,"UrlParserTests::test_parse_url#310":0,"UrlParserTests::test_parse_url#311":0,"UrlParserTests::test_parse_url#312":0,"UrlParserTests::test_parse_url#313":0,"UrlParserTests::test_parse_url#314":0,"UrlParserTests::test_parse_url#315":0,"UrlParserTests::test_parse_url#316":0,"UrlParserTests::test_parse_url#317":0,"UrlParserTests::test_parse_url#318":0,"UrlParserTests::test_parse_url#319":0,"UrlParserTests::test_parse_url#320":0,"UrlParserTests::test_parse_url#321":0,"UrlParserTests::test_parse_url#322":0,"UrlParserTests::test_parse_url#323":0,"UrlParserTests::test_parse_url#324":0,"UrlParserTests::test_parse_url#325":0,"UrlParserTests::test_parse_url#326":0,"UrlParserTests::test_parse_url#327":0,"UrlParserTests::test_parse_url#328":0,"UrlParserTests::test_parse_url#329":0,"UrlParserTests::test_parse_url#330":0,"UrlParserTests::test_parse_url#331":0,"UrlParserTests::test_parse_url#332":0,"UrlParserTests::test_parse_url#333":0,"UrlParserTests::test_parse_url#334":0,"UrlParserTests::test_parse_url#335":0,"UrlParserTests::test_parse_url#336":0,"UrlParserTests::test_parse_url#337":0,"UrlParserTests::test_parse_url#338":0,"UrlParserTests::test_parse_url#339":0,"UrlParserTests::test_parse_url#340":0,"UrlParserTests::test_parse_url#341":0,"UrlParserTests::test_parse_url#342":0,"UrlParserTests::test_parse_url#343":0,"UrlParserTests::test_parse_url#344":0,"UrlParserTests::test_parse_url#345":0,"UrlParserTests::test_parse_url#346":0,"UrlParserTests::test_parse_url#347":0,"UrlParserTests::test_parse_url#348":0,"UrlParserTests::test_parse_url#349":0,"UrlParserTests::test_parse_url#350":0,"UrlParserTests::test_parse_url#351":0,"UrlParserTests::test_parse_url#352":0,"UrlParserTests::test_parse_url#353":0,"UrlParserTests::test_parse_url#354":0,"UrlParserTests::test_parse_url#355":0,"UrlParserTests::test_parse_url#356":0,"UrlParserTests::test_parse_url#357":0,"UrlParserTests::test_parse_url#358":0,"UrlParserTests::test_parse_url#359":0,"UrlParserTests::test_parse_url#360":0,"UrlParserTests::test_parse_url#361":0,"UrlParserTests::test_parse_url#362":0,"UrlParserTests::test_parse_url#363":0,"UrlParserTests::test_parse_url#364":0,"UrlParserTests::test_parse_url#365":0,"UrlParserTests::test_parse_url#366":0,"UrlParserTests::test_parse_url#367":0,"UrlParserTests::test_parse_url#368":0,"UrlParserTests::test_parse_url#369":0,"UrlParserTests::test_parse_url#370":0,"UrlParserTests::test_parse_url#371":0,"UrlParserTests::test_parse_url#372":0,"UrlParserTests::test_parse_url#373":0,"UrlParserTests::test_parse_url#374":0,"UrlParserTests::test_parse_url#375":0,"UrlParserTests::test_parse_url#376":0,"UrlParserTests::test_parse_url#377":0,"UrlParserTests::test_parse_url#378":0,"UrlParserTests::test_parse_url#379":0,"UrlParserTests::test_parse_url#380":0,"UrlParserTests::test_parse_url#381":0,"UrlParserTests::test_parse_url#382":0,"UrlParserTests::test_parse_url#383":0,"UrlParserTests::test_parse_url#384":0,"UrlParserTests::test_parse_url#385":0,"UrlParserTests::test_parse_url#386":0,"UrlParserTests::test_parse_url#387":0,"UrlParserTests::test_parse_url#388":0,"UrlParserTests::test_parse_url#389":0,"UrlParserTests::test_parse_url#390":0,"UrlParserTests::test_parse_url#391":0,"UrlParserTests::test_parse_url#392":0,"UrlParserTests::test_parse_url#393":0,"UrlParserTests::test_parse_url#394":0,"UrlParserTests::test_parse_url#395":0,"UrlParserTests::test_parse_url#396":0,"UrlParserTests::test_parse_url#397":0,"UrlParserTests::test_parse_url#398":0,"UrlParserTests::test_parse_url#399":0,"UrlParserTests::test_parse_url#400":0,"UrlParserTests::test_parse_url#401":0,"UrlParserTests::test_parse_url#402":0,"UrlParserTests::test_parse_url#403":0,"UrlParserTests::test_parse_url#404":0,"UrlParserTests::test_parse_url#405":0,"UrlParserTests::test_parse_url#406":0,"UrlParserTests::test_parse_url#407":0,"UrlParserTests::test_parse_url#408":0,"UrlParserTests::test_parse_url#409":0,"UrlParserTests::test_parse_url#410":0,"UrlParserTests::test_parse_url#411":0,"UrlParserTests::test_parse_url#412":0,"UrlParserTests::test_parse_url#413":0,"UrlParserTests::test_parse_url#414":0,"UrlParserTests::test_parse_url#415":0,"UrlParserTests::test_parse_url#416":0,"UrlParserTests::test_parse_url#417":0,"UrlParserTests::test_parse_url#418":0,"UrlParserTests::test_parse_url#419":0,"UrlParserTests::test_parse_url#420":0,"UrlParserTests::test_parse_url#421":0,"UrlParserTests::test_parse_url#422":0,"UrlParserTests::test_parse_url#423":0,"UrlParserTests::test_parse_url#424":0,"UrlParserTests::test_parse_url#425":0,"UrlParserTests::test_parse_url#426":0,"UrlParserTests::test_parse_url#427":0,"UrlParserTests::test_parse_url#428":0,"UrlParserTests::test_parse_url#429":0,"UrlParserTests::test_parse_url#430":0,"UrlParserTests::test_parse_url#431":0,"UrlParserTests::test_parse_url#432":0,"UrlParserTests::test_parse_url#433":0,"UrlParserTests::test_parse_url#434":0,"UrlParserTests::test_parse_url#435":0,"UrlParserTests::test_parse_url#436":0,"UrlParserTests::test_parse_url#437":0,"UrlParserTests::test_parse_url#438":0,"UrlParserTests::test_parse_url#439":0,"UrlParserTests::test_parse_url#440":0,"UrlParserTests::test_parse_url#441":0,"UrlParserTests::test_parse_url#442":0,"UrlParserTests::test_parse_url#443":0,"UrlParserTests::test_parse_url#444":0,"UrlParserTests::test_parse_url#445":0,"UrlParserTests::test_parse_url#446":0,"UrlParserTests::test_parse_url#447":0,"UrlParserTests::test_parse_url#448":0,"UrlParserTests::test_parse_url#449":0,"UrlParserTests::test_parse_url#450":0,"UrlParserTests::test_parse_url#451":0,"UrlParserTests::test_parse_url#452":0,"UrlParserTests::test_parse_url#453":0,"UrlParserTests::test_parse_url#454":0,"UrlParserTests::test_parse_url#455":0,"UrlParserTests::test_parse_url#456":0,"UrlParserTests::test_parse_url#457":0,"UrlParserTests::test_parse_url#458":0,"UrlParserTests::test_parse_url#459":0,"UrlParserTests::test_parse_url#460":0,"UrlParserTests::test_parse_url#461":0,"UrlParserTests::test_parse_url#462":0,"UrlParserTests::test_parse_url#463":0,"UrlParserTests::test_parse_url#464":0,"UrlParserTests::test_parse_url#465":0,"UrlParserTests::test_parse_url#466":0,"UrlParserTests::test_parse_url#467":0,"UrlParserTests::test_parse_url#468":0,"UrlParserTests::test_parse_url#469":0,"UrlParserTests::test_parse_url#470":0,"UrlParserTests::test_parse_url#471":0,"UrlParserTests::test_parse_url#472":0,"UrlParserTests::test_parse_url#473":0,"UrlParserTests::test_parse_url#474":0,"UrlParserTests::test_parse_url#475":0,"UrlParserTests::test_parse_url#476":0,"UrlParserTests::test_parse_url#477":0,"UrlParserTests::test_parse_url#478":0,"UrlParserTests::test_parse_url#479":0,"UrlParserTests::test_parse_url#480":0,"UrlParserTests::test_parse_url#481":0,"UrlParserTests::test_parse_url#482":0,"UrlParserTests::test_parse_url#483":0,"UrlParserTests::test_parse_url#484":0,"UrlParserTests::test_parse_url#485":0,"UrlParserTests::test_parse_url#486":0,"UrlParserTests::test_parse_url#487":0,"UrlParserTests::test_parse_url#488":0,"UrlParserTests::test_parse_url#489":0,"UrlParserTests::test_parse_url#490":0,"UrlParserTests::test_parse_url#491":0,"UrlParserTests::test_parse_url#492":0,"UrlParserTests::test_parse_url#493":0,"UrlParserTests::test_parse_url#494":0,"UrlParserTests::test_parse_url#495":0,"UrlParserTests::test_parse_url#496":0,"UrlParserTests::test_parse_url#497":0,"UrlParserTests::test_parse_url#498":0,"UrlParserTests::test_parse_url#499":0,"UrlParserTests::test_parse_url#500":0,"UrlParserTests::test_parse_url#501":0,"UrlParserTests::test_parse_url#502":0,"UrlParserTests::test_parse_url#503":0,"UrlParserTests::test_parse_url#504":0,"UrlParserTests::test_parse_url#505":0,"UrlParserTests::test_parse_url#506":0,"UrlParserTests::test_parse_url#507":0,"UrlParserTests::test_parse_url#508":0,"UrlParserTests::test_parse_url#509":0,"UrlParserTests::test_parse_url#510":0,"UrlParserTests::test_parse_url#511":0,"UrlParserTests::test_parse_url#512":0,"UrlParserTests::test_parse_url#513":0,"UrlParserTests::test_parse_url#514":0,"UrlParserTests::test_parse_url#515":0,"UrlParserTests::test_parse_url#516":0,"UrlParserTests::test_parse_url#517":0,"UrlParserTests::test_parse_url#518":0,"UrlParserTests::test_parse_url#519":0,"UrlParserTests::test_parse_url#520":0,"UrlParserTests::test_parse_url#521":0,"UrlParserTests::test_parse_url#522":0,"UrlParserTests::test_parse_url#523":0,"UrlParserTests::test_parse_url#524":0,"UrlParserTests::test_parse_url#525":0,"UrlParserTests::test_parse_url#526":0,"UrlParserTests::test_parse_url#527":0,"UrlParserTests::test_parse_url#528":0,"UrlParserTests::test_parse_url#529":0,"UrlParserTests::test_parse_url#530":0,"UrlParserTests::test_parse_url#531":0,"UrlParserTests::test_parse_url#532":0,"UrlParserTests::test_parse_url#533":0,"UrlParserTests::test_parse_url#534":0,"UrlParserTests::test_parse_url#535":0,"UrlParserTests::test_parse_url#536":0,"UrlParserTests::test_parse_url#537":0,"UrlParserTests::test_parse_url#538":0,"UrlParserTests::test_parse_url#539":0,"UrlParserTests::test_parse_url#540":0,"UrlParserTests::test_parse_url#541":0,"UrlParserTests::test_parse_url#542":0,"UrlParserTests::test_parse_url#543":0,"UrlParserTests::test_parse_url#544":0,"UrlParserTests::test_parse_url#545":0,"UrlParserTests::test_parse_url#546":0,"UrlParserTests::test_parse_url#547":0,"UrlParserTests::test_parse_url#548":0,"UrlParserTests::test_parse_url#549":0,"UrlParserTests::test_parse_url#550":0,"UrlParserTests::test_parse_url#551":0,"UrlParserTests::test_parse_url#552":0,"UrlParserTests::test_parse_url#553":0,"UrlParserTests::test_parse_url#554":0,"UrlParserTests::test_parse_url#555":0,"UrlParserTests::test_parse_url#556":0,"UrlParserTests::test_parse_url#557":0,"UrlParserTests::test_parse_url#558":0,"UrlParserTests::test_parse_url#559":0,"UrlParserTests::test_parse_url#560":0,"UrlParserTests::test_parse_url#561":0,"UrlParserTests::test_parse_url#562":0,"UrlParserTests::test_parse_url#563":0,"UrlParserTests::test_parse_url#564":0,"UrlParserTests::test_parse_url#565":0,"UrlParserTests::test_parse_url#566":0,"UrlParserTests::test_parse_url#567":0,"UrlParserTests::test_parse_invalid_url#0":0,"UrlParserTests::test_parse_invalid_url#1":0,"UrlParserTests::test_parse_invalid_url#2":0,"UrlParserTests::test_parse_invalid_url#3":0,"UrlParserTests::test_parse_invalid_url#4":0,"UrlParserTests::test_parse_invalid_url#5":0,"UrlParserTests::test_parse_invalid_url#6":0,"UrlParserTests::test_parse_invalid_url#7":0,"UrlParserTests::test_parse_invalid_url#8":0,"UrlParserTests::test_parse_invalid_url#9":0,"UrlParserTests::test_parse_invalid_url#10":0,"UrlParserTests::test_parse_invalid_url#11":0,"UrlParserTests::test_parse_invalid_url#12":0,"UrlParserTests::test_parse_invalid_url#13":0,"UrlParserTests::test_parse_invalid_url#14":0,"UrlParserTests::test_parse_invalid_url#15":0,"UrlParserTests::test_parse_invalid_url#16":0,"UrlParserTests::test_parse_invalid_url#17":0,"UrlParserTests::test_parse_invalid_url#18":0,"UrlParserTests::test_parse_invalid_url#19":0,"UrlParserTests::test_parse_invalid_url#20":0,"UrlParserTests::test_parse_invalid_url#21":0,"UrlParserTests::test_parse_invalid_url#22":0,"UrlParserTests::test_parse_invalid_url#23":0,"UrlParserTests::test_parse_invalid_url#24":0,"UrlParserTests::test_parse_invalid_url#25":0,"UrlParserTests::test_parse_invalid_url#26":0,"UrlParserTests::test_parse_invalid_url#27":0,"UrlParserTests::test_parse_invalid_url#28":0,"UrlParserTests::test_parse_invalid_url#29":0,"UrlParserTests::test_parse_invalid_url#30":0,"UrlParserTests::test_parse_invalid_url#31":0,"UrlParserTests::test_parse_invalid_url#32":0,"UrlParserTests::test_parse_invalid_url#33":0,"UrlParserTests::test_parse_invalid_url#34":0,"UrlParserTests::test_parse_invalid_url#35":0,"UrlParserTests::test_parse_invalid_url#36":0,"UrlParserTests::test_parse_invalid_url#37":0,"UrlParserTests::test_parse_invalid_url#38":0,"UrlParserTests::test_parse_invalid_url#39":0,"UrlParserTests::test_parse_invalid_url#40":0,"UrlParserTests::test_parse_invalid_url#41":0,"UrlParserTests::test_parse_invalid_url#42":0,"UrlParserTests::test_parse_invalid_url#43":0,"UrlParserTests::test_parse_invalid_url#44":0,"UrlParserTests::test_parse_invalid_url#45":0,"UrlParserTests::test_parse_invalid_url#46":0,"UrlParserTests::test_parse_invalid_url#47":0,"UrlParserTests::test_parse_invalid_url#48":0,"UrlParserTests::test_parse_invalid_url#49":0,"UrlParserTests::test_parse_invalid_url#50":0,"UrlParserTests::test_parse_invalid_url#51":0,"UrlParserTests::test_parse_invalid_url#52":0,"UrlParserTests::test_parse_invalid_url#53":0,"UrlParserTests::test_parse_invalid_url#54":0,"UrlParserTests::test_parse_invalid_url#55":0,"UrlParserTests::test_parse_invalid_url#56":0,"UrlParserTests::test_parse_invalid_url#57":0,"UrlParserTests::test_parse_invalid_url#58":0,"UrlParserTests::test_parse_invalid_url#59":0,"UrlParserTests::test_parse_invalid_url#60":0,"UrlParserTests::test_parse_invalid_url#61":0,"UrlParserTests::test_parse_invalid_url#62":0,"UrlParserTests::test_parse_invalid_url#63":0,"UrlParserTests::test_parse_invalid_url#64":0,"UrlParserTests::test_parse_invalid_url#65":0,"UrlParserTests::test_parse_invalid_url#66":0,"UrlParserTests::test_parse_invalid_url#67":0,"UrlParserTests::test_parse_invalid_url#68":0,"UrlParserTests::test_parse_invalid_url#69":0,"UrlParserTests::test_parse_invalid_url#70":0,"UrlParserTests::test_parse_invalid_url#71":0,"UrlParserTests::test_parse_invalid_url#72":0,"UrlParserTests::test_parse_invalid_url#73":0,"UrlParserTests::test_parse_invalid_url#74":0,"UrlParserTests::test_parse_invalid_url#75":0,"UrlParserTests::test_parse_invalid_url#76":0,"UrlParserTests::test_parse_invalid_url#77":0,"UrlParserTests::test_parse_invalid_url#78":0,"UrlParserTests::test_parse_invalid_url#79":0,"UrlParserTests::test_parse_invalid_url#80":0,"UrlParserTests::test_parse_invalid_url#81":0,"UrlParserTests::test_parse_invalid_url#82":0,"UrlParserTests::test_parse_invalid_url#83":0,"UrlParserTests::test_parse_invalid_url#84":0,"UrlParserTests::test_parse_invalid_url#85":0,"UrlParserTests::test_parse_invalid_url#86":0,"UrlParserTests::test_parse_invalid_url#87":0,"UrlParserTests::test_parse_invalid_url#88":0,"UrlParserTests::test_parse_invalid_url#89":0,"UrlParserTests::test_parse_invalid_url#90":0,"UrlParserTests::test_parse_invalid_url#91":0,"UrlParserTests::test_parse_invalid_url#92":0,"UrlParserTests::test_parse_invalid_url#93":0,"UrlParserTests::test_parse_invalid_url#94":0,"UrlParserTests::test_parse_invalid_url#95":0,"UrlParserTests::test_parse_invalid_url#96":0,"UrlParserTests::test_parse_invalid_url#97":0,"UrlParserTests::test_parse_invalid_url#98":0,"UrlParserTests::test_parse_invalid_url#99":0,"UrlParserTests::test_parse_invalid_url#100":0,"UrlParserTests::test_parse_invalid_url#101":0,"UrlParserTests::test_parse_invalid_url#102":0,"UrlParserTests::test_parse_invalid_url#103":0,"UrlParserTests::test_parse_invalid_url#104":0,"UrlParserTests::test_parse_invalid_url#105":0,"UrlParserTests::test_parse_invalid_url#106":0,"UrlParserTests::test_parse_invalid_url#107":0,"UrlParserTests::test_parse_invalid_url#108":0,"UrlParserTests::test_parse_invalid_url#109":0,"UrlParserTests::test_parse_invalid_url#110":0,"UrlParserTests::test_parse_invalid_url#111":0,"UrlParserTests::test_parse_invalid_url#112":0,"UrlParserTests::test_parse_invalid_url#113":0,"UrlParserTests::test_parse_invalid_url#114":0,"UrlParserTests::test_parse_invalid_url#115":0,"UrlParserTests::test_parse_invalid_url#116":0,"UrlParserTests::test_parse_invalid_url#117":0,"UrlParserTests::test_parse_invalid_url#118":0,"UrlParserTests::test_parse_invalid_url#119":0,"UrlParserTests::test_parse_invalid_url#120":0,"UrlParserTests::test_parse_invalid_url#121":0,"UrlParserTests::test_parse_invalid_url#122":0,"UrlParserTests::test_parse_invalid_url#123":0,"UrlParserTests::test_parse_invalid_url#124":0,"UrlParserTests::test_parse_invalid_url#125":0,"UrlParserTests::test_parse_invalid_url#126":0,"UrlParserTests::test_parse_invalid_url#127":0,"UrlParserTests::test_parse_invalid_url#128":0,"UrlParserTests::test_parse_invalid_url#129":0,"UrlParserTests::test_parse_invalid_url#130":0,"UrlParserTests::test_parse_invalid_url#131":0,"UrlParserTests::test_parse_invalid_url#132":0,"UrlParserTests::test_parse_invalid_url#133":0,"UrlParserTests::test_parse_invalid_url#134":0,"UrlParserTests::test_parse_invalid_url#135":0,"UrlParserTests::test_parse_invalid_url#136":0,"UrlParserTests::test_parse_invalid_url#137":0,"UrlParserTests::test_parse_invalid_url#138":0,"UrlParserTests::test_parse_invalid_url#139":0,"UrlParserTests::test_parse_invalid_url#140":0,"UrlParserTests::test_parse_invalid_url#141":0,"UrlParserTests::test_parse_invalid_url#142":0,"UrlParserTests::test_parse_invalid_url#143":0,"UrlParserTests::test_parse_invalid_url#144":0,"UrlParserTests::test_parse_invalid_url#145":0,"UrlParserTests::test_parse_invalid_url#146":0,"UrlParserTests::test_parse_invalid_url#147":0,"UrlParserTests::test_parse_invalid_url#148":0,"UrlParserTests::test_parse_invalid_url#149":0,"UrlParserTests::test_parse_invalid_url#150":0,"UrlParserTests::test_parse_invalid_url#151":0,"UrlParserTests::test_parse_invalid_url#152":0,"UrlParserTests::test_parse_invalid_url#153":0,"UrlParserTests::test_parse_invalid_url#154":0,"UrlParserTests::test_parse_invalid_url#155":0,"UrlParserTests::test_parse_invalid_url#156":0,"UrlParserTests::test_parse_invalid_url#157":0,"UrlParserTests::test_parse_invalid_url#158":0,"UrlParserTests::test_parse_invalid_url#159":0,"UrlParserTests::test_parse_invalid_url#160":0,"UrlParserTests::test_parse_invalid_url#161":0,"UrlParserTests::test_parse_invalid_url#162":0,"UrlParserTests::test_parse_invalid_url#163":0,"UrlParserTests::test_parse_invalid_url#164":0,"UrlParserTests::test_parse_invalid_url#165":0,"UrlParserTests::test_parse_invalid_url#166":0,"UrlParserTests::test_parse_invalid_url#167":0,"UrlParserTests::test_parse_invalid_url#168":0,"UrlParserTests::test_parse_invalid_url#169":0,"UrlParserTests::test_parse_invalid_url#170":0,"UrlParserTests::test_parse_invalid_url#171":0,"UrlParserTests::test_parse_invalid_url#172":0,"UrlParserTests::test_parse_invalid_url#173":0,"UrlParserTests::test_parse_invalid_url#174":0,"UrlParserTests::test_parse_invalid_url#175":0,"UrlParserTests::test_parse_invalid_url#176":0,"UrlParserTests::test_parse_invalid_url#177":0,"UrlParserTests::test_parse_invalid_url#178":0,"UrlParserTests::test_parse_invalid_url#179":0,"UrlParserTests::test_parse_invalid_url#180":0,"UrlParserTests::test_parse_invalid_url#181":0,"UrlParserTests::test_parse_invalid_url#182":0,"UrlParserTests::test_parse_invalid_url#183":0,"UrlParserTests::test_parse_invalid_url#184":0,"UrlParserTests::test_parse_invalid_url#185":0,"UrlParserTests::test_parse_invalid_url#186":0,"UrlParserTests::test_parse_invalid_url#187":0,"UrlParserTests::test_parse_invalid_url#188":0,"UrlParserTests::test_parse_invalid_url#189":0,"UrlParserTests::test_parse_invalid_url#190":0,"UrlParserTests::test_parse_invalid_url#191":0,"UrlParserTests::test_parse_invalid_url#192":0,"UrlParserTests::test_parse_invalid_url#193":0,"UrlParserTests::test_parse_invalid_url#194":0,"UrlParserTests::test_parse_invalid_url#195":0,"UrlParserTests::test_parse_invalid_url#196":0,"UrlParserTests::test_parse_invalid_url#197":0,"UrlParserTests::test_parse_invalid_url#198":0,"UrlParserTests::test_parse_invalid_url#199":0,"UrlParserTests::test_parse_invalid_url#200":0,"UrlParserTests::test_parse_invalid_url#201":0,"UrlParserTests::test_parse_invalid_url#202":0,"UrlParserTests::test_parse_invalid_url#203":0,"UrlParserTests::test_parse_invalid_url#204":0,"UrlParserTests::test_parse_invalid_url#205":0,"UrlParserTests::test_parse_invalid_url#206":0,"UrlParserTests::test_parse_invalid_url#207":0,"UrlParserTests::test_parse_invalid_url#208":0,"UrlParserTests::test_parse_invalid_url#209":0,"UrlParserTests::test_parse_invalid_url#210":0,"UrlParserTests::test_parse_invalid_url#211":0,"UrlParserTests::test_parse_invalid_url#212":0,"UrlParserTests::test_parse_invalid_url#213":0,"UrlParserTests::test_parse_invalid_url#214":0,"UrlParserTests::test_parse_invalid_url#215":0,"UrlParserTests::test_parse_invalid_url#216":0,"UrlParserTests::test_parse_invalid_url#217":0,"UrlParserTests::test_parse_invalid_url#218":0,"UrlParserTests::test_parse_invalid_url#219":0,"UrlParserTests::test_parse_invalid_url#220":0,"UrlParserTests::test_parse_invalid_url#221":0,"UrlParserTests::test_parse_invalid_url#222":0,"UrlParserTests::test_parse_invalid_url#223":0,"UrlParserTests::test_parse_invalid_url#224":0,"UrlParserTests::test_parse_invalid_url#225":0,"UrlParserTests::test_parse_invalid_url#226":0,"UrlParserTests::test_parse_invalid_url#227":0,"UrlParserTests::test_parse_invalid_url#228":0,"UrlParserTests::test_parse_invalid_url#229":0,"UrlParserTests::test_parse_invalid_url#230":0,"UrlParserTests::test_parse_invalid_url#231":0,"UrlParserTests::test_parse_invalid_url#232":0,"UrlParserTests::test_parse_invalid_url#233":0,"UrlParserTests::test_parse_invalid_url#234":0,"UrlParserTests::test_parse_invalid_url#235":0,"UrlParserTests::test_parse_invalid_url#236":0,"UrlParserTests::test_parse_invalid_url#237":0,"UrlParserTests::test_parse_invalid_url#238":0,"UrlParserTests::test_parse_invalid_url#239":0,"UrlParserTests::test_parse_invalid_url#240":0,"UrlParserTests::test_parse_invalid_url#241":0,"UrlParserTests::test_parse_invalid_url#242":0,"UrlParserTests::test_parse_invalid_url#243":0,"UrlParserTests::test_parse_invalid_url#244":0,"UrlParserTests::test_parse_invalid_url#245":0,"UrlParserTests::test_parse_invalid_url#246":0,"UrlParserTests::test_parse_invalid_url#247":0,"UrlParserTests::test_parse_invalid_url#248":0,"UrlParserTests::test_parse_invalid_url#249":0,"UrlParserTests::test_parse_invalid_url#250":0,"UrlParserTests::test_parse_invalid_url#251":0,"UrlParserTests::test_parse_invalid_url#252":0,"UrlParserTests::test_parse_invalid_url#253":0,"UrlParserTests::test_parse_invalid_url#254":0,"UrlParserTests::test_parse_invalid_url#255":0,"UrlParserTests::test_parse_invalid_url#256":0,"UrlParserTests::test_parse_invalid_url#257":0,"UrlParserTests::test_parse_invalid_url#258":0,"UrlParserTests::test_parse_invalid_url#259":0,"UrlParserTests::test_parse_invalid_url#260":0,"UrlParserTests::test_parse_invalid_url#261":0,"UrlParserTests::test_parse_invalid_url#262":0,"UrlParserTests::test_parse_invalid_url#263":0,"UrlParserTests::test_parse_invalid_url#264":0,"UrlParserTests::test_parse_invalid_url#265":0,"UrlParserTests::test_parse_invalid_url#266":0,"UrlParserTests::test_parse_invalid_url#267":0,"UrlParserTests::test_parse_invalid_url#268":0,"UrlParserTests::test_parse_invalid_url#269":0,"UrlParserTests::test_parse_invalid_url#270":0,"UrlParserTests::test_parse_invalid_url#271":0,"UrlParserTests::test_parse_invalid_url#272":0,"UrlParserTests::test_parse_invalid_url#273":0,"UrlParserTests::test_parse_invalid_url#274":0,"UrlParserTests::test_parse_invalid_url#275":0,"UrlParserTests::test_parse_invalid_url#276":0,"UrlParserTests::test_parse_invalid_url#277":0,"UrlParserTests::test_parse_invalid_url#278":0,"UrlParserTests::test_parse_invalid_url#279":0,"UrlParserTests::test_parse_invalid_url#280":0,"UrlParserTests::test_parse_invalid_url#281":0,"UrlParserTests::test_parse_invalid_url#282":0,"UrlParserTests::test_parse_invalid_url#283":0,"UrlParserTests::test_parse_invalid_url#284":0,"UrlParserTests::test_parse_invalid_url#285":0,"UrlParserTests::test_parse_invalid_url#286":0,"UrlParserTests::test_parse_invalid_url#287":0,"UrlParserTests::test_parse_invalid_url#288":0,"UrlParserTests::test_parse_invalid_url#289":0,"UrlParserTests::test_parse_invalid_url#290":0,"UrlParserTests::test_parse_invalid_url#291":0,"UrlParserTests::test_parse_invalid_url#292":0,"UrlParserTests::test_parse_invalid_url#293":0,"UrlParserTests::test_parse_invalid_url#294":0,"UrlParserTests::test_parse_invalid_url#295":0,"UrlParserTests::test_parse_invalid_url#296":0,"UrlParserTests::test_parse_invalid_url#297":0,"UrlParserTests::test_parse_invalid_url#298":0,"UrlParserTests::test_parse_invalid_url#299":0,"UrlParserTests::test_parse_invalid_url#300":0,"UrlParserTests::test_parse_invalid_url#301":0,"UrlParserTests::test_parse_invalid_url#302":0,"UrlParserTests::test_parse_invalid_url#303":0,"UrlParserTests::test_parse_invalid_url#304":0,"UrlParserTests::test_parse_invalid_url#305":0,"UrlParserTests::test_parse_invalid_url#306":0,"UrlParserTests::test_parse_invalid_url#307":0,"UrlParserTests::test_parse_invalid_url#308":0,"UrlParserTests::test_parse_invalid_url#309":0,"UrlParserTests::test_parse_invalid_url#310":0,"UrlParserTests::test_parse_invalid_url#311":0,"UrlParserTests::test_parse_invalid_url#312":0,"UrlParserTests::test_parse_invalid_url#313":0,"UrlParserTests::test_parse_invalid_url#314":0,"UrlParserTests::test_parse_invalid_url#315":0,"UrlParserTests::test_parse_invalid_url#316":0,"UrlParserTests::test_parse_invalid_url#317":0,"UrlParserTests::test_parse_invalid_url#318":0,"UrlParserTests::test_parse_invalid_url#319":0,"UrlParserTests::test_parse_invalid_url#320":0,"UrlParserTests::test_parse_invalid_url#321":0,"UrlParserTests::test_parse_invalid_url#322":0,"UrlParserTests::test_parse_invalid_url#323":0,"UrlParserTests::test_parse_invalid_url#324":0,"UrlParserTests::test_parse_invalid_url#325":0,"UrlParserTests::test_parse_invalid_url#326":0,"UrlParserTests::test_parse_invalid_url#327":0,"UrlParserTests::test_parse_invalid_url#328":0,"UrlParserTests::test_parse_invalid_url#329":0,"UrlParserTests::test_parse_invalid_url#330":0,"UrlParserTests::test_parse_invalid_url#331":0,"UrlParserTests::test_parse_invalid_url#332":0,"UrlParserTests::test_parse_invalid_url#333":0,"UrlParserTests::test_parse_invalid_url#334":0,"UrlParserTests::test_parse_invalid_url#335":0,"UrlParserTests::test_parse_invalid_url#336":0,"UrlParserTests::test_parse_invalid_url#337":0,"UrlParserTests::test_parse_invalid_url#338":0,"UrlParserTests::test_parse_invalid_url#339":0,"UrlParserTests::test_parse_invalid_url#340":0,"UrlParserTests::test_parse_invalid_url#341":0,"UrlParserTests::test_parse_invalid_url#342":0,"UrlParserTests::test_parse_invalid_url#343":0,"UrlParserTests::test_parse_invalid_url#344":0,"UrlParserTests::test_parse_invalid_url#345":0,"UrlParserTests::test_parse_invalid_url#346":0,"UrlParserTests::test_parse_invalid_url#347":0,"UrlParserTests::test_parse_invalid_url#348":0,"UrlParserTests::test_parse_invalid_url#349":0,"UrlParserTests::test_parse_invalid_url#350":0,"UrlParserTests::test_parse_invalid_url#351":0,"UrlParserTests::test_parse_invalid_url#352":0,"UrlParserTests::test_parse_invalid_url#353":0,"UrlParserTests::test_parse_invalid_url#354":0,"UrlParserTests::test_parse_invalid_url#355":0,"UrlParserTests::test_parse_invalid_url#356":0,"UrlParserTests::test_parse_invalid_url#357":0,"UrlParserTests::test_parse_invalid_url#358":0,"UrlParserTests::test_parse_invalid_url#359":0,"UrlParserTests::test_parse_invalid_url#360":0,"UrlParserTests::test_parse_invalid_url#361":0,"UrlParserTests::test_parse_invalid_url#362":0,"UrlParserTests::test_parse_invalid_url#363":0,"UrlParserTests::test_parse_invalid_url#364":0,"UrlParserTests::test_parse_invalid_url#365":0,"UrlParserTests::test_parse_invalid_url#366":0,"UrlParserTests::test_parse_invalid_url#367":0,"UrlParserTests::test_parse_invalid_url#368":0,"UrlParserTests::test_parse_invalid_url#369":0,"UrlParserTests::test_parse_invalid_url#370":0,"UrlParserTests::test_parse_invalid_url#371":0,"UrlParserTests::test_parse_invalid_url#372":0,"UrlParserTests::test_parse_invalid_url#373":0,"UrlParserTests::test_parse_invalid_url#374":0,"UrlParserTests::test_parse_invalid_url#375":0,"UrlParserTests::test_parse_invalid_url#376":0,"UrlParserTests::test_parse_invalid_url#377":0,"UrlParserTests::test_parse_invalid_url#378":0,"UrlParserTests::test_parse_invalid_url#379":0,"UrlParserTests::test_parse_invalid_url#380":0,"UrlParserTests::test_parse_invalid_url#381":0,"UrlParserTests::test_parse_invalid_url#382":0,"UrlParserTests::test_parse_invalid_url#383":0,"UrlParserTests::test_parse_invalid_url#384":0,"UrlParserTests::test_parse_invalid_url#385":0,"UrlParserTests::test_parse_invalid_url#386":0,"UrlParserTests::test_parse_invalid_url#387":0,"UrlParserTests::test_parse_invalid_url#388":0,"UrlParserTests::test_parse_invalid_url#389":0,"UrlParserTests::test_parse_invalid_url#390":0,"UrlParserTests::test_parse_invalid_url#391":0,"UrlParserTests::test_parse_invalid_url#392":0,"UrlParserTests::test_parse_invalid_url#393":0,"UrlParserTests::test_parse_invalid_url#394":0,"UrlParserTests::test_parse_invalid_url#395":0,"UrlParserTests::test_parse_invalid_url#396":0,"UrlParserTests::test_parse_invalid_url#397":0,"UrlParserTests::test_parse_invalid_url#398":0,"UrlParserTests::test_parse_invalid_url#399":0,"UrlParserTests::test_parse_invalid_url#400":0,"UrlParserTests::test_parse_invalid_url#401":0,"UrlParserTests::test_parse_invalid_url#402":0,"UrlParserTests::test_parse_invalid_url#403":0,"UrlParserTests::test_parse_invalid_url#404":0,"UrlParserTests::test_parse_invalid_url#405":0,"UrlParserTests::test_parse_invalid_url#406":0,"UrlParserTests::test_parse_invalid_url#407":0,"UrlParserTests::test_parse_invalid_url#408":0,"UrlParserTests::test_parse_invalid_url#409":0,"UrlParserTests::test_parse_invalid_url#410":0,"UrlParserTests::test_parse_invalid_url#411":0,"UrlParserTests::test_parse_invalid_url#412":0,"UrlParserTests::test_parse_invalid_url#413":0,"UrlParserTests::test_parse_invalid_url#414":0,"UrlParserTests::test_parse_invalid_url#415":0,"UrlParserTests::test_parse_invalid_url#416":0,"UrlParserTests::test_parse_invalid_url#417":0,"UrlParserTests::test_parse_invalid_url#418":0,"UrlParserTests::test_parse_invalid_url#419":0,"UrlParserTests::test_parse_invalid_url#420":0,"UrlParserTests::test_parse_invalid_url#421":0,"UrlParserTests::test_parse_invalid_url#422":0,"UrlParserTests::test_parse_invalid_url#423":0,"UrlParserTests::test_parse_invalid_url#424":0,"UrlParserTests::test_parse_invalid_url#425":0,"UrlParserTests::test_parse_invalid_url#426":0,"UrlParserTests::test_parse_invalid_url#427":0,"UrlParserTests::test_parse_invalid_url#428":0,"UrlParserTests::test_parse_invalid_url#429":0,"UrlParserTests::test_parse_invalid_url#430":0,"UrlParserTests::test_parse_invalid_url#431":0,"UrlParserTests::test_parse_invalid_url#432":0,"UrlParserTests::test_parse_invalid_url#433":0,"UrlParserTests::test_parse_invalid_url#434":0,"UrlParserTests::test_parse_invalid_url#435":0,"UrlParserTests::test_parse_invalid_url#436":0,"UrlParserTests::test_parse_invalid_url#437":0,"UrlParserTests::test_parse_invalid_url#438":0,"UrlParserTests::test_parse_invalid_url#439":0,"UrlParserTests::test_parse_invalid_url#440":0,"UrlParserTests::test_parse_invalid_url#441":0,"UrlParserTests::test_parse_invalid_url#442":0,"UrlParserTests::test_parse_invalid_url#443":0,"UrlParserTests::test_parse_invalid_url#444":0,"UrlParserTests::test_parse_invalid_url#445":0,"UrlParserTests::test_parse_invalid_url#446":0,"UrlParserTests::test_parse_invalid_url#447":0,"UrlParserTests::test_parse_invalid_url#448":0,"UrlParserTests::test_parse_invalid_url#449":0,"UrlParserTests::test_parse_invalid_url#450":0,"UrlParserTests::test_parse_invalid_url#451":0,"UrlParserTests::test_parse_invalid_url#452":0,"UrlParserTests::test_parse_invalid_url#453":0,"UrlParserTests::test_parse_invalid_url#454":0,"UrlParserTests::test_parse_invalid_url#455":0,"UrlParserTests::test_parse_invalid_url#456":0,"UrlParserTests::test_parse_invalid_url#457":0,"UrlParserTests::test_parse_invalid_url#458":0,"UrlParserTests::test_parse_invalid_url#459":0,"UrlParserTests::test_parse_invalid_url#460":0,"UrlParserTests::test_parse_invalid_url#461":0,"UrlParserTests::test_parse_invalid_url#462":0,"UrlParserTests::test_parse_invalid_url#463":0,"UrlParserTests::test_parse_invalid_url#464":0,"UrlParserTests::test_parse_invalid_url#465":0,"UrlParserTests::test_parse_invalid_url#466":0,"UrlParserTests::test_parse_invalid_url#467":0,"UrlParserTests::test_parse_invalid_url#468":0,"UrlParserTests::test_parse_invalid_url#469":0,"UrlParserTests::test_parse_invalid_url#470":0,"UrlParserTests::test_parse_invalid_url#471":0,"UrlParserTests::test_parse_invalid_url#472":0,"UrlParserTests::test_parse_invalid_url#473":0,"UrlParserTests::test_parse_invalid_url#474":0,"UrlParserTests::test_parse_invalid_url#475":0,"UrlParserTests::test_parse_invalid_url#476":0,"UrlParserTests::test_parse_invalid_url#477":0,"UrlParserTests::test_parse_invalid_url#478":0,"UrlParserTests::test_parse_invalid_url#479":0,"UrlParserTests::test_parse_invalid_url#480":0,"UrlParserTests::test_parse_invalid_url#481":0,"UrlParserTests::test_parse_invalid_url#482":0,"UrlParserTests::test_parse_invalid_url#483":0,"UrlParserTests::test_parse_invalid_url#484":0,"UrlParserTests::test_parse_invalid_url#485":0,"UrlParserTests::test_parse_invalid_url#486":0,"UrlParserTests::test_parse_invalid_url#487":0,"UrlParserTests::test_parse_invalid_url#488":0,"UrlParserTests::test_parse_invalid_url#489":0,"UrlParserTests::test_parse_invalid_url#490":0,"UrlParserTests::test_parse_invalid_url#491":0,"UrlParserTests::test_parse_invalid_url#492":0,"UrlParserTests::test_parse_invalid_url#493":0,"UrlParserTests::test_parse_invalid_url#494":0,"UrlParserTests::test_parse_invalid_url#495":0,"UrlParserTests::test_parse_invalid_url#496":0,"UrlParserTests::test_parse_invalid_url#497":0,"UrlParserTests::test_parse_invalid_url#498":0,"UrlParserTests::test_parse_invalid_url#499":0,"UrlParserTests::test_parse_invalid_url#500":0,"UrlParserTests::test_parse_invalid_url#501":0,"UrlParserTests::test_parse_invalid_url#502":0,"UrlParserTests::test_parse_invalid_url#503":0,"UrlParserTests::test_parse_invalid_url#504":0,"UrlParserTests::test_parse_invalid_url#505":0,"UrlParserTests::test_parse_invalid_url#506":0,"UrlParserTests::test_parse_invalid_url#507":0,"UrlParserTests::test_parse_invalid_url#508":0,"UrlParserTests::test_parse_invalid_url#509":0,"UrlParserTests::test_parse_invalid_url#510":0,"UrlParserTests::test_parse_invalid_url#511":0,"UrlParserTests::test_parse_invalid_url#512":0,"UrlParserTests::test_parse_invalid_url#513":0,"UrlParserTests::test_parse_invalid_url#514":0,"UrlParserTests::test_parse_invalid_url#515":0,"UrlParserTests::test_parse_invalid_url#516":0,"UrlParserTests::test_parse_invalid_url#517":0,"UrlParserTests::test_parse_invalid_url#518":0,"UrlParserTests::test_parse_invalid_url#519":0,"UrlParserTests::test_parse_invalid_url#520":0,"UrlParserTests::test_parse_invalid_url#521":0,"UrlParserTests::test_parse_invalid_url#522":0,"UrlParserTests::test_parse_invalid_url#523":0,"UrlParserTests::test_parse_invalid_url#524":0,"UrlParserTests::test_parse_invalid_url#525":0,"UrlParserTests::test_parse_invalid_url#526":0,"UrlParserTests::test_parse_invalid_url#527":0,"UrlParserTests::test_parse_invalid_url#528":0,"UrlParserTests::test_parse_invalid_url#529":0,"UrlParserTests::test_parse_invalid_url#530":0,"UrlParserTests::test_parse_invalid_url#531":0,"UrlParserTests::test_parse_invalid_url#532":0,"UrlParserTests::test_parse_invalid_url#533":0,"UrlParserTests::test_parse_invalid_url#534":0,"UrlParserTests::test_parse_invalid_url#535":0,"UrlParserTests::test_parse_invalid_url#536":0,"UrlParserTests::test_parse_invalid_url#537":0,"UrlParserTests::test_parse_invalid_url#538":0,"UrlParserTests::test_parse_invalid_url#539":0,"UrlParserTests::test_parse_invalid_url#540":0,"UrlParserTests::test_parse_invalid_url#541":0,"UrlParserTests::test_parse_invalid_url#542":0,"UrlParserTests::test_parse_invalid_url#543":0,"UrlParserTests::test_parse_invalid_url#544":0,"UrlParserTests::test_parse_invalid_url#545":0,"UrlParserTests::test_parse_invalid_url#546":0,"UrlParserTests::test_parse_invalid_url#547":0,"UrlParserTests::test_parse_invalid_url#548":0,"UrlParserTests::test_parse_invalid_url#549":0,"UrlParserTests::test_parse_invalid_url#550":0,"UrlParserTests::test_parse_invalid_url#551":0,"UrlParserTests::test_parse_invalid_url#552":0,"UrlParserTests::test_parse_invalid_url#553":0,"UrlParserTests::test_parse_invalid_url#554":0,"UrlParserTests::test_parse_invalid_url#555":0,"UrlParserTests::test_parse_invalid_url#556":0,"UrlParserTests::test_parse_invalid_url#557":0,"UrlParserTests::test_parse_invalid_url#558":0,"UrlParserTests::test_parse_invalid_url#559":0,"UrlParserTests::test_parse_invalid_url#560":0,"UrlParserTests::test_parse_invalid_url#561":0,"UrlParserTests::test_parse_invalid_url#562":0,"UrlParserTests::test_parse_invalid_url#563":0,"UrlParserTests::test_parse_invalid_url#564":0,"UrlParserTests::test_parse_invalid_url#565":0,"UrlParserTests::test_parse_invalid_url#566":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener without attributes":0.001,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener without trailing whitespaces":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener without the trailing whitespace":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with a lot of trailing whitespace":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with attributes":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with empty attributes":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with lots of whitespace around attributes":0,"WP_Block_Markup_Processor_Tests::test_finds_block_openers#Opener with object and array attributes":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Opener with a line break before whitespace":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Block name including !":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Block name including a whitespace":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#No namespace in the block name":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Non-object attributes":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_openers_as_comments#Invalid JSON as attributes \u2013 Double }} ":0,"WP_Block_Markup_Processor_Tests::test_find_block_closers#Closer without attributes":0,"WP_Block_Markup_Processor_Tests::test_find_block_closers#Closer without the trailing whitespace":0,"WP_Block_Markup_Processor_Tests::test_find_block_closers#Closer with a lot of trailing whitespace":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_closers_as_comments#Closer with a line break before whitespace":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_closers_as_comments#Closer with attributes":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_closers_as_comments#Closer with solidus at the end (before whitespace)":0,"WP_Block_Markup_Processor_Tests::test_treat_invalid_block_closers_as_comments#Closer with solidus at the end (after whitespace)":0,"WP_Post_Import_Processor_Test::test_next_url_finds_the_url#In the tag":0.01,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In the tag":0.001,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_multiple_attributes":0.001,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_urls_in_multiple_attributes":0,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_urls_in_multiple_tags":0,"WP_Block_Markup_Url_Processor_Tests::test_next_url_returns_false_once_theres_no_more_urls":0,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In block attributes":0,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In the first block attribute, when it contains just the URL":0.006,"WP_Block_Markup_Url_Processor_Tests::test_next_url_finds_the_url#In the second block attribute, when it contains just the URL":0}} \ No newline at end of file diff --git a/transfer-protocol/README.md b/transfer-protocol/README.md new file mode 100644 index 0000000..2c4655d --- /dev/null +++ b/transfer-protocol/README.md @@ -0,0 +1,6 @@ +## Site Transfer Protocol prototype + +This is an exploration of what could become the WordPress +Site Transfer Protocol. The current version is focused on +finding and rewriting URLs as well as downloading any +related assets. diff --git a/transfer-protocol/bootstrap.php b/transfer-protocol/bootstrap.php new file mode 100644 index 0000000..021767b --- /dev/null +++ b/transfer-protocol/bootstrap.php @@ -0,0 +1,25 @@ +=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": "rowbot/idna", + "version": "0.1.5", + "source": { + "type": "git", + "url": "https://github.com/TRowbotham/idna.git", + "reference": "02d94e4caa435547d2027086c57c69d34e6ed4fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TRowbotham/idna/zipball/02d94e4caa435547d2027086c57c69d34e6ed4fa", + "reference": "02d94e4caa435547d2027086c57c69d34e6ed4fa", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "rowbot/punycode": "^1.0", + "symfony/polyfill-intl-normalizer": "^1.18" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.5 || ^7.0", + "phpstan/phpstan": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.5.1", + "symfony/cache": "^4.3 || ^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Rowbot\\Idna\\": "src/", + "Rowbot\\Idna\\Resource\\": "resources/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Trevor Rowbotham" + } + ], + "description": "An implementation of UTS#46 Unicode IDNA Compatibility Processing.", + "keywords": [ + "idn", + "idna", + "international domain names", + "iri", + "tr46", + "unicode", + "uts46" + ], + "support": { + "issues": "https://github.com/TRowbotham/idna/issues", + "source": "https://github.com/TRowbotham/idna/tree/0.1.5" + }, + "time": "2022-01-10T19:51:24+00:00" + }, + { + "name": "rowbot/punycode", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/TRowbotham/punycode.git", + "reference": "ec116e99cb089a25d45147813d61bfa2deb29328" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TRowbotham/punycode/zipball/ec116e99cb089a25d45147813d61bfa2deb29328", + "reference": "ec116e99cb089a25d45147813d61bfa2deb29328", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "ext-mbstring": "*", + "phpstan/phpstan": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Rowbot\\Punycode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Trevor Rowbotham", + "homepage": "https://trowbotham.com", + "role": "Developer" + } + ], + "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA).", + "keywords": [ + "punycode", + "rfc-3492", + "rfc3492" + ], + "support": { + "issues": "https://github.com/TRowbotham/punycode/issues", + "source": "https://github.com/TRowbotham/punycode/tree/1.0.4" + }, + "time": "2024-05-03T00:56:10+00:00" + }, + { + "name": "rowbot/url", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/TRowbotham/URL-Parser.git", + "reference": "b81e4b4f55ba4fdefaaedebf22d5a060080809f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TRowbotham/URL-Parser/zipball/b81e4b4f55ba4fdefaaedebf22d5a060080809f4", + "reference": "b81e4b4f55ba4fdefaaedebf22d5a060080809f4", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.13 || ^0.9", + "ext-mbstring": "*", + "php": ">=8.1", + "psr/log": "^3.0", + "rowbot/idna": "^0.1.5" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.0", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^10.0 || ^11.0", + "slevomat/coding-standard": "^8.0", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/cache": "^5.0 || ^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Rowbot\\URL\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Trevor Rowbotham", + "homepage": "https://trowbotham.com", + "role": "Developer" + } + ], + "description": "A WHATWG URL spec compliant URL parser for working with URLs and their query strings.", + "keywords": [ + "WHATWG", + "query-string", + "querystring", + "uri", + "url", + "url-parser", + "url-parsing" + ], + "support": { + "issues": "https://github.com/TRowbotham/URL-Parser/issues", + "source": "https://github.com/TRowbotham/URL-Parser/tree/4.0.0" + }, + "time": "2024-06-21T01:00:47+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "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.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/transfer-protocol/iter.php b/transfer-protocol/iter.php new file mode 100644 index 0000000..ec1a5e3 --- /dev/null +++ b/transfer-protocol/iter.php @@ -0,0 +1,32 @@ + 1, + 'b' => [ + 'c' => 2, + 'd' => 3, + ], + 't' => [ + 'cd' => 2, + 'd' => 3, + ], + 'e' => 4, +]; +$subiterator = new \RecursiveArrayIterator($array); +$iterator = new \RecursiveIteratorIterator( + $subiterator, + \RecursiveIteratorIterator::SELF_FIRST, + \RecursiveIteratorIterator::LEAVES_ONLY +); + +var_dump($iterator->current()); +die(); + +$do = false; +foreach ($iterator as $key => $value) { + if($key === 'c') { + $iterator->getSubIterator($iterator->getDepth())->offsetSet($key, 'new value'); + } + echo "$key => $value\n"; +} +print_r($subiterator->getArrayCopy()); diff --git a/transfer-protocol/married.html b/transfer-protocol/married.html new file mode 100644 index 0000000..a6274ea --- /dev/null +++ b/transfer-protocol/married.html @@ -0,0 +1,319 @@ + +

2021 was another most intense year of my life. It was also unique: I reached almost none of the goals I set. The crazy part? I feel damn good about it.

+ + + +

I declared a goals bankruptcy

+ + + +

I started the year with my usual list of Big Hairy Goals. It mentioned things like starting a Master’s degree, advancing my new data scientist career, and moving to Australia. I was excited about that list. I believed I could make it all happen if I only pushed my limits a bit more.

+ + + +

Things looked great at the beginning. I finished my degree with a 4.0 GPA, self-published my final paper at arXiv, and even got admitted to a Master’s in Data Analytics program at Georgia Tech. 

+ + + +

However, my excitement turned into burnout when I found myself working most evenings. During the therapy, I realized I got addicted to achieving. The second I reached one goal, my back alley drug-dealing brain was already tempting me with another, as if it was saying Pssst! Hey kid! You want some goals? I clearly needed a rehab.

+ + + +

I declared a goals bankruptcy and took a leap of faith into the unknown. Goodbye Master’s degree leading to a Ph.D. leading to an AI research career, goodbye learning ukulele, going to Machu Picchu, and building muscles, and goodbye the rest of the list. Welcome, life.

+ + + +

It was so liberating! Every day I woke up to a refreshing buffet of options, not a daunting list of obligations. I felt more relaxed, present, and alive. I didn’t know where I was headed, and yet I still ended up learning, traveling, and exercising a lot. Replacing KPIs with joy has served me well.

+ + + +

It wasn’t all smooth sailing, though. I did relapse into pressing schedules a few more times that year.

+ + + +

During the Write of Passage, I stubbornly tried to beat my writer’s block by writing until 3am multiple times. The burnout returned. I dropped everything and went to Greece for a week.

+ + + +

In December, I realized my calendar and my to-do lists somehow bulked again, leaving me very little time for improvising activities. I took 3 weeks off for Christmas and new year, completed 70 tasks I considered important, and removed most of the remaining ones.

+ + + +

Now I have about 40 tasks left and almost no deadlines. Yay! To keep it that way, I am experimenting with work in progress limits from Kanban:

+ + + + + + + +

I pulled these numbers out of a hat just to have something to work with. I will follow up on how these constraints work and evolve over time.

+ + + +

We got married!

+ + + +

Anna and I got married on the last day of July! Our string quartet welcomed Anna with the sound of 20th-century fox fanfare instead of the classical Mendelssohn March. It was fantastic!

+ + + +
+ + + +

I’m surprised by how well it all went considering we’ve only spent about 40 hours on preparations. Instead of shaping a narrowly-defined perfect wedding, we hired trustworthy vendors, set minimal viable expectations, and gave them complete autonomy. It was a bet, and it turned out great.

+ + + +

For example, our DJ, photographer, and venue staff coordinated without our involvement. They timed the meals, the music, the wedding cake, and the outdoor photoshoot perfectly. We were impressed! Our venue even added lovely touches, such as kids-friendly champagne made of sparkling water and apple juice.

+ + + +

If we tried micromanaging, not only would we be more stressed, but we would also likely get worse results.

+ + + +

We also made our own wedding bands using molding wax. It was our first wax project. As we climbed the learning curve for 40 hours filled with trial, error, and frustration, we realized we’ve severely underestimated how long it would take. We could have planned another wedding during that time!

+ + + +

Still, it was worth it. We now get to carry a symbol of our love as unique as the two of us.

+ + + +
+ + + +

After my 30th birthday, I time-traveled an entire decade to reflect

+ + + +

As of October, I’m 30 years old. Being the best partner I could have imagined, Anna prepared a day full of friends and surprises for me. At no point did I know what was going to happen next. It was perfect! It rooted me in the moment, giving me no chance to think about how cool the next thing is going to be. We ended with a Halloween-themed party.

+ + + +
+ + + +

+ + + +

Shortly after, I had the perfect opportunity to reflect upon the past decade. A work trip enabled me to visit the same place I contemplated as a 20-year-old young adult: The Montjuic Castle in Barcelona. As I stood in the same spot, faced the same panorama, and felt the same cold breeze on my cheeks as a decade ago, I was flooded by vivid memories from that time. It was illuminating.

+ + + +

I remembered how stressed I was back then about dropping out of university, my future career, the unhappy relationship. Then I noticed how all these insurmountable problems are gone. I figured out my career, let go of strategizing the future, and found a fulfilling relationship. Of course, I still have worries and problems, but they’re all different now.

+ + + +

I like to come back to that moment whenever I stress about something. Will it matter ten years from now? If not, why worry? It will all work out in the end.

+ + + +

Just-in-time education replaced my Master’s

+ + + +

I got my Bachelor’s in Computer Science with a 4.0. GPA. It took me 6 months, most of which I spent writing the white paper about the impact of AI on pharmaceutical research.

+ + + +

In retrospect, I’m not sure if my Bachelor’s was worth it. I traded $10k and many evenings for a diploma that opened the doors to a Master’s program. I even accepted, but then I dropped out due to my goals bankruptcy.

+ + + +

Instead, I signed up for Building A Second Brain, which redefined my relationship with knowledge. I learned how to retain all my learning indefinitely and reap compound interests on it. Next, I took the Write of Passage, which taught me to turn consumption into creation. This is how I created this blog. I also realized I have a severe case of writer’s block, but I overcame it thanks to The Writing Studio

+ + + +

It’s crazy how it almost didn’t happen! Had I stuck to my original goals, I would have missed a chance to improve how I work, spend my time, and even talk to people. Serendipity is a powerful force. I will try to leverage it even more through a learning strategy I called just-in-time education.

+ + + +

As a side note, I am grateful to Automattic for paying the tuition. These courses were expensive to me, and I don’t think I would have paid out of pocket.

+ + + +

The other courses I took weren’t as good, so I’ll spare you the details. Other than that, I spent quite a bit of time learning about ADHD, finances, Web3, data science, turn-based gaming AI, and a few programming languages: Scala and F#. I intend to write articles on some of these topics, so stay tuned! 

+ + + +

I let go of a data science career and started compounding my productivity over time

+ + + +

I started the year as a data scientist in Tumblr. I thought I’d pivot my career in that direction, but in the end, I quit.

+ + + +

It was six months filled with fun roleplay. I became Sherlock Holmes in rainy London to interrogate the data, Plato in sunny Greece to ponder questions like Oh you want to find similar content? But what does similar even mean?, and McGyver in trouble to prototype statistical models. I enjoyed that! But I also realized it wasn’t the right fit for me.

+ + + +

The time in the data science world flows slower. Processing big data takes time, so my feedback loop was no longer measured in minutes but hours. My ADHD struggled. There was also something else: I missed working with the WordPress community. Data science was fascinating, but it just didn’t fire me up as much the same way. It all coincided with my goals bankruptcy, so I gave myself permission to return to WordPress.

+ + + +

Shortly after, I stumbled upon How To Get Rich by Naval. It's been one of the best things I've ever read. I realized I can trade my work for not just money, but also for published articles, retained knowledge, built reputation, better relationships, and more opportunities. It’s like building a modern capital.

+ + + +

As a first step, I brought writing to my day-to-day work. For example, I've been learning about a particularly tricky part of WordPress for months, drafted a technical tutorial about it, and now you can learn it in a day. Everyone wins. I’ve also researched the impact of Web3 on the future of online publishing, which matters greatly for WordPress. I’ve recently published my thoughts so far.

+ + + +

In 2022, I would like to double down on writing. Ideally, I won’t move on to the next book, course, and online research before writing an article about the last one. Let’s see how it will go!

+ + + +

I wrote a short novel worth of thoughts

+ + + +

I am proud to say that I wrote 20,000+ words in 2021. Here’s some of them:

+ + + + + + + +

To me, it’s more than just writing – it is a personal breakthrough.

+ + + +

In January, I was convinced I could never write consistently. Every time I tried to write something longer, I would second-guess, self-edit, and rewrite every sentence a gazillion times. The result? I was lucky if a two-hour writing session yielded a single paragraph.

+ + + +

Then I enrolled in the Write of Passage and started this blog. The goal seemed simple: to publish five short articles. How hard could that be? I thought. I sat down, cracked my knuckles, opened my laptop, and two frustrating hours later, I read my answer off the empty screen. It was very hard.

+ + + +

Writing a few short posts took me more than a hundred hours. It wasn’t working, but I was too stubborn to quit. At one point, I got burned out, threw the papers, and went to Greece to recuperate. I couldn’t figure out what was wrong.

+ + + +

Call it insanity, but once I returned and regained some motivation, I enrolled in yet another course called The Writing Studio. I hoped to figure out my writer's block. Although TWS was excellent, I still spent way too much time writing, missed all the deadlines, and began to give up. And then, as I was recapping one of the exercises, it all clicked.

+ + + +

I approached writing all wrong. My default mode was to sit down and power through tasks. Even when I was tired, I often said I want this off my to-do list already and kept going. It worked well for many things, but I realized I just can’t write this way.

+ + + +

Writing is more like falling asleep. It only works when I show up, relax, and don’t overthink it. But when I feel pressed, impatient, and tense, I keep going in circles. In bed, I keep tossing and turning, and in writing, I keep rewriting the same sentence fifty times and second-guessing all my ideas.

+ + + +

I adjusted my writing strategy to fit my style. I don’t block multi-hour writing sessions in my calendar anymore. Instead, I only show up for 5 minutes of writing every day. Sometimes I’m into it, keep going beyond these 5 minutes, and end up writing a few dozens or hundred words. Other times I struggle, call it a day, and go for a walk instead. I don’t judge the outcome. I only aim to show up consistently.

+ + + +

I may leverage deadlines to publish regularly one day, but I'm not there yet. For now, I just write.

+ + + +

I self-educated on investing and built an effective portfolio

+ + + +

In 2021, I got a few months ahead of my optimistic projections from 2020. Three things made that possible.

+ + + +

First, I saved more than I expected. My goals bankruptcy erased all the projected spendings for my Master’s degree and other projects. In addition, my Bachelor’s degree and Stanford’s AI program ended up being less expensive than I initially expected.

+ + + +

Second, my financial self-education paid off. I was afraid of keeping my savings in cash but didn't know enough about finances to manage my own money. The local financial advisors only seemed to talk about costly mutual funds, so I sighed and did my own research. It was hard work, but it has paid off.

+ + + +

I built an investment portfolio that grew more than 20% last year which is less than SP500, but I am still thrilled. In broad strokes, my asset allocation is as follows:

+ + + + + + + +

If that sounds interesting, shoot me an email. I could dive into more details in my new post series about personal finance. I just need a little push.

+ + + +

Finally, I changed my outlook on investing. I used to think that living my best life required reaching early retirement. Last year, I realized it’s a mirage that distracts me from enjoying today.

+ + + +

Crossing the gap between savings and early retirement is like swimming through the Atlantic ocean on a kayak. Some people get there, but not everyone will. Even if I ever do, I want to be honest: Laying on the beach all day sounds just dull. I'd much rather express myself creatively during the day, spend evenings with my close ones, and travel from time to time to change scenery.

+ + + +

Except this is what I already do! It took me years to realize that. Reaching financial freedom wouldn't change anything fundamental about spending my days. That's great news! It means I can treat my savings as a peace-of-mind vehicle, not a top-of-mind strategic asset to monitor each day. It is a different, more relaxed game.

+ + + +

I crashed with a car and started biking indoors

+ + + +

Once my Apple Watch told me that my aerobic capacity (VO2max) was below average, I started exercising more.

+ + + +

I made a lot of attempts: Tango lessons, bouldering, rucking, squash, go-karting, laser tag, short HIIT training, calisthenics, running, and biking. Running stuck with me. Perhaps for the first time in my life, I have been consistently jogging on most days for three months, 

+ + + +

I surprised myself here. I used to dread running – it keeps my body busy but leaves my mind bored. Still, I knew I had to do something, and running was the most convenient option. It worked on my schedule, and I could start and be done in the same 30 minutes window I would have otherwise spent commuting to an organized class or a gym.

+ + + +

I overcame the boredom issue by giving my brain something to do. Sometimes I practiced mindfulness; other times, I listened to Huberman lab's podcast, and I even called someone a few times. It worked, and I learned to enjoy jogging. Yay! It showed on my apple watch, too: After about 30 days, my VO2max hit the above-average slot, and it has stayed there ever since. 

+ + + +

Unfortunately, I injured my foot during a laser tag game on my 30th birthday and couldn't run anymore. I needed a different sport.

+ + + +

I turned to bike. It was joyful, but I underestimated the dangers of cycling on a slippery road in winter. One day, a car drove out of a garage and stopped right in front of me. We were both going just a bit too fast, and this specific place made it hard to see that coming for either of us. I started breaking, but it was too late. I hit that car from a side, flew over the hood head-first, and hit the concrete.

+ + + +

How am I still here? Maybe that's luck, or perhaps that's some reflexes back from my martial arts/parkour years, but I turned in mid-air, then guided the impact with my arms, and hit the ground mainly with the side of my butt. It hurt like hell! As I was laying on the ground in pain, I was scared I got seriously injured, but after a few minutes the worst pain has passed and I was able to get up. I got away with a big bruise and a lesson about safety.

+ + + +

And that's how I ended up getting a bicycle trainer. It's a simple device where I mount my regular bike and drive in the comfort of my apartment while reading some low-focus articles or watching Locke&Key on Netflix. I liked it enough to turn it into a habit, which I hope to retain for the entire 2022.

+ + + +

Project Kangaroo

+ + + +

Anna and I applied for Australian visas in the first half of 2021. Initially, we want to go there for six months and see how we like it. It’s like a test drive. We may miss our home and return, or we may find it fantastic and apply for a proper immigration visa. 

+ + + +

When will we go? I have no idea! There is too much uncertainty to tell. Covid derailed all the visa procedures, and we’re still waiting for our approvals. It may happen tomorrow, next year, or never if we get rejected. For now, I don’t think about it too much and just wait.

+ + + +

What’s next?

+ + + +

I made 2021 about doing more. Instead of shaping the bright future I envisioned, I ended up chasing goals, grandiose plans and getting burned out. It wasn't bad. It was just the cost of getting to know myself better.

+ + + +

I will make 2022 about doing less. My only map is my intuition. Amor fati, as the Stoics would say. I am open to whatever life will bring. Where is it going to take me? Who knows? We'll see next year!

+ \ No newline at end of file diff --git a/transfer-protocol/phpunit.xml b/transfer-protocol/phpunit.xml new file mode 100644 index 0000000..5349c27 --- /dev/null +++ b/transfer-protocol/phpunit.xml @@ -0,0 +1,7 @@ + + + + ./tests + + + \ No newline at end of file diff --git a/transfer-protocol/rewrite-urls.php b/transfer-protocol/rewrite-urls.php new file mode 100644 index 0000000..d74e0c4 --- /dev/null +++ b/transfer-protocol/rewrite-urls.php @@ -0,0 +1,170 @@ +next_token(); + if($p->get_token_type() === '#block-comment') { + $updated_attrs = map_block_attributes($p->get_block_attributes(), function($key, $value) { + if($key === 'url') { + return 'https://example.com'; + } + return $value; + }); + $p->set_block_attributes($updated_attrs); + echo substr($p->get_updated_html(), 0, 100) . "\n"; + die(); + } +} + +function map_block_attributes(array $attributes, $mapper) +{ + $new_attributes = array(); + foreach ($attributes as $key => $value) { + if (is_array($value)) { + $new_attributes[$key] = map_block_attributes($value, $mapper); + } else { + $new_attributes[$key] = $mapper($key, $value); + } + } + return $new_attributes; +} + +class URL_Processor { + + private $string; + + const STATE_LOOKING_FOR_URL = 'looking-for-url'; + const STATE_URL = 'url'; + + private $starts_at; + private $ends_at; + + public function __construct($string) + { + $this->string = $string; + } + + /** + * + * URL syntax is defined in RFC 3986, section 3: + * https://datatracker.ietf.org/doc/html/rfc3986#section-3 + * + * 3. Syntax Components + * + * The generic URI syntax consists of a hierarchical sequence of + * components referred to as the scheme, authority, path, query, and + * fragment. + * + * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + * hier-part = "//" authority path-abempty + * / path-absolute + * / path-rootless + * / path-empty + * + * @return void + */ + public function next_url() + { + $this->starts_at = null; + $this->ends_at = null; + $this->state = self::STATE_LOOKING_FOR_URL; + + /* + * A relative reference starts with a double slash and takes + * advantage of the hierarchical syntax to use the same scheme + * as the currently visited resource. + * https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 + */ + + + $url_pattern = '/ + # Match an opening tag + (?:https?:)? # A protocol part of the URL is optional. + # Absolute URLs starts with one, but protocol-relative URLs do not. + # This processor is only interested in http and https. + \/\/ # Two slashes – protocol-relative URLs start with those + + # Important! Anything from now on may use punycode + # and percent encoding + + userinfo@host:port/path?query#fragment + + /xu'; + // preg_match( + // '~(?:(https?)://|www\.)[-a-zA-Z0-9@:%._\+\~#=]+(?:\.[a-zA-Z0-9]{2,})+[-a-zA-Z0-9@:%_\+.\~#?&//=]*~', + // $this->string, + // $matches, + // PREG_OFFSET_CAPTURE + // ); + + // An absolute URL starts with a scheme, and the two schemes this + // processor is interested in are http and https. + // A scheme cannot contain percent encoding. + + // A protocol-relative URL starts with two slashes. + + // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + } + + public function get_updated_string() + { + return $this->string; + } + + public function set_url($new_url) + { + if($this->state !== self::STATE_URL) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set a URL when not in `url` state' ), + 'WP_VERSION' + ); + return false; + } + + // @TODO: defer these like in WP_HTML_Tag_Processor + $this->string = substr_replace($this->string, $new_url, $this->starts_at, $this->ends_at - $this->starts_at); + } + +} + + /** + * @TODO: Investigate how bad this is – would it stand the test of time, or do we need + * a proper URL-matching state machine? + */ + // const URL_REGEXP = '\b((?:(https?):\/\/|www\.)[-a-zA-Z0-9@:%._\+\~#=]+(?:\.[a-zA-Z0-9]{2,})+[-a-zA-Z0-9@:%_\+.\~#?&//=]*)\b'; + // private function process_as_plaintext($text) { + // return preg_replace_callback( + // '~'.self::URL_REGEXP.'~', + // function ($matches) { + // $this->found_urls[$matches[0]] = true; + // $replacer = $this->rewrite_url_callback; + // return $replacer($matches[0]); + // }, + // $text + // ); + // } \ No newline at end of file diff --git a/transfer-protocol/run-tests.sh b/transfer-protocol/run-tests.sh new file mode 100644 index 0000000..e544ff7 --- /dev/null +++ b/transfer-protocol/run-tests.sh @@ -0,0 +1,4 @@ +#!/bin/bash +COMMAND="phpunit tests/WP_Block_Markup_Url*" +$COMMAND +fswatch -o ./**/*.php | xargs -n1 -I{} $COMMAND diff --git a/transfer-protocol/src/WP_Block_Markup_Processor.php b/transfer-protocol/src/WP_Block_Markup_Processor.php new file mode 100644 index 0000000..b26a035 --- /dev/null +++ b/transfer-protocol/src/WP_Block_Markup_Processor.php @@ -0,0 +1,243 @@ +parser_state ) { + case self::STATE_COMMENT: + if(null !== $this->block_name) { + return '#block-comment'; + } + return '#comment'; + + default: + return parent::get_token_type(); + } + } + + public function next_token() + { + $this->block_name = null; + $this->block_attributes = null; + $this->block_closer = false; + + if(parent::next_token() === false) { + return false; + } + + if (parent::get_token_type() !== '#comment') { + return true; + } + + $text = parent::get_modifiable_text(); + // Try to parse as a block. The block parser won't cut it because + // while it can parse blocks, it has no semantics for rewriting the + // block markup. Let's do our best here: + $at = strspn($text, ' \t\f\r\n'); // Whitespace + + if($at >= strlen($text)) { + // This is an empty comment. Not a block. + return true; + } + + // Blocks closers start with the solidus character (`/`) + if ('/' === $text[$at]) { + $this->block_closer = true; + ++$at; + } + + // Blocks start with wp: + if (!( + $at + 3 < strlen($text) && + $text[$at] === 'w' && + $text[$at + 1] === 'p' && + $text[$at + 2] === ':' + )) { + return true; + } + + $name_starts_at = $at; + + // Skip wp: + $at += 3; + + // Parse the actual block name after wp: + $name_length = strspn($text, 'abcdefghijklmnopqrstuwxvyzABCDEFGHIJKLMNOPRQSTUWXVYZ0123456789_-', $at); + if ($name_length === 0) { + // This wasn't a block after all, just a regular comment. + return true; + } + $name = substr($text, $name_starts_at, $name_length + 3); + $at += $name_length; + + // Skip the whitespace that follows the block name + $at += strspn($text, ' \t\f\r\n', $at); + if ($at >= strlen($text)) { + // It's a block without attributes. + $this->block_name = $name; + return true; + } + + // It seems we may have block attributes here. + + // Block closers cannot have attributes. + if($this->block_closer) { + return true; + } + + // Let's try to parse them as JSON. + $json_maybe = substr($text, $at); + $attributes = json_decode($json_maybe, true); + if (null === $attributes || !is_array($attributes)) { + // This comment looked like a block comment, but the attributes didn't + // parse as a JSON array. This means it wasn't a block after all. + return true; + } + + // We have a block name and a valid attributes array. We may not find a block + // closer, but let's assume is a block and process it as such. + // @TODO: Confirm that WordPress block parser would have parsed this as a block. + $this->block_name = $name; + $this->block_attributes = $attributes; + + return true; + } + + /** + * Returns the name of the block if the current token is a block comment. + * + * @return string|false + */ + public function get_block_name() + { + if(null === $this->block_name) { + return false; + } + return $this->block_name; + } + + public function get_block_attributes() + { + if(null === $this->block_attributes) { + return false; + } + return $this->block_attributes; + } + + public function is_block_closer() + { + return $this->block_name !== null && $this->block_closer === true; + } + + public function set_block_attributes(array $new_attributes) + { + if(null === $this->block_name) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set block attributes when not in `block_attributes` state' ), + 'WP_VERSION' + ); + return false; + } + + $this->block_attributes = $new_attributes; + $this->set_modifiable_text( + $this->block_name . ' ' . + json_encode( + $new_attributes, + JSON_HEX_TAG | // Convert < and > to \u003C and \u003E + JSON_HEX_AMP // Convert & to \u0026 + ) + ); + } + + /** + * Don't do this at home :-) Changes access to private properties of the + * WP_HTML_Tag_Processor class to enable changing the text content of a + * node. + * + * @param mixed $new_content + * @return bool + */ + private function set_modifiable_text($new_value) { + $reflection = new ReflectionClass('WP_HTML_Tag_Processor'); + $accessible_text_starts_at = $reflection->getProperty('text_starts_at'); + $accessible_text_starts_at->setAccessible(true); + + $accessible_text_length = $reflection->getProperty('text_length'); + $accessible_text_length->setAccessible(true); + + $lexical_updates = $reflection->getProperty('lexical_updates'); + $lexical_updates->setAccessible(true); + + switch ( parent::get_token_type() ) { + case '#text': + $lexical_updates_now = $lexical_updates->getValue($this); + $lexical_updates_now[] = new WP_HTML_Text_Replacement( + $accessible_text_starts_at->getValue($this), + $accessible_text_length->getValue($this), + htmlspecialchars( $new_value, ENT_XML1, 'UTF-8' ) + ); + $lexical_updates->setValue($this, $lexical_updates_now); + return true; + + case '#comment': + case '#cdata-section': + if( + parent::get_token_type() === '#comment' && ( + strpos($new_value, '-->') !== false || + strpos($new_value, '--!>') !== false + ) + ) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set a comment closer as a text of an HTML comment.' ), + 'WP_VERSION' + ); + return false; + } + if( + $this->get_token_type() === '#cdata-section' && + strpos($new_value, '>') !== false + ) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set a CDATA closer as text of an HTML CDATA-lookalike section.' ), + 'WP_VERSION' + ); + return false; + } + $lexical_updates_now = $lexical_updates->getValue($this); + $lexical_updates_now[] = new WP_HTML_Text_Replacement( + $accessible_text_starts_at->getValue($this), + $accessible_text_length->getValue($this), + $new_value + ); + $lexical_updates->setValue($this, $lexical_updates_now); + return true; + default: + _doing_it_wrong( + __METHOD__, + __( 'Cannot set text content on a non-text node.' ), + 'WP_VERSION' + ); + return false; + } + } +} diff --git a/transfer-protocol/src/WP_Block_Markup_Url_Processor.php b/transfer-protocol/src/WP_Block_Markup_Url_Processor.php new file mode 100644 index 0000000..4c99d07 --- /dev/null +++ b/transfer-protocol/src/WP_Block_Markup_Url_Processor.php @@ -0,0 +1,208 @@ +base_url = $base_url; + } + + public function next_url() { + do { + if ( true === $this->next_url_in_current_token() ) { + return true; + } + } while ( $this->next_token() !== false ); + + return false; + } + + public function get_url() { + return $this->url; + } + + private function next_url_in_current_token() { + switch ( parent::get_token_type() ) { + case '#tag': + return $this->next_url_attribute(); + case '#block-comment': + return $this->next_url_block_attribute(); + break; + // case '#text': + // $this->rewrite_text(); + // break; + } + } + + public function next_token() { + $this->url = null; + $this->inspected_attribute_idx = - 1; + $this->block_attributes_iterator = null; + + return parent::next_token(); + } + + /** + * A list of HTML attributes meant to contain URLs, as defined in the HTML specification. + * It includes some deprecated attributes like `lowsrc` and `highsrc` for the `IMG` element. + * + * See https://html.spec.whatwg.org/multipage/indices.html#attributes-1. + * See https://stackoverflow.com/questions/2725156/complete-list-of-html-tag-attributes-which-have-a-url-value. + * + */ + public const URL_ATTRIBUTES = [ + 'A' => [ 'href' ], + 'APPLET' => [ 'codebase', 'archive' ], + 'AREA' => [ 'href' ], + 'AUDIO' => [ 'src' ], + 'BASE' => [ 'href' ], + 'BLOCKQUOTE' => [ 'cite' ], + 'BODY' => [ 'background' ], + 'BUTTON' => [ 'formaction' ], + 'COMMAND' => [ 'icon' ], + 'DEL' => [ 'cite' ], + 'EMBED' => [ 'src' ], + 'FORM' => [ 'action' ], + 'FRAME' => [ 'longdesc', 'src' ], + 'HEAD' => [ 'profile' ], + 'HTML' => [ 'manifest' ], + 'IFRAME' => [ 'longdesc', 'src' ], + // SVG element + 'IMAGE' => [ 'href' ], + 'IMG' => [ 'longdesc', 'src', 'usemap', 'lowsrc', 'highsrc' ], + 'INPUT' => [ 'src', 'usemap', 'formaction' ], + 'INS' => [ 'cite' ], + 'LINK' => [ 'href' ], + 'OBJECT' => [ 'classid', 'codebase', 'data', 'usemap' ], + 'Q' => [ 'cite' ], + 'SCRIPT' => [ 'src' ], + 'SOURCE' => [ 'src' ], + 'TRACK' => [ 'src' ], + 'VIDEO' => [ 'poster', 'src' ], + ]; + + /** + * @TODO: Either explicitly support these attributes, or explicitly drop support for + * handling their subsyntax. A generic URL matcher might be good enough. + */ + public const URL_ATTRIBUTES_WITH_SUBSYNTAX = [ + '*' => [ 'style' ], // background(), background-image() + 'APPLET' => [ 'archive' ], + 'IMG' => [ 'srcset' ], + 'META' => [ 'content' ], + 'SOURCE' => [ 'srcset' ], + 'OBJECT' => [ 'archive' ], + ]; + + /** + * Also + * + * @TODO: Either explicitly support these tags, or explicitly drop support for + * handling their subsyntax. A generic URL matcher might be good enough. + */ + public const URL_CONTAINING_TAGS_WITH_SUBSYNTAX = [ + 'STYLE', + 'SCRIPT', + ]; + + private function next_url_attribute() { + $tag = $this->get_tag(); + if ( + ! array_key_exists( $tag, self::URL_ATTRIBUTES ) && + $tag !== 'INPUT' // type=image => src, + ) { + return false; + } + + while ( true ) { + ++ $this->inspected_attribute_idx; + if ( $this->inspected_attribute_idx >= count( self::URL_ATTRIBUTES[ $tag ] ) ) { + return false; + } + $this->url = $this->get_attribute( + self::URL_ATTRIBUTES[ $tag ][ $this->inspected_attribute_idx ] + ); + if ( $this->url !== null ) { + break; + } + } + + if ( null === $this->url ) { + return false; + } + + return true; + } + + /** + * @var \RecursiveIteratorIterator + */ + private $block_attributes_iterator; + private $current_block_attribute_key = null; + private $current_block_attribute_value = null; + + private function next_url_block_attribute() { + if ( null === $this->block_attributes || 0 === count( $this->block_attributes ) ) { + return false; + } + + if ( null === $this->block_attributes_iterator ) { + // Re-entrant iteration over the block attributes. + $this->block_attributes_iterator = new \RecursiveIteratorIterator( + new \RecursiveArrayIterator( $this->block_attributes ), + \RecursiveIteratorIterator::SELF_FIRST, + \RecursiveIteratorIterator::LEAVES_ONLY + ); + } else { + $this->block_attributes_iterator->next(); + } + + do { + $url_maybe = $this->block_attributes_iterator->current(); + if ( URL::canParse( $url_maybe, $this->base_url ) ) { + $this->current_block_attribute_key = $this->block_attributes_iterator->key(); + $this->current_block_attribute_value = $url_maybe; + $this->url = $url_maybe; + + return true; + } + $this->block_attributes_iterator->next(); + } while ( $this->block_attributes_iterator->valid() ); + + return false; + } + + public function get_current_block_attribute_key() { + if ( null === $this->block_attributes_iterator || null === $this->current_block_attribute_key ) { + return false; + } + + return $this->current_block_attribute_key; + } + + public function get_current_block_attribute_value() { + if ( null === $this->block_attributes_iterator || null === $this->current_block_attribute_key ) { + return false; + } + if ( null === $this->current_block_attribute_value ) { + $this->current_block_attribute_value = $this->block_attributes_iterator->current(); + } + + return $this->current_block_attribute_value; + } + +} diff --git a/transfer-protocol/tests/UrlParserTests.php b/transfer-protocol/tests/UrlParserTests.php new file mode 100644 index 0000000..5246575 --- /dev/null +++ b/transfer-protocol/tests/UrlParserTests.php @@ -0,0 +1,133 @@ +assertTrue(URL::canParse($example['input'], $example['base'])); + + $parsed = new URL($example['input'], $example['base']); + $this->assertEquals($example['protocol'], $parsed->protocol); + $this->assertEquals($example['username'], $parsed->username); + $this->assertEquals($example['password'], $parsed->password); + $this->assertEquals($example['host'], $parsed->host); + $this->assertEquals($example['port'], $parsed->port); + $this->assertEquals($example['hostname'], $parsed->hostname); + $this->assertEquals($example['pathname'], $parsed->pathname); + $this->assertEquals($example['search'], $parsed->search); + $this->assertEquals($example['hash'], $parsed->hash); + if (isset($example['origin'])) { + $this->assertEquals($example['origin'], $parsed->origin); + } + } + + /** + * Data provider. + * + * @return array[]. + */ + static public function data_valid_urls() { + static $test_examples = load_test_examples(); + + $valid_urls = array(); + foreach($test_examples as $example) { + if(is_string($example)) { + continue; + } + if (!isset($example['failure'])) { + $valid_urls[] = [$example]; + } + } + return $valid_urls; + + // @TODO: Figure out why this test case fails. I had to remove it from urltestdata.json because + // the UTF-16 sequences made the json_code return null. The error was: + // + // > Single unpaired UTF-16 surrogate in unicode escape + // + // $valid_urls[] = array( + // array( + // "input" => "http://example.com/".encodeUtf16Hex('d800')."𐟾".encodeUtf16Hex('dfff')."﷐﷏﷯ﷰ￾￿?".encodeUtf16Hex('d800')."𐟾".encodeUtf16Hex('dfff')."﷐﷏﷯ﷰ￾￿", + // "base" => null, + // "href" => "http://example.com/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF", + // "origin" => "http://example.com", + // "protocol" => "http:", + // "username" => "", + // "password" => "", + // "host" => "example.com", + // "hostname" => "example.com", + // "port" => "", + // "pathname" => "/%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF", + // "search" => "?%EF%BF%BD%F0%90%9F%BE%EF%BF%BD%EF%B7%90%EF%B7%8F%EF%B7%AF%EF%B7%B0%EF%BF%BE%EF%BF%BF", + // "hash" => "" + // ), + // ), + } + + /** + * Test url_parser function. + * + * @dataProvider data_invalid_urls + * @return void + */ + public function test_parse_invalid_url($example) + { + $this->assertFalse( + URL::canParse($example['input'], $example['base']), + "Should have rejected invalid URL {$example['input']} with base {$example['base']}" + ); + } + + /** + * Data provider. + * + * @return array[]. + */ + static public function data_invalid_urls() { + static $test_examples = load_test_examples(); + + $urls = array(); + foreach($test_examples as $example) { + if(is_string($example)) { + continue; + } + if (array_key_exists('failure', $example) && $example['failure'] === true) { + $urls[] = [$example]; + } + } + return $urls; + } + +} diff --git a/transfer-protocol/tests/WP_Block_Markup_Processor_Tests.php b/transfer-protocol/tests/WP_Block_Markup_Processor_Tests.php new file mode 100644 index 0000000..b567ecb --- /dev/null +++ b/transfer-protocol/tests/WP_Block_Markup_Processor_Tests.php @@ -0,0 +1,114 @@ +next_token(); + $this->assertEquals('#block-comment', $p->get_token_type(), 'Failed to identify the block comment'); + $this->assertEquals($block_name, $p->get_block_name(), 'Failed to identify the block name'); + $this->assertEquals($block_attributes, $p->get_block_attributes(), 'Failed to identify the block attributes'); + } + + static public function provider_test_finds_block_openers() + { + return [ + 'Opener without attributes' => ['', 'wp:paragraph', null], + 'Opener without the trailing whitespace' => ['', 'wp:paragraph', null], + 'Opener with a lot of trailing whitespace' => ['', 'wp:paragraph', null], + 'Opener with attributes' => ['', 'wp:paragraph', ['class' => 'wp-bold']], + 'Opener with empty attributes' => ['', 'wp:paragraph', []], + 'Opener with lots of whitespace around attributes' => [ + '', + 'wp:paragraph', + [ 'class'=> 'wp-bold'] + ], + 'Opener with object and array attributes' => [ + '', + 'wp:code', + [ 'meta' => [ 'language' => 'php', 'highlightedLines' => [14, 22] ], 'class' => 'dark' ] + ], + ]; + } + + /** + * + * @dataProvider provider_test_finds_block_closers + */ + public function test_find_block_closers($markup, $block_name) + { + $p = new WP_Block_Markup_Processor($markup); + $p->next_token(); + $this->assertEquals('#block-comment', $p->get_token_type(), 'Failed to identify the block comment'); + $this->assertEquals($block_name, $p->get_block_name(), 'Failed to identify the block name'); + $this->assertTrue($p->is_block_closer(), 'Failed to identify the block closer status'); + } + + static public function provider_test_finds_block_closers() + { + return [ + 'Closer without attributes' => ['', 'wp:paragraph'], + 'Closer without the trailing whitespace' => ['', 'wp:paragraph'], + 'Closer with a lot of trailing whitespace' => ['', 'wp:paragraph'], + ]; + } + + /** + * + * @dataProvider provider_test_treat_invalid_block_openers_as_comments + */ + public function test_treat_invalid_block_openers_as_comments($markup) + { + $p = new WP_Block_Markup_Processor($markup); + $p->next_token(); + $this->assertEquals('#comment', $p->get_token_type(), 'Failed to identify the comment'); + $this->assertFalse($p->get_block_name(), 'The block name wasn\'t false'); + $this->assertFalse($p->get_block_attributes(), 'The block attributes weren\'t false'); + } + + static public function provider_test_treat_invalid_block_openers_as_comments() + { + return [ + 'Opener with a line break before whitespace' => ["",], + 'Block name including !' => ['',], + 'Block name including a whitespace' => ['',], + 'No namespace in the block name' => ['',], + 'Non-object attributes' => ['',], + 'Invalid JSON as attributes – Double }} ' => ['',], + ]; + } + + /** + * + * @dataProvider provider_test_treat_invalid_block_closers_as_comments + */ + public function test_treat_invalid_block_closers_as_comments($markup) + { + $p = new WP_Block_Markup_Processor($markup); + $p->next_token(); + $this->assertEquals('#comment', $p->get_token_type(), 'Failed to identify the comment'); + $this->assertFalse($p->get_block_name(), 'The block name wasn\'t false'); + $this->assertFalse($p->get_block_attributes(), 'The block attributes weren\'t false'); + } + + static public function provider_test_treat_invalid_block_closers_as_comments() + { + return [ + 'Closer with a line break before whitespace' => ["",], + 'Closer with attributes' => ['',], + 'Closer with solidus at the end (before whitespace)' => ['',], + 'Closer with solidus at the end (after whitespace)' => ['',], + ]; + } + + + +} diff --git a/transfer-protocol/tests/WP_Block_Markup_Url_Processor_Tests.php b/transfer-protocol/tests/WP_Block_Markup_Url_Processor_Tests.php new file mode 100644 index 0000000..bc04965 --- /dev/null +++ b/transfer-protocol/tests/WP_Block_Markup_Url_Processor_Tests.php @@ -0,0 +1,99 @@ +next_url(); + +// for ($i = 0; $i < 15; $i++) { +// $p->next_token(); +// if($p->get_token_type() === '#block-comment') { +// $updated_attrs = map_block_attributes($p->get_block_attributes(), function($key, $value) { +// if($key === 'url') { +// return 'https://example.com'; +// } +// return $value; +// }); +// $p->set_block_attributes($updated_attrs); +// echo substr($p->get_updated_html(), 0, 100) . "\n"; +// die(); +// } +// } + +//private function map_block_attributes( array $attributes, $mapper ) { +// $new_attributes = array(); +// foreach ( $attributes as $key => $value ) { +// if ( is_array( $value ) ) { +// $new_attributes[ $key ] = map_block_attributes( $value, $mapper ); +// } else { +// $new_attributes[ $key ] = $mapper( $key, $value ); +// } +// } +// +// return $new_attributes; +//} + + +class WP_Block_Markup_Url_Processor_Tests extends TestCase +{ + + /** + * + * @dataProvider provider_test_finds_next_url + */ + public function test_next_url_finds_the_url($url, $markup) + { + $p = new WP_Block_Markup_Url_Processor($markup); + $this->assertTrue($p->next_url(), 'Failed to find the URL in the markup.'); + $this->assertEquals($url, $p->get_url(), 'Found a URL in the markup, but it wasn\'t the expected one.'); + } + + static public function provider_test_finds_next_url() + { + return [ + 'In the tag' => ['https://wordpress.org', ''], + 'In the first block attribute, when it contains just the URL' => [ + 'https://mysite.com/wp-content/image.png', + '' + ], + 'In the second block attribute, when it contains just the URL' => [ + 'https://mysite.com/wp-content/image.png', + '' + ], + ]; + } + + public function test_next_url_returns_false_once_theres_no_more_urls( ) { + $markup = ''; + $p = new WP_Block_Markup_Url_Processor( $markup ); + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertFalse( $p->next_url(), 'Found more URLs than expected.' ); + } + + public function test_next_url_finds_urls_in_multiple_attributes( ) { + $markup = ''; + $p = new WP_Block_Markup_Url_Processor( $markup ); + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertEquals( 'https://first-url.org', $p->get_url(), 'Found a URL in the markup, but it wasn\'t the expected one.' ); + + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertEquals( 'https://mysite.com/wp-content/image.png', $p->get_url(), 'Found a URL in the markup, but it wasn\'t the expected one.' ); + } + + public function test_next_url_finds_urls_in_multiple_tags( ) { + $markup = ''; + $p = new WP_Block_Markup_Url_Processor( $markup ); + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertEquals( 'https://first-url.org', $p->get_url(), 'Found a URL in the markup, but it wasn\'t the expected one.' ); + + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertEquals( 'https://mysite.com/wp-content/image.png', $p->get_url(), 'Found a URL in the markup, but it wasn\'t the expected one.' ); + + $this->assertTrue( $p->next_url(), 'Failed to find the URL in the markup.' ); + $this->assertEquals( 'https://third-url.org', $p->get_url(), 'Found a URL in the markup, but it wasn\'t the expected one.' ); + } + +} diff --git a/transfer-protocol/tests/urltestdata.json b/transfer-protocol/tests/urltestdata.json new file mode 100644 index 0000000..9dafdc7 --- /dev/null +++ b/transfer-protocol/tests/urltestdata.json @@ -0,0 +1,9801 @@ +[ + "See ../README.md for a description of the format.", + { + "input": "http://example\t.\norg", + "base": "http://example.org/foo/bar", + "href": "http://example.org/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://user:pass@foo:21/bar;par?b#c", + "base": "http://example.org/foo/bar", + "href": "http://user:pass@foo:21/bar;par?b#c", + "origin": "http://foo:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "foo:21", + "hostname": "foo", + "port": "21", + "pathname": "/bar;par", + "search": "?b", + "hash": "#c" + }, + { + "input": "https://test:@test", + "base": null, + "href": "https://test@test/", + "origin": "https://test", + "protocol": "https:", + "username": "test", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://:@test", + "base": null, + "href": "https://test/", + "origin": "https://test", + "protocol": "https:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://test:@test/x", + "base": null, + "href": "non-special://test@test/x", + "origin": "null", + "protocol": "non-special:", + "username": "test", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "non-special://:@test/x", + "base": null, + "href": "non-special://test/x", + "origin": "null", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "http:foo.com", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/foo.com", + "search": "", + "hash": "" + }, + { + "input": "\t :foo.com \n", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com", + "search": "", + "hash": "" + }, + { + "input": " foo.com ", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/foo.com", + "search": "", + "hash": "" + }, + { + "input": "a:\t foo.com", + "base": "http://example.org/foo/bar", + "href": "a: foo.com", + "origin": "null", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": " foo.com", + "search": "", + "hash": "" + }, + { + "input": "http://f:21/ b ? d # e ", + "base": "http://example.org/foo/bar", + "href": "http://f:21/%20b%20?%20d%20#%20e", + "origin": "http://f:21", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:21", + "hostname": "f", + "port": "21", + "pathname": "/%20b%20", + "search": "?%20d%20", + "hash": "#%20e" + }, + { + "input": "lolscheme:x x#x x", + "base": null, + "href": "lolscheme:x x#x%20x", + "protocol": "lolscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "x x", + "search": "", + "hash": "#x%20x" + }, + { + "input": "http://f:/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:0/c", + "base": "http://example.org/foo/bar", + "href": "http://f:0/c", + "origin": "http://f:0", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:0", + "hostname": "f", + "port": "0", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:00000000000000/c", + "base": "http://example.org/foo/bar", + "href": "http://f:0/c", + "origin": "http://f:0", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:0", + "hostname": "f", + "port": "0", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:00000000000000000000080/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:b/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f: /c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f:\n/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:fifty-two/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "non-special://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f: 21 / b ? d # e ", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": " \t", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": ":foo.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com/", + "search": "", + "hash": "" + }, + { + "input": ":foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com/", + "search": "", + "hash": "" + }, + { + "input": ":", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:", + "search": "", + "hash": "" + }, + { + "input": ":a", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:a", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:a", + "search": "", + "hash": "" + }, + { + "input": ":/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:/", + "search": "", + "hash": "" + }, + { + "input": ":\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:/", + "search": "", + "hash": "" + }, + { + "input": ":#", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:#", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:", + "search": "", + "hash": "" + }, + { + "input": "#", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "#/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#/" + }, + { + "input": "#\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#\\", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#\\" + }, + { + "input": "#;?", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#;?", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#;?" + }, + { + "input": "?", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar?", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": ":23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:23", + "search": "", + "hash": "" + }, + { + "input": "/:23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/:23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/:23", + "search": "", + "hash": "" + }, + { + "input": "\\x", + "base": "http://example.org/foo/bar", + "href": "http://example.org/x", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "\\\\x\\hello", + "base": "http://example.org/foo/bar", + "href": "http://x/hello", + "origin": "http://x", + "protocol": "http:", + "username": "", + "password": "", + "host": "x", + "hostname": "x", + "port": "", + "pathname": "/hello", + "search": "", + "hash": "" + }, + { + "input": "::", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/::", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/::", + "search": "", + "hash": "" + }, + { + "input": "::23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/::23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/::23", + "search": "", + "hash": "" + }, + { + "input": "foo://", + "base": "http://example.org/foo/bar", + "href": "foo://", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@c:29/d", + "base": "http://example.org/foo/bar", + "href": "http://a:b@c:29/d", + "origin": "http://c:29", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "c:29", + "hostname": "c", + "port": "29", + "pathname": "/d", + "search": "", + "hash": "" + }, + { + "input": "http::@c:29", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:@c:29", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:@c:29", + "search": "", + "hash": "" + }, + { + "input": "http://&a:foo(b]c@d:2/", + "base": "http://example.org/foo/bar", + "href": "http://&a:foo(b%5Dc@d:2/", + "origin": "http://d:2", + "protocol": "http:", + "username": "&a", + "password": "foo(b%5Dc", + "host": "d:2", + "hostname": "d", + "port": "2", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://::@c@d:2", + "base": "http://example.org/foo/bar", + "href": "http://:%3A%40c@d:2/", + "origin": "http://d:2", + "protocol": "http:", + "username": "", + "password": "%3A%40c", + "host": "d:2", + "hostname": "d", + "port": "2", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo.com:b@d/", + "base": "http://example.org/foo/bar", + "href": "http://foo.com:b@d/", + "origin": "http://d", + "protocol": "http:", + "username": "foo.com", + "password": "b", + "host": "d", + "hostname": "d", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo.com/\\@", + "base": "http://example.org/foo/bar", + "href": "http://foo.com//@", + "origin": "http://foo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.com", + "hostname": "foo.com", + "port": "", + "pathname": "//@", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://foo.com/", + "origin": "http://foo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.com", + "hostname": "foo.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\a\\b:c\\d@foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://a/b:c/d@foo.com/", + "origin": "http://a", + "protocol": "http:", + "username": "", + "password": "", + "host": "a", + "hostname": "a", + "port": "", + "pathname": "/b:c/d@foo.com/", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@c\\", + "base": null, + "href": "http://a:b@c/", + "origin": "http://c", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "c", + "hostname": "c", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://a@b\\c", + "base": null, + "href": "ws://a@b/c", + "origin": "ws://b", + "protocol": "ws:", + "username": "a", + "password": "", + "host": "b", + "hostname": "b", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "foo:/", + "base": "http://example.org/foo/bar", + "href": "foo:/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "foo:/bar.com/", + "base": "http://example.org/foo/bar", + "href": "foo:/bar.com/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/bar.com/", + "search": "", + "hash": "" + }, + { + "input": "foo://///////", + "base": "http://example.org/foo/bar", + "href": "foo://///////", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///////", + "search": "", + "hash": "" + }, + { + "input": "foo://///////bar.com/", + "base": "http://example.org/foo/bar", + "href": "foo://///////bar.com/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///////bar.com/", + "search": "", + "hash": "" + }, + { + "input": "foo:////://///", + "base": "http://example.org/foo/bar", + "href": "foo:////://///", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//://///", + "search": "", + "hash": "" + }, + { + "input": "c:/foo", + "base": "http://example.org/foo/bar", + "href": "c:/foo", + "origin": "null", + "protocol": "c:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "//foo/bar", + "base": "http://example.org/foo/bar", + "href": "http://foo/bar", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/bar", + "search": "", + "hash": "" + }, + { + "input": "http://foo/path;a??e#f#g", + "base": "http://example.org/foo/bar", + "href": "http://foo/path;a??e#f#g", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/path;a", + "search": "??e", + "hash": "#f#g" + }, + { + "input": "http://foo/abcd?efgh?ijkl", + "base": "http://example.org/foo/bar", + "href": "http://foo/abcd?efgh?ijkl", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/abcd", + "search": "?efgh?ijkl", + "hash": "" + }, + { + "input": "http://foo/abcd#foo?bar", + "base": "http://example.org/foo/bar", + "href": "http://foo/abcd#foo?bar", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/abcd", + "search": "", + "hash": "#foo?bar" + }, + { + "input": "[61:24:74]:98", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/[61:24:74]:98", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/[61:24:74]:98", + "search": "", + "hash": "" + }, + { + "input": "http:[61:27]/:foo", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/[61:27]/:foo", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/[61:27]/:foo", + "search": "", + "hash": "" + }, + { + "input": "http://[1::2]:3:4", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1]", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1]:80", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://[2001::1]", + "base": "http://example.org/foo/bar", + "href": "http://[2001::1]/", + "origin": "http://[2001::1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[2001::1]", + "hostname": "[2001::1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[::127.0.0.1]", + "base": "http://example.org/foo/bar", + "href": "http://[::7f00:1]/", + "origin": "http://[::7f00:1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[::7f00:1]", + "hostname": "[::7f00:1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[::127.0.0.1.]", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://[0:0:0:0:0:0:13.1.68.3]", + "base": "http://example.org/foo/bar", + "href": "http://[::d01:4403]/", + "origin": "http://[::d01:4403]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[::d01:4403]", + "hostname": "[::d01:4403]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[2001::1]:80", + "base": "http://example.org/foo/bar", + "href": "http://[2001::1]/", + "origin": "http://[2001::1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[2001::1]", + "hostname": "[2001::1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/example.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/example.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftp:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:/example.com/", + "base": "http://example.org/foo/bar", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:/example.com/", + "base": "http://example.org/foo/bar", + "href": "madeupscheme:/example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file:/example.com/", + "base": "http://example.org/foo/bar", + "href": "file:///example.com/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file://example:1/", + "base": null, + "failure": true + }, + { + "input": "file://example:test/", + "base": null, + "failure": true + }, + { + "input": "file://example%/", + "base": null, + "failure": true + }, + { + "input": "file://[example]/", + "base": null, + "failure": true + }, + { + "input": "ftps:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ftps:/example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:/example.com/", + "base": "http://example.org/foo/bar", + "href": "gopher:/example.com/", + "origin": "null", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ws:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:/example.com/", + "base": "http://example.org/foo/bar", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/example.com/", + "base": "http://example.org/foo/bar", + "href": "data:/example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/example.com/", + "base": "http://example.org/foo/bar", + "href": "javascript:/example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/example.com/", + "base": "http://example.org/foo/bar", + "href": "mailto:/example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "http:example.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/example.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftp:example.com/", + "base": "http://example.org/foo/bar", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:example.com/", + "base": "http://example.org/foo/bar", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:example.com/", + "base": "http://example.org/foo/bar", + "href": "madeupscheme:example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:example.com/", + "base": "http://example.org/foo/bar", + "href": "ftps:example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:example.com/", + "base": "http://example.org/foo/bar", + "href": "gopher:example.com/", + "origin": "null", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ws:example.com/", + "base": "http://example.org/foo/bar", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:example.com/", + "base": "http://example.org/foo/bar", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:example.com/", + "base": "http://example.org/foo/bar", + "href": "data:example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:example.com/", + "base": "http://example.org/foo/bar", + "href": "javascript:example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:example.com/", + "base": "http://example.org/foo/bar", + "href": "mailto:example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "/a/b/c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/b/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/b/c", + "search": "", + "hash": "" + }, + { + "input": "/a/ /c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/%20/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/%20/c", + "search": "", + "hash": "" + }, + { + "input": "/a%2fc", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a%2fc", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a%2fc", + "search": "", + "hash": "" + }, + { + "input": "/a/%2f/c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/%2f/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/%2f/c", + "search": "", + "hash": "" + }, + { + "input": "#β", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#%CE%B2", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#%CE%B2" + }, + { + "input": "data:text/html,test#test", + "base": "http://example.org/foo/bar", + "href": "data:text/html,test#test", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "text/html,test", + "search": "", + "hash": "#test" + }, + { + "input": "tel:1234567890", + "base": "http://example.org/foo/bar", + "href": "tel:1234567890", + "origin": "null", + "protocol": "tel:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "1234567890", + "search": "", + "hash": "" + }, + "# Based on https://felixfbecker.github.io/whatwg-url-custom-host-repro/", + { + "input": "ssh://example.com/foo/bar.git", + "base": "http://example.org/", + "href": "ssh://example.com/foo/bar.git", + "origin": "null", + "protocol": "ssh:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/bar.git", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html", + { + "input": "file:c:\\foo\\bar.html", + "base": "file:///tmp/mock/path", + "href": "file:///c:/foo/bar.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar.html", + "search": "", + "hash": "" + }, + { + "input": " File:c|////foo\\bar.html", + "base": "file:///tmp/mock/path", + "href": "file:///c:////foo/bar.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:////foo/bar.html", + "search": "", + "hash": "" + }, + { + "input": "C|/foo/bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/C|\\foo\\bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "//C|/foo/bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "//server/file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "\\\\server\\file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "/\\server/file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "file:///foo/bar.txt", + "base": "file:///tmp/mock/path", + "href": "file:///foo/bar.txt", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/foo/bar.txt", + "search": "", + "hash": "" + }, + { + "input": "file:///home/me", + "base": "file:///tmp/mock/path", + "href": "file:///home/me", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/home/me", + "search": "", + "hash": "" + }, + { + "input": "//", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///test", + "base": "file:///tmp/mock/path", + "href": "file:///test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "file://test", + "base": "file:///tmp/mock/path", + "href": "file://test/", + "protocol": "file:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost/", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost/test", + "base": "file:///tmp/mock/path", + "href": "file:///test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "test", + "base": "file:///tmp/mock/path", + "href": "file:///tmp/mock/test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/tmp/mock/test", + "search": "", + "hash": "" + }, + { + "input": "file:test", + "base": "file:///tmp/mock/path", + "href": "file:///tmp/mock/test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/tmp/mock/test", + "search": "", + "hash": "" + }, + { + "input": "file:///w|m", + "base": null, + "href": "file:///w|m", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/w|m", + "search": "", + "hash": "" + }, + { + "input": "file:///w||m", + "base": null, + "href": "file:///w||m", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/w||m", + "search": "", + "hash": "" + }, + { + "input": "file:///w|/m", + "base": null, + "href": "file:///w:/m", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/w:/m", + "search": "", + "hash": "" + }, + { + "input": "file:C|/m/", + "base": null, + "href": "file:///C:/m/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/m/", + "search": "", + "hash": "" + }, + { + "input": "file:C||/m/", + "base": null, + "href": "file:///C||/m/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C||/m/", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js", + { + "input": "http://example.com/././foo", + "base": null, + "href": "http://example.com/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/./.foo", + "base": null, + "href": "http://example.com/.foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/.foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/.", + "base": null, + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/./", + "base": null, + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/..", + "base": null, + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../", + "base": null, + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/..bar", + "base": null, + "href": "http://example.com/foo/..bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/..bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../ton", + "base": null, + "href": "http://example.com/foo/ton", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/ton", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../ton/../../a", + "base": null, + "href": "http://example.com/a", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/a", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/../../..", + "base": null, + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/../../../ton", + "base": null, + "href": "http://example.com/ton", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/ton", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e", + "base": null, + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e%2", + "base": null, + "href": "http://example.com/foo/%2e%2", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/%2e%2", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar", + "base": null, + "href": "http://example.com/%2e.bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%2e.bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com////../..", + "base": null, + "href": "http://example.com//", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar//../..", + "base": null, + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar//..", + "base": null, + "href": "http://example.com/foo/bar/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/bar/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo", + "base": null, + "href": "http://example.com/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%20foo", + "base": null, + "href": "http://example.com/%20foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%20foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%", + "base": null, + "href": "http://example.com/foo%", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2", + "base": null, + "href": "http://example.com/foo%2", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2zbar", + "base": null, + "href": "http://example.com/foo%2zbar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2zbar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2©zbar", + "base": null, + "href": "http://example.com/foo%2%C3%82%C2%A9zbar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2%C3%82%C2%A9zbar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%41%7a", + "base": null, + "href": "http://example.com/foo%41%7a", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%41%7a", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo\t‘%91", + "base": null, + "href": "http://example.com/foo%C2%91%91", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%C2%91%91", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%00%51", + "base": null, + "href": "http://example.com/foo%00%51", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%00%51", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/(%28:%3A%29)", + "base": null, + "href": "http://example.com/(%28:%3A%29)", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/(%28:%3A%29)", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%3A%3a%3C%3c", + "base": null, + "href": "http://example.com/%3A%3a%3C%3c", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%3A%3a%3C%3c", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo\tbar", + "base": null, + "href": "http://example.com/foobar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foobar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com\\\\foo\\\\bar", + "base": null, + "href": "http://example.com//foo//bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "//foo//bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", + "base": null, + "href": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%7Ffp3%3Eju%3Dduvgw%3Dd", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/@asdf%40", + "base": null, + "href": "http://example.com/@asdf%40", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/@asdf%40", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/你好你好", + "base": null, + "href": "http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/‥/foo", + "base": null, + "href": "http://example.com/%E2%80%A5/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E2%80%A5/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com//foo", + "base": null, + "href": "http://example.com/%EF%BB%BF/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%EF%BB%BF/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/‮/foo/‭/bar", + "base": null, + "href": "http://example.com/%E2%80%AE/foo/%E2%80%AD/bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E2%80%AE/foo/%E2%80%AD/bar", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js", + { + "input": "http://www.google.com/foo?bar=baz#", + "base": null, + "href": "http://www.google.com/foo?bar=baz#", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "?bar=baz", + "hash": "" + }, + { + "input": "http://www.google.com/foo?bar=baz# »", + "base": null, + "href": "http://www.google.com/foo?bar=baz#%20%C2%BB", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "?bar=baz", + "hash": "#%20%C2%BB" + }, + { + "input": "data:test# »", + "base": null, + "href": "data:test#%20%C2%BB", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "", + "hash": "#%20%C2%BB" + }, + { + "input": "http://www.google.com", + "base": null, + "href": "http://www.google.com/", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.0x00A80001", + "base": null, + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://www/foo%2Ehtml", + "base": null, + "href": "http://www/foo%2Ehtml", + "origin": "http://www", + "protocol": "http:", + "username": "", + "password": "", + "host": "www", + "hostname": "www", + "port": "", + "pathname": "/foo%2Ehtml", + "search": "", + "hash": "" + }, + { + "input": "http://www/foo/%2E/html", + "base": null, + "href": "http://www/foo/html", + "origin": "http://www", + "protocol": "http:", + "username": "", + "password": "", + "host": "www", + "hostname": "www", + "port": "", + "pathname": "/foo/html", + "search": "", + "hash": "" + }, + { + "input": "http://user:pass@/", + "base": null, + "failure": true + }, + { + "input": "http://%25DOMAIN:foobar@foodomain.com/", + "base": null, + "href": "http://%25DOMAIN:foobar@foodomain.com/", + "origin": "http://foodomain.com", + "protocol": "http:", + "username": "%25DOMAIN", + "password": "foobar", + "host": "foodomain.com", + "hostname": "foodomain.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\www.google.com\\foo", + "base": null, + "href": "http://www.google.com/foo", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://foo:80/", + "base": null, + "href": "http://foo/", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo:81/", + "base": null, + "href": "http://foo:81/", + "origin": "http://foo:81", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "httpa://foo:80/", + "base": null, + "href": "httpa://foo:80/", + "origin": "null", + "protocol": "httpa:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo:-80/", + "base": null, + "failure": true + }, + { + "input": "https://foo:443/", + "base": null, + "href": "https://foo/", + "origin": "https://foo", + "protocol": "https:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://foo:80/", + "base": null, + "href": "https://foo:80/", + "origin": "https://foo:80", + "protocol": "https:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp://foo:21/", + "base": null, + "href": "ftp://foo/", + "origin": "ftp://foo", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp://foo:80/", + "base": null, + "href": "ftp://foo:80/", + "origin": "ftp://foo:80", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "gopher://foo:70/", + "base": null, + "href": "gopher://foo:70/", + "origin": "null", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "foo:70", + "hostname": "foo", + "port": "70", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "gopher://foo:443/", + "base": null, + "href": "gopher://foo:443/", + "origin": "null", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "foo:443", + "hostname": "foo", + "port": "443", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:80/", + "base": null, + "href": "ws://foo/", + "origin": "ws://foo", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:81/", + "base": null, + "href": "ws://foo:81/", + "origin": "ws://foo:81", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:443/", + "base": null, + "href": "ws://foo:443/", + "origin": "ws://foo:443", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:443", + "hostname": "foo", + "port": "443", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:815/", + "base": null, + "href": "ws://foo:815/", + "origin": "ws://foo:815", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:815", + "hostname": "foo", + "port": "815", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:80/", + "base": null, + "href": "wss://foo:80/", + "origin": "wss://foo:80", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:81/", + "base": null, + "href": "wss://foo:81/", + "origin": "wss://foo:81", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:443/", + "base": null, + "href": "wss://foo/", + "origin": "wss://foo", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:815/", + "base": null, + "href": "wss://foo:815/", + "origin": "wss://foo:815", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:815", + "hostname": "foo", + "port": "815", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/example.com/", + "base": null, + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp:/example.com/", + "base": null, + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:/example.com/", + "base": null, + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:/example.com/", + "base": null, + "href": "madeupscheme:/example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file:/example.com/", + "base": null, + "href": "file:///example.com/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:/example.com/", + "base": null, + "href": "ftps:/example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:/example.com/", + "base": null, + "href": "gopher:/example.com/", + "origin": "null", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ws:/example.com/", + "base": null, + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:/example.com/", + "base": null, + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/example.com/", + "base": null, + "href": "data:/example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/example.com/", + "base": null, + "href": "javascript:/example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/example.com/", + "base": null, + "href": "mailto:/example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "http:example.com/", + "base": null, + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp:example.com/", + "base": null, + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:example.com/", + "base": null, + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:example.com/", + "base": null, + "href": "madeupscheme:example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:example.com/", + "base": null, + "href": "ftps:example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:example.com/", + "base": null, + "href": "gopher:example.com/", + "origin": "null", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ws:example.com/", + "base": null, + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:example.com/", + "base": null, + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:example.com/", + "base": null, + "href": "data:example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:example.com/", + "base": null, + "href": "javascript:example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:example.com/", + "base": null, + "href": "mailto:example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html", + { + "input": "http:@www.example.com", + "base": null, + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/@www.example.com", + "base": null, + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://@www.example.com", + "base": null, + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:a:b@www.example.com", + "base": null, + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/a:b@www.example.com", + "base": null, + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@www.example.com", + "base": null, + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://@pple.com", + "base": null, + "href": "http://pple.com/", + "origin": "http://pple.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "pple.com", + "hostname": "pple.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http::b@www.example.com", + "base": null, + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/:b@www.example.com", + "base": null, + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://:b@www.example.com", + "base": null, + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/:@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http://user@/www.example.com", + "base": null, + "failure": true + }, + { + "input": "http:@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http:/@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http://@/www.example.com", + "base": null, + "failure": true + }, + { + "input": "https:@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http:a:b@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http:/a:b@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http://a:b@/www.example.com", + "base": null, + "failure": true + }, + { + "input": "http::@/www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http:a:@www.example.com", + "base": null, + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/a:@www.example.com", + "base": null, + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:@www.example.com", + "base": null, + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://www.@pple.com", + "base": null, + "href": "http://www.@pple.com/", + "origin": "http://pple.com", + "protocol": "http:", + "username": "www.", + "password": "", + "host": "pple.com", + "hostname": "pple.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:@:www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http:/@:www.example.com", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "http://@:www.example.com", + "base": null, + "failure": true + }, + { + "input": "http://:@www.example.com", + "base": null, + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# Others", + { + "input": "/", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": ".", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "./test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../aaa/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/aaa/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/aaa/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../../test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "中/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/%E4%B8%AD/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/%E4%B8%AD/test.txt", + "search": "", + "hash": "" + }, + { + "input": "http://www.example2.com", + "base": "http://www.example.com/test", + "href": "http://www.example2.com/", + "origin": "http://www.example2.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example2.com", + "hostname": "www.example2.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "//www.example2.com", + "base": "http://www.example.com/test", + "href": "http://www.example2.com/", + "origin": "http://www.example2.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example2.com", + "hostname": "www.example2.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:...", + "base": "http://www.example.com/test", + "href": "file:///...", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/...", + "search": "", + "hash": "" + }, + { + "input": "file:..", + "base": "http://www.example.com/test", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:a", + "base": "http://www.example.com/test", + "href": "file:///a", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/a", + "search": "", + "hash": "" + }, + { + "input": "file:.", + "base": null, + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:.", + "base": "http://www.example.com/test", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html", + "Basic canonicalization, uppercase should be converted to lowercase", + { + "input": "http://ExAmPlE.CoM", + "base": "http://other.com/", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://example example.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://Goo%20 goo%7C|.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[:]", + "base": "http://other.com/", + "failure": true + }, + "U+3000 is mapped to U+0020 (space) which is disallowed", + { + "input": "http://GOO  goo.com", + "base": "http://other.com/", + "failure": true + }, + "Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored", + { + "input": "http://GOO​⁠goo.com", + "base": "http://other.com/", + "href": "http://googoo.com/", + "origin": "http://googoo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "googoo.com", + "hostname": "googoo.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Leading and trailing C0 control or space", + { + "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \r ", + "base": null, + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)", + { + "input": "http://www.foo。bar.com", + "base": "http://other.com/", + "href": "http://www.foo.bar.com/", + "origin": "http://www.foo.bar.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.foo.bar.com", + "hostname": "www.foo.bar.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0", + { + "input": "http://﷐zyx.com", + "base": "http://other.com/", + "failure": true + }, + "This is the same as previous but escaped", + { + "input": "http://%ef%b7%90zyx.com", + "base": "http://other.com/", + "failure": true + }, + "U+FFFD", + { + "input": "https://�", + "base": null, + "failure": true + }, + { + "input": "https://%EF%BF%BD", + "base": null, + "failure": true + }, + { + "input": "https://x/�?�#�", + "base": null, + "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD", + "origin": "https://x", + "protocol": "https:", + "username": "", + "password": "", + "host": "x", + "hostname": "x", + "port": "", + "pathname": "/%EF%BF%BD", + "search": "?%EF%BF%BD", + "hash": "#%EF%BF%BD" + }, + "Domain is ASCII, but a label is invalid IDNA", + { + "input": "http://a.b.c.xn--pokxncvks", + "base": null, + "failure": true + }, + { + "input": "http://10.0.0.xn--pokxncvks", + "base": null, + "failure": true + }, + "IDNA labels should be matched case-insensitively", + { + "input": "http://a.b.c.XN--pokxncvks", + "base": null, + "failure": true + }, + { + "input": "http://a.b.c.Xn--pokxncvks", + "base": null, + "failure": true + }, + { + "input": "http://10.0.0.XN--pokxncvks", + "base": null, + "failure": true + }, + { + "input": "http://10.0.0.xN--pokxncvks", + "base": null, + "failure": true + }, + "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", + { + "input": "http://Go.com", + "base": "http://other.com/", + "href": "http://go.com/", + "origin": "http://go.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "go.com", + "hostname": "go.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257", + { + "input": "http://%41.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%ef%bc%85%ef%bc%94%ef%bc%91.com", + "base": "http://other.com/", + "failure": true + }, + "...%00 in fullwidth should fail (also as escaped UTF-8 input)", + { + "input": "http://%00.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%ef%bc%85%ef%bc%90%ef%bc%90.com", + "base": "http://other.com/", + "failure": true + }, + "Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN", + { + "input": "http://你好你好", + "base": "http://other.com/", + "href": "http://xn--6qqa088eba/", + "origin": "http://xn--6qqa088eba", + "protocol": "http:", + "username": "", + "password": "", + "host": "xn--6qqa088eba", + "hostname": "xn--6qqa088eba", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://faß.ExAmPlE/", + "base": null, + "href": "https://xn--fa-hia.example/", + "origin": "https://xn--fa-hia.example", + "protocol": "https:", + "username": "", + "password": "", + "host": "xn--fa-hia.example", + "hostname": "xn--fa-hia.example", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://faß.ExAmPlE/", + "base": null, + "href": "sc://fa%C3%9F.ExAmPlE/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "fa%C3%9F.ExAmPlE", + "hostname": "fa%C3%9F.ExAmPlE", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191", + { + "input": "http://%zz%66%a.com", + "base": "http://other.com/", + "failure": true + }, + "If we get an invalid character that has been escaped.", + { + "input": "http://%25", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://hello%00", + "base": "http://other.com/", + "failure": true + }, + "Escaped numbers should be treated like IP addresses if they are.", + { + "input": "http://%30%78%63%30%2e%30%32%35%30.01", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://%30%78%63%30%2e%30%32%35%30.01%2e", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.0.257", + "base": "http://other.com/", + "failure": true + }, + "Invalid escaping in hosts causes failure", + { + "input": "http://%3g%78%63%30%2e%30%32%35%30%2E.01", + "base": "http://other.com/", + "failure": true + }, + "A space in a host causes failure", + { + "input": "http://192.168.0.1 hello", + "base": "http://other.com/", + "failure": true + }, + { + "input": "https://x x:12", + "base": null, + "failure": true + }, + "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP", + { + "input": "http://0Xc0.0250.01", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Domains with empty labels", + { + "input": "http://./", + "base": null, + "href": "http://./", + "origin": "http://.", + "protocol": "http:", + "username": "", + "password": "", + "host": ".", + "hostname": ".", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://../", + "base": null, + "href": "http://../", + "origin": "http://..", + "protocol": "http:", + "username": "", + "password": "", + "host": "..", + "hostname": "..", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Non-special domains with empty labels", + { + "input": "h://.", + "base": null, + "href": "h://.", + "origin": "null", + "protocol": "h:", + "username": "", + "password": "", + "host": ".", + "hostname": ".", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + "Broken IPv6", + { + "input": "http://[www.google.com]/", + "base": null, + "failure": true + }, + { + "input": "http://[google.com]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.3.4x]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.3.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::.1.2]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::.1]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::%31]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%5B::1]", + "base": "http://other.com/", + "failure": true + }, + "Misc Unicode", + { + "input": "http://foo:💩@example.com/bar", + "base": "http://other.com/", + "href": "http://foo:%F0%9F%92%A9@example.com/bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "foo", + "password": "%F0%9F%92%A9", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/bar", + "search": "", + "hash": "" + }, + "# resolving a fragment against any scheme succeeds", + { + "input": "#", + "base": "test:test", + "href": "test:test#", + "origin": "null", + "protocol": "test:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "", + "hash": "" + }, + { + "input": "#x", + "base": "mailto:x@x.com", + "href": "mailto:x@x.com#x", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "x@x.com", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "data:,", + "href": "data:,#x", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": ",", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "about:blank", + "href": "about:blank#x", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blank", + "search": "", + "hash": "#x" + }, + { + "input": "#x:y", + "base": "about:blank", + "href": "about:blank#x:y", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blank", + "search": "", + "hash": "#x:y" + }, + { + "input": "#", + "base": "test:test?test", + "href": "test:test?test#", + "origin": "null", + "protocol": "test:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "?test", + "hash": "" + }, + "# multiple @ in authority state", + { + "input": "https://@test@test@example:800/", + "base": "http://doesnotmatter/", + "href": "https://%40test%40test@example:800/", + "origin": "https://example:800", + "protocol": "https:", + "username": "%40test%40test", + "password": "", + "host": "example:800", + "hostname": "example", + "port": "800", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://@@@example", + "base": "http://doesnotmatter/", + "href": "https://%40%40@example/", + "origin": "https://example", + "protocol": "https:", + "username": "%40%40", + "password": "", + "host": "example", + "hostname": "example", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "non-az-09 characters", + { + "input": "http://`{}:`{}@h/`{}?`{}", + "base": "http://doesnotmatter/", + "href": "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}", + "origin": "http://h", + "protocol": "http:", + "username": "%60%7B%7D", + "password": "%60%7B%7D", + "host": "h", + "hostname": "h", + "port": "", + "pathname": "/%60%7B%7D", + "search": "?`{}", + "hash": "" + }, + "byte is ' and url is special", + { + "input": "http://host/?'", + "base": null, + "href": "http://host/?%27", + "origin": "http://host", + "protocol": "http:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/", + "search": "?%27", + "hash": "" + }, + { + "input": "notspecial://host/?'", + "base": null, + "href": "notspecial://host/?'", + "origin": "null", + "protocol": "notspecial:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/", + "search": "?'", + "hash": "" + }, + "# Credentials in base", + { + "input": "/some/path", + "base": "http://user@example.org/smth", + "href": "http://user@example.org/some/path", + "origin": "http://example.org", + "protocol": "http:", + "username": "user", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/some/path", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "http://user:pass@example.org:21/smth", + "href": "http://user:pass@example.org:21/smth", + "origin": "http://example.org:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "example.org:21", + "hostname": "example.org", + "port": "21", + "pathname": "/smth", + "search": "", + "hash": "" + }, + { + "input": "/some/path", + "base": "http://user:pass@example.org:21/smth", + "href": "http://user:pass@example.org:21/some/path", + "origin": "http://example.org:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "example.org:21", + "hostname": "example.org", + "port": "21", + "pathname": "/some/path", + "search": "", + "hash": "" + }, + "# a set of tests designed by zcorpan for relative URLs with unknown schemes", + { + "input": "i", + "base": "sc:sd", + "failure": true + }, + { + "input": "i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "i", + "base": "sc:/pa/pa", + "href": "sc:/pa/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/i", + "search": "", + "hash": "" + }, + { + "input": "i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "i", + "base": "sc:///pa/pa", + "href": "sc:///pa/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc:sd", + "failure": true + }, + { + "input": "../i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "../i", + "base": "sc:/pa/pa", + "href": "sc:/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc:///pa/pa", + "href": "sc:///i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc:sd", + "failure": true + }, + { + "input": "/i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "/i", + "base": "sc:/pa/pa", + "href": "sc:/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc:///pa/pa", + "href": "sc:///i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "?i", + "base": "sc:sd", + "failure": true + }, + { + "input": "?i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "?i", + "base": "sc:/pa/pa", + "href": "sc:/pa/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "?i", + "hash": "" + }, + { + "input": "?i", + "base": "sc://ho/pa", + "href": "sc://ho/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/pa", + "search": "?i", + "hash": "" + }, + { + "input": "?i", + "base": "sc:///pa/pa", + "href": "sc:///pa/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "?i", + "hash": "" + }, + { + "input": "#i", + "base": "sc:sd", + "href": "sc:sd#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "sd", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:sd/sd", + "href": "sc:sd/sd#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "sd/sd", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:/pa/pa", + "href": "sc:/pa/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc://ho/pa", + "href": "sc://ho/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/pa", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:///pa/pa", + "href": "sc:///pa/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "", + "hash": "#i" + }, + "# make sure that relative URL logic works on known typically non-relative schemes too", + { + "input": "about:/../", + "base": null, + "href": "about:/", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/../", + "base": null, + "href": "data:/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/../", + "base": null, + "href": "javascript:/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/../", + "base": null, + "href": "mailto:/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# unknown schemes and their hosts", + { + "input": "sc://ñ.test/", + "base": null, + "href": "sc://%C3%B1.test/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1.test", + "hostname": "%C3%B1.test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://%/", + "base": null, + "href": "sc://%/", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%", + "hostname": "%", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://@/", + "base": null, + "failure": true + }, + { + "input": "sc://te@s:t@/", + "base": null, + "failure": true + }, + { + "input": "sc://:/", + "base": null, + "failure": true + }, + { + "input": "sc://:12/", + "base": null, + "failure": true + }, + { + "input": "x", + "base": "sc://ñ", + "href": "sc://%C3%B1/x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + "# unknown schemes and backslashes", + { + "input": "sc:\\../", + "base": null, + "href": "sc:\\../", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "\\../", + "search": "", + "hash": "" + }, + "# unknown scheme with path looking like a password", + { + "input": "sc::a@example.net", + "base": null, + "href": "sc::a@example.net", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": ":a@example.net", + "search": "", + "hash": "" + }, + "# unknown scheme with bogus percent-encoding", + { + "input": "wow:%NBD", + "base": null, + "href": "wow:%NBD", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%NBD", + "search": "", + "hash": "" + }, + { + "input": "wow:%1G", + "base": null, + "href": "wow:%1G", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%1G", + "search": "", + "hash": "" + }, + "# unknown scheme with non-URL characters", + { + "input": "wow:￿", + "base": null, + "href": "wow:%EF%BF%BF", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%EF%BF%BF", + "search": "", + "hash": "" + }, + "Forbidden host code points", + { + "input": "sc://a\u0000b/", + "base": null, + "failure": true + }, + { + "input": "sc://a b/", + "base": null, + "failure": true + }, + { + "input": "sc://ab", + "base": null, + "failure": true + }, + { + "input": "sc://a[b/", + "base": null, + "failure": true + }, + { + "input": "sc://a\\b/", + "base": null, + "failure": true + }, + { + "input": "sc://a]b/", + "base": null, + "failure": true + }, + { + "input": "sc://a^b", + "base": null, + "failure": true + }, + { + "input": "sc://a|b/", + "base": null, + "failure": true + }, + "Forbidden host codepoints: tabs and newlines are removed during preprocessing", + { + "input": "foo://ho\tst/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://host/", + "password": "", + "pathname": "/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "" + }, + { + "input": "foo://ho\nst/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://host/", + "password": "", + "pathname": "/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "" + }, + { + "input": "foo://ho\rst/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://host/", + "password": "", + "pathname": "/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "" + }, + "Forbidden domain code-points", + { + "input": "http://a\u0000b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0001b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0002b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0003b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0004b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0005b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0006b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0007b/", + "base": null, + "failure": true + }, + { + "input": "http://a\bb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u000bb/", + "base": null, + "failure": true + }, + { + "input": "http://a\fb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u000eb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u000fb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0010b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0011b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0012b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0013b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0014b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0015b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0016b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0017b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0018b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u0019b/", + "base": null, + "failure": true + }, + { + "input": "http://a\u001ab/", + "base": null, + "failure": true + }, + { + "input": "http://a\u001bb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u001cb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u001db/", + "base": null, + "failure": true + }, + { + "input": "http://a\u001eb/", + "base": null, + "failure": true + }, + { + "input": "http://a\u001fb/", + "base": null, + "failure": true + }, + { + "input": "http://a b/", + "base": null, + "failure": true + }, + { + "input": "http://a%b/", + "base": null, + "failure": true + }, + { + "input": "http://ab", + "base": null, + "failure": true + }, + { + "input": "http://a[b/", + "base": null, + "failure": true + }, + { + "input": "http://a]b/", + "base": null, + "failure": true + }, + { + "input": "http://a^b", + "base": null, + "failure": true + }, + { + "input": "http://a|b/", + "base": null, + "failure": true + }, + { + "input": "http://ab/", + "base": null, + "failure": true + }, + "Forbidden domain codepoints: tabs and newlines are removed during preprocessing", + { + "input": "http://ho\tst/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "http://host/", + "password": "", + "pathname": "/", + "port": "", + "protocol": "http:", + "search": "", + "username": "" + }, + { + "input": "http://ho\nst/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "http://host/", + "password": "", + "pathname": "/", + "port": "", + "protocol": "http:", + "search": "", + "username": "" + }, + { + "input": "http://ho\rst/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "http://host/", + "password": "", + "pathname": "/", + "port": "", + "protocol": "http:", + "search": "", + "username": "" + }, + "Encoded forbidden domain codepoints in special URLs", + { + "input": "http://ho%00st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%01st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%02st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%03st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%04st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%05st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%06st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%07st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%08st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%09st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%0Ast/", + "base": null, + "failure": true + }, + { + "input": "http://ho%0Bst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%0Cst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%0Dst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%0Est/", + "base": null, + "failure": true + }, + { + "input": "http://ho%0Fst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%10st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%11st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%12st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%13st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%14st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%15st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%16st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%17st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%18st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%19st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%1Ast/", + "base": null, + "failure": true + }, + { + "input": "http://ho%1Bst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%1Cst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%1Dst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%1Est/", + "base": null, + "failure": true + }, + { + "input": "http://ho%1Fst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%20st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%23st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%25st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%2Fst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%3Ast/", + "base": null, + "failure": true + }, + { + "input": "http://ho%3Cst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%3Est/", + "base": null, + "failure": true + }, + { + "input": "http://ho%3Fst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%40st/", + "base": null, + "failure": true + }, + { + "input": "http://ho%5Bst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%5Cst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%5Dst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%7Cst/", + "base": null, + "failure": true + }, + { + "input": "http://ho%7Fst/", + "base": null, + "failure": true + }, + "Allowed host/domain code points", + { + "input": "http://!\"$&'()*+,-.;=_`{}~/", + "base": null, + "href": "http://!\"$&'()*+,-.;=_`{}~/", + "origin": "http://!\"$&'()*+,-.;=_`{}~", + "protocol": "http:", + "username": "", + "password": "", + "host": "!\"$&'()*+,-.;=_`{}~", + "hostname": "!\"$&'()*+,-.;=_`{}~", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\u000b\f\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f!\"$%&'()*+,-.;=_`{}~/", + "base": null, + "href": "sc://%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\"$%&'()*+,-.;=_`{}~/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\"$%&'()*+,-.;=_`{}~", + "hostname": "%01%02%03%04%05%06%07%08%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%7F!\"$%&'()*+,-.;=_`{}~", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# Hosts and percent-encoding", + { + "input": "ftp://example.com%80/", + "base": null, + "failure": true + }, + { + "input": "ftp://example.com%A0/", + "base": null, + "failure": true + }, + { + "input": "https://example.com%80/", + "base": null, + "failure": true + }, + { + "input": "https://example.com%A0/", + "base": null, + "failure": true + }, + { + "input": "ftp://%e2%98%83", + "base": null, + "href": "ftp://xn--n3h/", + "origin": "ftp://xn--n3h", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "xn--n3h", + "hostname": "xn--n3h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://%e2%98%83", + "base": null, + "href": "https://xn--n3h/", + "origin": "https://xn--n3h", + "protocol": "https:", + "username": "", + "password": "", + "host": "xn--n3h", + "hostname": "xn--n3h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# tests from jsdom/whatwg-url designed for code coverage", + { + "input": "http://127.0.0.1:10100/relative_import.html", + "base": null, + "href": "http://127.0.0.1:10100/relative_import.html", + "origin": "http://127.0.0.1:10100", + "protocol": "http:", + "username": "", + "password": "", + "host": "127.0.0.1:10100", + "hostname": "127.0.0.1", + "port": "10100", + "pathname": "/relative_import.html", + "search": "", + "hash": "" + }, + { + "input": "http://facebook.com/?foo=%7B%22abc%22", + "base": null, + "href": "http://facebook.com/?foo=%7B%22abc%22", + "origin": "http://facebook.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "facebook.com", + "hostname": "facebook.com", + "port": "", + "pathname": "/", + "search": "?foo=%7B%22abc%22", + "hash": "" + }, + { + "input": "https://localhost:3000/jqueryui@1.2.3", + "base": null, + "href": "https://localhost:3000/jqueryui@1.2.3", + "origin": "https://localhost:3000", + "protocol": "https:", + "username": "", + "password": "", + "host": "localhost:3000", + "hostname": "localhost", + "port": "3000", + "pathname": "/jqueryui@1.2.3", + "search": "", + "hash": "" + }, + "# tab/LF/CR", + { + "input": "h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg", + "base": null, + "href": "http://host:9000/path?query#frag", + "origin": "http://host:9000", + "protocol": "http:", + "username": "", + "password": "", + "host": "host:9000", + "hostname": "host", + "port": "9000", + "pathname": "/path", + "search": "?query", + "hash": "#frag" + }, + "# Stringification of URL.searchParams", + { + "input": "?a=b&c=d", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar?a=b&c=d", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "?a=b&c=d", + "searchParams": "a=b&c=d", + "hash": "" + }, + { + "input": "??a=b&c=d", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar??a=b&c=d", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "??a=b&c=d", + "searchParams": "%3Fa=b&c=d", + "hash": "" + }, + "# Scheme only", + { + "input": "http:", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "searchParams": "", + "hash": "" + }, + { + "input": "http:", + "base": "https://example.org/foo/bar", + "failure": true + }, + { + "input": "sc:", + "base": "https://example.org/foo/bar", + "href": "sc:", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "searchParams": "", + "hash": "" + }, + "# Percent encoding of fragments", + { + "input": "http://foo.bar/baz?qux#foo\bbar", + "base": null, + "href": "http://foo.bar/baz?qux#foo%08bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%08bar" + }, + { + "input": "http://foo.bar/baz?qux#foo\"bar", + "base": null, + "href": "http://foo.bar/baz?qux#foo%22bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%22bar" + }, + { + "input": "http://foo.bar/baz?qux#foobar", + "base": null, + "href": "http://foo.bar/baz?qux#foo%3Ebar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%3Ebar" + }, + { + "input": "http://foo.bar/baz?qux#foo`bar", + "base": null, + "href": "http://foo.bar/baz?qux#foo%60bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%60bar" + }, + "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)", + { + "input": "http://1.2.3.4/", + "base": "http://other.com/", + "href": "http://1.2.3.4/", + "origin": "http://1.2.3.4", + "protocol": "http:", + "username": "", + "password": "", + "host": "1.2.3.4", + "hostname": "1.2.3.4", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://1.2.3.4./", + "base": "http://other.com/", + "href": "http://1.2.3.4/", + "origin": "http://1.2.3.4", + "protocol": "http:", + "username": "", + "password": "", + "host": "1.2.3.4", + "hostname": "1.2.3.4", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.257", + "base": "http://other.com/", + "href": "http://192.168.1.1/", + "origin": "http://192.168.1.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.1.1", + "hostname": "192.168.1.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.257.", + "base": "http://other.com/", + "href": "http://192.168.1.1/", + "origin": "http://192.168.1.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.1.1", + "hostname": "192.168.1.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.257.com", + "base": "http://other.com/", + "href": "http://192.168.257.com/", + "origin": "http://192.168.257.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.257.com", + "hostname": "192.168.257.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://256", + "base": "http://other.com/", + "href": "http://0.0.1.0/", + "origin": "http://0.0.1.0", + "protocol": "http:", + "username": "", + "password": "", + "host": "0.0.1.0", + "hostname": "0.0.1.0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://256.com", + "base": "http://other.com/", + "href": "http://256.com/", + "origin": "http://256.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "256.com", + "hostname": "256.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999", + "base": "http://other.com/", + "href": "http://59.154.201.255/", + "origin": "http://59.154.201.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "59.154.201.255", + "hostname": "59.154.201.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999.", + "base": "http://other.com/", + "href": "http://59.154.201.255/", + "origin": "http://59.154.201.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "59.154.201.255", + "hostname": "59.154.201.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999.com", + "base": "http://other.com/", + "href": "http://999999999.com/", + "origin": "http://999999999.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "999999999.com", + "hostname": "999999999.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://10000000000", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://10000000000.com", + "base": "http://other.com/", + "href": "http://10000000000.com/", + "origin": "http://10000000000.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "10000000000.com", + "hostname": "10000000000.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://4294967295", + "base": "http://other.com/", + "href": "http://255.255.255.255/", + "origin": "http://255.255.255.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "255.255.255.255", + "hostname": "255.255.255.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://4294967296", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://0xffffffff", + "base": "http://other.com/", + "href": "http://255.255.255.255/", + "origin": "http://255.255.255.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "255.255.255.255", + "hostname": "255.255.255.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0xffffffff1", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://256.256.256.256", + "base": "http://other.com/", + "failure": true + }, + { + "input": "https://0x.0x.0", + "base": null, + "href": "https://0.0.0.0/", + "origin": "https://0.0.0.0", + "protocol": "https:", + "username": "", + "password": "", + "host": "0.0.0.0", + "hostname": "0.0.0.0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)", + { + "input": "https://0x100000000/test", + "base": null, + "failure": true + }, + { + "input": "https://256.0.0.1/test", + "base": null, + "failure": true + }, + "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", + { + "input": "file:///C%3A/", + "base": null, + "href": "file:///C%3A/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C%3A/", + "search": "", + "hash": "" + }, + { + "input": "file:///C%7C/", + "base": null, + "href": "file:///C%7C/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C%7C/", + "search": "", + "hash": "" + }, + { + "input": "file://%43%3A", + "base": null, + "failure": true + }, + { + "input": "file://%43%7C", + "base": null, + "failure": true + }, + { + "input": "file://%43|", + "base": null, + "failure": true + }, + { + "input": "file://C%7C", + "base": null, + "failure": true + }, + { + "input": "file://%43%7C/", + "base": null, + "failure": true + }, + { + "input": "https://%43%7C/", + "base": null, + "failure": true + }, + { + "input": "asdf://%43|/", + "base": null, + "failure": true + }, + { + "input": "asdf://%43%7C/", + "base": null, + "href": "asdf://%43%7C/", + "origin": "null", + "protocol": "asdf:", + "username": "", + "password": "", + "host": "%43%7C", + "hostname": "%43%7C", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)", + { + "input": "pix/submit.gif", + "base": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html", + "href": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///C:/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# More file URL tests by zcorpan and annevk", + { + "input": "/", + "base": "file:///C:/a/b", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "/", + "base": "file://h/C:/a/b", + "href": "file://h/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "h", + "hostname": "h", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "/", + "base": "file://h/a/b", + "href": "file://h/", + "protocol": "file:", + "username": "", + "password": "", + "host": "h", + "hostname": "h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "//d:", + "base": "file:///C:/a/b", + "href": "file:///d:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/d:", + "search": "", + "hash": "" + }, + { + "input": "//d:/..", + "base": "file:///C:/a/b", + "href": "file:///d:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/d:/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///ab:/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///1:/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "file:///test?test#test", + "href": "file:///test?test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "" + }, + { + "input": "file:", + "base": "file:///test?test#test", + "href": "file:///test?test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "" + }, + { + "input": "?x", + "base": "file:///test?test#test", + "href": "file:///test?x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?x", + "hash": "" + }, + { + "input": "file:?x", + "base": "file:///test?test#test", + "href": "file:///test?x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?x", + "hash": "" + }, + { + "input": "#x", + "base": "file:///test?test#test", + "href": "file:///test?test#x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "#x" + }, + { + "input": "file:#x", + "base": "file:///test?test#test", + "href": "file:///test?test#x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "#x" + }, + "# File URLs and many (back)slashes", + { + "input": "file:\\\\//", + "base": null, + "href": "file:////", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "file:\\\\\\\\", + "base": null, + "href": "file:////", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "file:\\\\\\\\?fox", + "base": null, + "href": "file:////?fox", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "?fox", + "hash": "" + }, + { + "input": "file:\\\\\\\\#guppy", + "base": null, + "href": "file:////#guppy", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "#guppy" + }, + { + "input": "file://spider///", + "base": null, + "href": "file://spider///", + "protocol": "file:", + "username": "", + "password": "", + "host": "spider", + "hostname": "spider", + "port": "", + "pathname": "///", + "search": "", + "hash": "" + }, + { + "input": "file:\\\\localhost//", + "base": null, + "href": "file:////", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "file:///localhost//cat", + "base": null, + "href": "file:///localhost//cat", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/localhost//cat", + "search": "", + "hash": "" + }, + { + "input": "file://\\/localhost//cat", + "base": null, + "href": "file:////localhost//cat", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//localhost//cat", + "search": "", + "hash": "" + }, + { + "input": "file://localhost//a//../..//", + "base": null, + "href": "file://///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///", + "search": "", + "hash": "" + }, + { + "input": "/////mouse", + "base": "file:///elephant", + "href": "file://///mouse", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///mouse", + "search": "", + "hash": "" + }, + { + "input": "\\//pig", + "base": "file://lion/", + "href": "file:///pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pig", + "search": "", + "hash": "" + }, + { + "input": "\\/localhost//pig", + "base": "file://lion/", + "href": "file:////pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//pig", + "search": "", + "hash": "" + }, + { + "input": "//localhost//pig", + "base": "file://lion/", + "href": "file:////pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//pig", + "search": "", + "hash": "" + }, + { + "input": "/..//localhost//pig", + "base": "file://lion/", + "href": "file://lion//localhost//pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "lion", + "hostname": "lion", + "port": "", + "pathname": "//localhost//pig", + "search": "", + "hash": "" + }, + { + "input": "file://", + "base": "file://ape/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# File URLs with non-empty hosts", + { + "input": "/rooibos", + "base": "file://tea/", + "href": "file://tea/rooibos", + "protocol": "file:", + "username": "", + "password": "", + "host": "tea", + "hostname": "tea", + "port": "", + "pathname": "/rooibos", + "search": "", + "hash": "" + }, + { + "input": "/?chai", + "base": "file://tea/", + "href": "file://tea/?chai", + "protocol": "file:", + "username": "", + "password": "", + "host": "tea", + "hostname": "tea", + "port": "", + "pathname": "/", + "search": "?chai", + "hash": "" + }, + "# Windows drive letter handling with the 'file:' base URL", + { + "input": "C|", + "base": "file://host/dir/file", + "href": "file://host/C:", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|", + "base": "file://host/D:/dir1/dir2/file", + "href": "file://host/C:", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|#", + "base": "file://host/dir/file", + "href": "file://host/C:#", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|?", + "base": "file://host/dir/file", + "href": "file://host/C:?", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|/", + "base": "file://host/dir/file", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\n/", + "base": "file://host/dir/file", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\\", + "base": "file://host/dir/file", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C", + "base": "file://host/dir/file", + "href": "file://host/dir/C", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C", + "search": "", + "hash": "" + }, + { + "input": "C|a", + "base": "file://host/dir/file", + "href": "file://host/dir/C|a", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C|a", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk in the file slash state", + { + "input": "/c:/foo/bar", + "base": "file:///c:/baz/qux", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/c|/foo/bar", + "base": "file:///c:/baz/qux", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "file:\\c:\\foo\\bar", + "base": "file:///c:/baz/qux", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/c:/foo/bar", + "base": "file://host/path", + "href": "file://host/c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + "# Do not drop the host in the presence of a drive letter", + { + "input": "file://example.net/C:/", + "base": null, + "href": "file://example.net/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "example.net", + "hostname": "example.net", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://1.2.3.4/C:/", + "base": null, + "href": "file://1.2.3.4/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "1.2.3.4", + "hostname": "1.2.3.4", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://[1::8]/C:/", + "base": null, + "href": "file://[1::8]/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "[1::8]", + "hostname": "[1::8]", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# Copy the host from the base URL in the following cases", + { + "input": "C|/", + "base": "file://host/", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "/C:/", + "base": "file://host/", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file:C:/", + "base": "file://host/", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file:/C:/", + "base": "file://host/", + "href": "file://host/C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# Copy the empty host from the input in the following cases", + { + "input": "//C:/", + "base": "file://host/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://C:/", + "base": "file://host/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "///C:/", + "base": "file://host/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file:///C:/", + "base": "file://host/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk (no host)", + { + "input": "file:/C|/", + "base": null, + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://C|/", + "base": null, + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# file URLs without base URL by Rimas Misevičius", + { + "input": "file:", + "base": null, + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:?q=v", + "base": null, + "href": "file:///?q=v", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "?q=v", + "hash": "" + }, + { + "input": "file:#frag", + "base": null, + "href": "file:///#frag", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "#frag" + }, + "# file: drive letter cases from https://crbug.com/1078698", + { + "input": "file:///Y:", + "base": null, + "href": "file:///Y:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/Y:", + "search": "", + "hash": "" + }, + { + "input": "file:///Y:/", + "base": null, + "href": "file:///Y:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/Y:/", + "search": "", + "hash": "" + }, + { + "input": "file:///./Y", + "base": null, + "href": "file:///Y", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/Y", + "search": "", + "hash": "" + }, + { + "input": "file:///./Y:", + "base": null, + "href": "file:///Y:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/Y:", + "search": "", + "hash": "" + }, + { + "input": "\\\\\\.\\Y:", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + "# file: drive letter cases from https://crbug.com/1078698 but lowercased", + { + "input": "file:///y:", + "base": null, + "href": "file:///y:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/y:", + "search": "", + "hash": "" + }, + { + "input": "file:///y:/", + "base": null, + "href": "file:///y:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/y:/", + "search": "", + "hash": "" + }, + { + "input": "file:///./y", + "base": null, + "href": "file:///y", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/y", + "search": "", + "hash": "" + }, + { + "input": "file:///./y:", + "base": null, + "href": "file:///y:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/y:", + "search": "", + "hash": "" + }, + { + "input": "\\\\\\.\\y:", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + "# Additional file URL tests for (https://github.com/whatwg/url/issues/405)", + { + "input": "file://localhost//a//../..//foo", + "base": null, + "href": "file://///foo", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///foo", + "search": "", + "hash": "" + }, + { + "input": "file://localhost////foo", + "base": null, + "href": "file://////foo", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "////foo", + "search": "", + "hash": "" + }, + { + "input": "file:////foo", + "base": null, + "href": "file:////foo", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//foo", + "search": "", + "hash": "" + }, + { + "input": "file:///one/two", + "base": "file:///", + "href": "file:///one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/one/two", + "search": "", + "hash": "" + }, + { + "input": "file:////one/two", + "base": "file:///", + "href": "file:////one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//one/two", + "search": "", + "hash": "" + }, + { + "input": "//one/two", + "base": "file:///", + "href": "file://one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "one", + "hostname": "one", + "port": "", + "pathname": "/two", + "search": "", + "hash": "" + }, + { + "input": "///one/two", + "base": "file:///", + "href": "file:///one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/one/two", + "search": "", + "hash": "" + }, + { + "input": "////one/two", + "base": "file:///", + "href": "file:////one/two", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//one/two", + "search": "", + "hash": "" + }, + { + "input": "file:///.//", + "base": "file:////", + "href": "file:////", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + "File URL tests for https://github.com/whatwg/url/issues/549", + { + "input": "file:.//p", + "base": null, + "href": "file:////p", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//p", + "search": "", + "hash": "" + }, + { + "input": "file:/.//p", + "base": null, + "href": "file:////p", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//p", + "search": "", + "hash": "" + }, + "# IPv6 tests", + { + "input": "http://[1:0::]", + "base": "http://example.net/", + "href": "http://[1::]/", + "origin": "http://[1::]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[1::]", + "hostname": "[1::]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[0:1:2:3:4:5:6:7:8]", + "base": "http://example.net/", + "failure": true + }, + { + "input": "https://[0::0::0]", + "base": null, + "failure": true + }, + { + "input": "https://[0:.0]", + "base": null, + "failure": true + }, + { + "input": "https://[0:0:]", + "base": null, + "failure": true + }, + { + "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]", + "base": null, + "failure": true + }, + { + "input": "https://[0:1.00.0.0.0]", + "base": null, + "failure": true + }, + { + "input": "https://[0:1.290.0.0.0]", + "base": null, + "failure": true + }, + { + "input": "https://[0:1.23.23]", + "base": null, + "failure": true + }, + "# Empty host", + { + "input": "http://?", + "base": null, + "failure": true + }, + { + "input": "http://#", + "base": null, + "failure": true + }, + "Port overflow (2^32 + 81)", + { + "input": "http://f:4294967377/c", + "base": "http://example.org/", + "failure": true + }, + "Port overflow (2^64 + 81)", + { + "input": "http://f:18446744073709551697/c", + "base": "http://example.org/", + "failure": true + }, + "Port overflow (2^128 + 81)", + { + "input": "http://f:340282366920938463463374607431768211537/c", + "base": "http://example.org/", + "failure": true + }, + "# Non-special-URL path tests", + { + "input": "sc://ñ", + "base": null, + "href": "sc://%C3%B1", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "sc://ñ?x", + "base": null, + "href": "sc://%C3%B1?x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "?x", + "hash": "" + }, + { + "input": "sc://ñ#x", + "base": null, + "href": "sc://%C3%B1#x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "sc://ñ", + "href": "sc://%C3%B1#x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "", + "hash": "#x" + }, + { + "input": "?x", + "base": "sc://ñ", + "href": "sc://%C3%B1?x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "?x", + "hash": "" + }, + { + "input": "sc://?", + "base": null, + "href": "sc://?", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "sc://#", + "base": null, + "href": "sc://#", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "///", + "base": "sc://x/", + "href": "sc:///", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "////", + "base": "sc://x/", + "href": "sc:////", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "////x/", + "base": "sc://x/", + "href": "sc:////x/", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//x/", + "search": "", + "hash": "" + }, + { + "input": "tftp://foobar.com/someconfig;mode=netascii", + "base": null, + "href": "tftp://foobar.com/someconfig;mode=netascii", + "origin": "null", + "protocol": "tftp:", + "username": "", + "password": "", + "host": "foobar.com", + "hostname": "foobar.com", + "port": "", + "pathname": "/someconfig;mode=netascii", + "search": "", + "hash": "" + }, + { + "input": "telnet://user:pass@foobar.com:23/", + "base": null, + "href": "telnet://user:pass@foobar.com:23/", + "origin": "null", + "protocol": "telnet:", + "username": "user", + "password": "pass", + "host": "foobar.com:23", + "hostname": "foobar.com", + "port": "23", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ut2004://10.10.10.10:7777/Index.ut2", + "base": null, + "href": "ut2004://10.10.10.10:7777/Index.ut2", + "origin": "null", + "protocol": "ut2004:", + "username": "", + "password": "", + "host": "10.10.10.10:7777", + "hostname": "10.10.10.10", + "port": "7777", + "pathname": "/Index.ut2", + "search": "", + "hash": "" + }, + { + "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", + "base": null, + "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", + "origin": "null", + "protocol": "redis:", + "username": "foo", + "password": "bar", + "host": "somehost:6379", + "hostname": "somehost", + "port": "6379", + "pathname": "/0", + "search": "?baz=bam&qux=baz", + "hash": "" + }, + { + "input": "rsync://foo@host:911/sup", + "base": null, + "href": "rsync://foo@host:911/sup", + "origin": "null", + "protocol": "rsync:", + "username": "foo", + "password": "", + "host": "host:911", + "hostname": "host", + "port": "911", + "pathname": "/sup", + "search": "", + "hash": "" + }, + { + "input": "git://github.com/foo/bar.git", + "base": null, + "href": "git://github.com/foo/bar.git", + "origin": "null", + "protocol": "git:", + "username": "", + "password": "", + "host": "github.com", + "hostname": "github.com", + "port": "", + "pathname": "/foo/bar.git", + "search": "", + "hash": "" + }, + { + "input": "irc://myserver.com:6999/channel?passwd", + "base": null, + "href": "irc://myserver.com:6999/channel?passwd", + "origin": "null", + "protocol": "irc:", + "username": "", + "password": "", + "host": "myserver.com:6999", + "hostname": "myserver.com", + "port": "6999", + "pathname": "/channel", + "search": "?passwd", + "hash": "" + }, + { + "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT", + "base": null, + "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT", + "origin": "null", + "protocol": "dns:", + "username": "", + "password": "", + "host": "fw.example.org:9999", + "hostname": "fw.example.org", + "port": "9999", + "pathname": "/foo.bar.org", + "search": "?type=TXT", + "hash": "" + }, + { + "input": "ldap://localhost:389/ou=People,o=JNDITutorial", + "base": null, + "href": "ldap://localhost:389/ou=People,o=JNDITutorial", + "origin": "null", + "protocol": "ldap:", + "username": "", + "password": "", + "host": "localhost:389", + "hostname": "localhost", + "port": "389", + "pathname": "/ou=People,o=JNDITutorial", + "search": "", + "hash": "" + }, + { + "input": "git+https://github.com/foo/bar", + "base": null, + "href": "git+https://github.com/foo/bar", + "origin": "null", + "protocol": "git+https:", + "username": "", + "password": "", + "host": "github.com", + "hostname": "github.com", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "urn:ietf:rfc:2648", + "base": null, + "href": "urn:ietf:rfc:2648", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ietf:rfc:2648", + "search": "", + "hash": "" + }, + { + "input": "tag:joe@example.org,2001:foo/bar", + "base": null, + "href": "tag:joe@example.org,2001:foo/bar", + "origin": "null", + "protocol": "tag:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "joe@example.org,2001:foo/bar", + "search": "", + "hash": "" + }, + "Serialize /. in path", + { + "input": "non-spec:/.//", + "base": null, + "href": "non-spec:/.//", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "non-spec:/..//", + "base": null, + "href": "non-spec:/.//", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "non-spec:/a/..//", + "base": null, + "href": "non-spec:/.//", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "non-spec:/.//path", + "base": null, + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "non-spec:/..//path", + "base": null, + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "non-spec:/a/..//path", + "base": null, + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "/.//path", + "base": "non-spec:/p", + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "/..//path", + "base": "non-spec:/p", + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "..//path", + "base": "non-spec:/p", + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "a/..//path", + "base": "non-spec:/p", + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "non-spec:/..//p", + "href": "non-spec:/.//p", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//p", + "search": "", + "hash": "" + }, + { + "input": "path", + "base": "non-spec:/..//p", + "href": "non-spec:/.//path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//path", + "search": "", + "hash": "" + }, + "Do not serialize /. in path", + { + "input": "../path", + "base": "non-spec:/.//p", + "href": "non-spec:/path", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + "# percent encoded hosts in non-special-URLs", + { + "input": "non-special://%E2%80%A0/", + "base": null, + "href": "non-special://%E2%80%A0/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "%E2%80%A0", + "hostname": "%E2%80%A0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://H%4fSt/path", + "base": null, + "href": "non-special://H%4fSt/path", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "H%4fSt", + "hostname": "H%4fSt", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + "# IPv6 in non-special-URLs", + { + "input": "non-special://[1:2:0:0:5:0:0:0]/", + "base": null, + "href": "non-special://[1:2:0:0:5::]/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2:0:0:5::]", + "hostname": "[1:2:0:0:5::]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[1:2:0:0:0:0:0:3]/", + "base": null, + "href": "non-special://[1:2::3]/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2::3]", + "hostname": "[1:2::3]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[1:2::3]:80/", + "base": null, + "href": "non-special://[1:2::3]:80/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2::3]:80", + "hostname": "[1:2::3]", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[:80/", + "base": null, + "failure": true + }, + { + "input": "blob:https://example.com:443/", + "base": null, + "href": "blob:https://example.com:443/", + "origin": "https://example.com", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "https://example.com:443/", + "search": "", + "hash": "" + }, + { + "input": "blob:http://example.org:88/", + "base": null, + "href": "blob:http://example.org:88/", + "origin": "http://example.org:88", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "http://example.org:88/", + "search": "", + "hash": "" + }, + { + "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", + "base": null, + "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "d3958f5c-0777-0845-9dcf-2cb28783acaf", + "search": "", + "hash": "" + }, + { + "input": "blob:", + "base": null, + "href": "blob:", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + "blob: in blob:", + { + "input": "blob:blob:", + "base": null, + "href": "blob:blob:", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blob:", + "search": "", + "hash": "" + }, + { + "input": "blob:blob:https://example.org/", + "base": null, + "href": "blob:blob:https://example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blob:https://example.org/", + "search": "", + "hash": "" + }, + "Non-http(s): in blob:", + { + "input": "blob:about:blank", + "base": null, + "href": "blob:about:blank", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "about:blank", + "search": "", + "hash": "" + }, + { + "input": "blob:file://host/path", + "base": null, + "href": "blob:file://host/path", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "file://host/path", + "search": "", + "hash": "" + }, + { + "input": "blob:ftp://host/path", + "base": null, + "href": "blob:ftp://host/path", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ftp://host/path", + "search": "", + "hash": "" + }, + { + "input": "blob:ws://example.org/", + "base": null, + "href": "blob:ws://example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ws://example.org/", + "search": "", + "hash": "" + }, + { + "input": "blob:wss://example.org/", + "base": null, + "href": "blob:wss://example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "wss://example.org/", + "search": "", + "hash": "" + }, + "Percent-encoded http: in blob:", + { + "input": "blob:http%3a//example.org/", + "base": null, + "href": "blob:http%3a//example.org/", + "origin": "null", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "http%3a//example.org/", + "search": "", + "hash": "" + }, + "Invalid IPv4 radix digits", + { + "input": "http://0x7f.0.0.0x7g", + "base": null, + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0X7F.0.0.0X7G", + "base": null, + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid IPv4 portion of IPv6 address", + { + "input": "http://[::127.0.0.0.1]", + "base": null, + "failure": true + }, + "Uncompressed IPv6 addresses with 0", + { + "input": "http://[0:1:0:1:0:1:0:1]", + "base": null, + "href": "http://[0:1:0:1:0:1:0:1]/", + "protocol": "http:", + "username": "", + "password": "", + "host": "[0:1:0:1:0:1:0:1]", + "hostname": "[0:1:0:1:0:1:0:1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[1:0:1:0:1:0:1:0]", + "base": null, + "href": "http://[1:0:1:0:1:0:1:0]/", + "protocol": "http:", + "username": "", + "password": "", + "host": "[1:0:1:0:1:0:1:0]", + "hostname": "[1:0:1:0:1:0:1:0]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Percent-encoded query and fragment", + { + "input": "http://example.org/test?\"", + "base": null, + "href": "http://example.org/test?%22", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%22", + "hash": "" + }, + { + "input": "http://example.org/test?#", + "base": null, + "href": "http://example.org/test?#", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "http://example.org/test?<", + "base": null, + "href": "http://example.org/test?%3C", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%3C", + "hash": "" + }, + { + "input": "http://example.org/test?>", + "base": null, + "href": "http://example.org/test?%3E", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%3E", + "hash": "" + }, + { + "input": "http://example.org/test?⌣", + "base": null, + "href": "http://example.org/test?%E2%8C%A3", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%E2%8C%A3", + "hash": "" + }, + { + "input": "http://example.org/test?%23%23", + "base": null, + "href": "http://example.org/test?%23%23", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%23%23", + "hash": "" + }, + { + "input": "http://example.org/test?%GH", + "base": null, + "href": "http://example.org/test?%GH", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%GH", + "hash": "" + }, + { + "input": "http://example.org/test?a#%EF", + "base": null, + "href": "http://example.org/test?a#%EF", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#%EF" + }, + { + "input": "http://example.org/test?a#%GH", + "base": null, + "href": "http://example.org/test?a#%GH", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#%GH" + }, + "URLs that require a non-about:blank base. (Also serve as invalid base tests.)", + { + "input": "a", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "a/", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "a//", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + "Bases that don't fail to parse but fail to be bases", + { + "input": "test-a-colon.html", + "base": "a:", + "failure": true + }, + { + "input": "test-a-colon-b.html", + "base": "a:b", + "failure": true + }, + "Other base URL tests, that must succeed", + { + "input": "test-a-colon-slash.html", + "base": "a:/", + "href": "a:/test-a-colon-slash.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-slash.html", + "base": "a://", + "href": "a:///test-a-colon-slash-slash.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash-slash.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-b.html", + "base": "a:/b", + "href": "a:/test-a-colon-slash-b.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash-b.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-slash-b.html", + "base": "a://b", + "href": "a://b/test-a-colon-slash-slash-b.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "b", + "hostname": "b", + "port": "", + "pathname": "/test-a-colon-slash-slash-b.html", + "search": "", + "hash": "" + }, + "Null code point in fragment", + { + "input": "http://example.org/test?a#b\u0000c", + "base": null, + "href": "http://example.org/test?a#b%00c", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#b%00c" + }, + { + "input": "non-spec://example.org/test?a#b\u0000c", + "base": null, + "href": "non-spec://example.org/test?a#b%00c", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#b%00c" + }, + { + "input": "non-spec:/test?a#b\u0000c", + "base": null, + "href": "non-spec:/test?a#b%00c", + "protocol": "non-spec:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#b%00c" + }, + "First scheme char - not allowed: https://github.com/whatwg/url/issues/464", + { + "input": "10.0.0.7:8080/foo.html", + "base": "file:///some/dir/bar.html", + "href": "file:///some/dir/10.0.0.7:8080/foo.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/some/dir/10.0.0.7:8080/foo.html", + "search": "", + "hash": "" + }, + "Subsequent scheme chars - not allowed", + { + "input": "a!@$*=/foo.html", + "base": "file:///some/dir/bar.html", + "href": "file:///some/dir/a!@$*=/foo.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/some/dir/a!@$*=/foo.html", + "search": "", + "hash": "" + }, + "First and subsequent scheme chars - allowed", + { + "input": "a1234567890-+.:foo/bar", + "base": "http://example.com/dir/file", + "href": "a1234567890-+.:foo/bar", + "protocol": "a1234567890-+.:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "foo/bar", + "search": "", + "hash": "" + }, + "IDNA ignored code points in file URLs hosts", + { + "input": "file://a­b/p", + "base": null, + "href": "file://ab/p", + "protocol": "file:", + "username": "", + "password": "", + "host": "ab", + "hostname": "ab", + "port": "", + "pathname": "/p", + "search": "", + "hash": "" + }, + { + "input": "file://a%C2%ADb/p", + "base": null, + "href": "file://ab/p", + "protocol": "file:", + "username": "", + "password": "", + "host": "ab", + "hostname": "ab", + "port": "", + "pathname": "/p", + "search": "", + "hash": "" + }, + "IDNA hostnames which get mapped to 'localhost'", + { + "input": "file://loC𝐀𝐋𝐇𝐨𝐬𝐭/usr/bin", + "base": null, + "href": "file:///usr/bin", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/usr/bin", + "search": "", + "hash": "" + }, + "Empty host after the domain to ASCII", + { + "input": "file://­/p", + "base": null, + "failure": true + }, + { + "input": "file://%C2%AD/p", + "base": null, + "failure": true + }, + { + "input": "file://xn--/p", + "base": null, + "failure": true + }, + "https://bugzilla.mozilla.org/show_bug.cgi?id=1647058", + { + "input": "#link", + "base": "https://example.org/##link", + "href": "https://example.org/#link", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "#link" + }, + "UTF-8 percent-encode of C0 control percent-encode set and supersets", + { + "input": "non-special:cannot-be-a-base-url-\u0000\u0001\u001f\u001e~€", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:cannot-be-a-base-url-%00%01%1F%1E~%7F%C2%80", + "origin": "null", + "password": "", + "pathname": "cannot-be-a-base-url-%00%01%1F%1E~%7F%C2%80", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "https://www.example.com/path{path.html?query'=query#fragment<fragment", + "base": null, + "hash": "#fragment%3C%7Ffragment", + "host": "www.example.com", + "hostname": "www.example.com", + "href": "https://www.example.com/path%7B%7Fpath.html?query%27%7F=query#fragment%3C%7Ffragment", + "origin": "https://www.example.com", + "password": "", + "pathname": "/path%7B%7Fpath.html", + "port": "", + "protocol": "https:", + "search": "?query%27%7F=query", + "username": "" + }, + { + "input": "https://user:pass[@foo/bar", + "base": "http://example.org", + "hash": "", + "host": "foo", + "hostname": "foo", + "href": "https://user:pass%5B%7F@foo/bar", + "origin": "https://foo", + "password": "pass%5B%7F", + "pathname": "/bar", + "port": "", + "protocol": "https:", + "search": "", + "username": "user" + }, + "Tests for the distinct percent-encode sets", + { + "input": "foo:// !\"$%&'()*+,-.;<=>@[\\]^_`{|}~@host/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/", + "origin": "null", + "password": "", + "pathname": "/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~" + }, + { + "input": "wss:// !\"$%&'()*+,-.;<=>@[]^_`{|}~@host/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "wss://%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/", + "origin": "wss://host", + "password": "", + "pathname": "/", + "port": "", + "protocol": "wss:", + "search": "", + "username": "%20!%22$%&'()*+,-.%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~" + }, + { + "input": "foo://joe: !\"$%&'()*+,-.:;<=>@[\\]^_`{|}~@host/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~@host/", + "origin": "null", + "password": "%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5C%5D%5E_%60%7B%7C%7D~", + "pathname": "/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "joe" + }, + { + "input": "wss://joe: !\"$%&'()*+,-.:;<=>@[]^_`{|}~@host/", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "wss://joe:%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~@host/", + "origin": "wss://host", + "password": "%20!%22$%&'()*+,-.%3A%3B%3C%3D%3E%40%5B%5D%5E_%60%7B%7C%7D~", + "pathname": "/", + "port": "", + "protocol": "wss:", + "search": "", + "username": "joe" + }, + { + "input": "foo://!\"$%&'()*+,-.;=_`{}~/", + "base": null, + "hash": "", + "host": "!\"$%&'()*+,-.;=_`{}~", + "hostname": "!\"$%&'()*+,-.;=_`{}~", + "href": "foo://!\"$%&'()*+,-.;=_`{}~/", + "origin": "null", + "password": "", + "pathname": "/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "" + }, + { + "input": "wss://!\"$&'()*+,-.;=_`{}~/", + "base": null, + "hash": "", + "host": "!\"$&'()*+,-.;=_`{}~", + "hostname": "!\"$&'()*+,-.;=_`{}~", + "href": "wss://!\"$&'()*+,-.;=_`{}~/", + "origin": "wss://!\"$&'()*+,-.;=_`{}~", + "password": "", + "pathname": "/", + "port": "", + "protocol": "wss:", + "search": "", + "username": "" + }, + { + "input": "foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://host/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]^_%60%7B|%7D~", + "origin": "null", + "password": "", + "pathname": "/%20!%22$%&'()*+,-./:;%3C=%3E@[\\]^_%60%7B|%7D~", + "port": "", + "protocol": "foo:", + "search": "", + "username": "" + }, + { + "input": "wss://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "wss://host/%20!%22$%&'()*+,-./:;%3C=%3E@[/]^_%60%7B|%7D~", + "origin": "wss://host", + "password": "", + "pathname": "/%20!%22$%&'()*+,-./:;%3C=%3E@[/]^_%60%7B|%7D~", + "port": "", + "protocol": "wss:", + "search": "", + "username": "" + }, + { + "input": "foo://host/dir/? !\"$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "foo://host/dir/?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\]^_`{|}~", + "origin": "null", + "password": "", + "pathname": "/dir/", + "port": "", + "protocol": "foo:", + "search": "?%20!%22$%&'()*+,-./:;%3C=%3E?@[\\]^_`{|}~", + "username": "" + }, + { + "input": "wss://host/dir/? !\"$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "base": null, + "hash": "", + "host": "host", + "hostname": "host", + "href": "wss://host/dir/?%20!%22$%&%27()*+,-./:;%3C=%3E?@[\\]^_`{|}~", + "origin": "wss://host", + "password": "", + "pathname": "/dir/", + "port": "", + "protocol": "wss:", + "search": "?%20!%22$%&%27()*+,-./:;%3C=%3E?@[\\]^_`{|}~", + "username": "" + }, + { + "input": "foo://host/dir/# !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "base": null, + "hash": "#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\]^_%60{|}~", + "host": "host", + "hostname": "host", + "href": "foo://host/dir/#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\]^_%60{|}~", + "origin": "null", + "password": "", + "pathname": "/dir/", + "port": "", + "protocol": "foo:", + "search": "", + "username": "" + }, + { + "input": "wss://host/dir/# !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "base": null, + "hash": "#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\]^_%60{|}~", + "host": "host", + "hostname": "host", + "href": "wss://host/dir/#%20!%22#$%&'()*+,-./:;%3C=%3E?@[\\]^_%60{|}~", + "origin": "wss://host", + "password": "", + "pathname": "/dir/", + "port": "", + "protocol": "wss:", + "search": "", + "username": "" + }, + "Ensure that input schemes are not ignored when resolving non-special URLs", + { + "input": "abc:rootless", + "base": "abc://host/path", + "hash": "", + "host": "", + "hostname": "", + "href": "abc:rootless", + "password": "", + "pathname": "rootless", + "port": "", + "protocol": "abc:", + "search": "", + "username": "" + }, + { + "input": "abc:rootless", + "base": "abc:/path", + "hash": "", + "host": "", + "hostname": "", + "href": "abc:rootless", + "password": "", + "pathname": "rootless", + "port": "", + "protocol": "abc:", + "search": "", + "username": "" + }, + { + "input": "abc:rootless", + "base": "abc:path", + "hash": "", + "host": "", + "hostname": "", + "href": "abc:rootless", + "password": "", + "pathname": "rootless", + "port": "", + "protocol": "abc:", + "search": "", + "username": "" + }, + { + "input": "abc:/rooted", + "base": "abc://host/path", + "hash": "", + "host": "", + "hostname": "", + "href": "abc:/rooted", + "password": "", + "pathname": "/rooted", + "port": "", + "protocol": "abc:", + "search": "", + "username": "" + }, + "Empty query and fragment with blank should throw an error", + { + "input": "#", + "base": null, + "failure": true, + "relativeTo": "any-base" + }, + { + "input": "?", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + "Last component looks like a number, but not valid IPv4", + { + "input": "http://1.2.3.4.5", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://1.2.3.4.5.", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://0..0x300/", + "base": null, + "failure": true + }, + { + "input": "http://0..0x300./", + "base": null, + "failure": true + }, + { + "input": "http://256.256.256.256.256", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://256.256.256.256.256.", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://1.2.3.08", + "base": null, + "failure": true + }, + { + "input": "http://1.2.3.08.", + "base": null, + "failure": true + }, + { + "input": "http://1.2.3.09", + "base": null, + "failure": true + }, + { + "input": "http://09.2.3.4", + "base": null, + "failure": true + }, + { + "input": "http://09.2.3.4.", + "base": null, + "failure": true + }, + { + "input": "http://01.2.3.4.5", + "base": null, + "failure": true + }, + { + "input": "http://01.2.3.4.5.", + "base": null, + "failure": true + }, + { + "input": "http://0x100.2.3.4", + "base": null, + "failure": true + }, + { + "input": "http://0x100.2.3.4.", + "base": null, + "failure": true + }, + { + "input": "http://0x1.2.3.4.5", + "base": null, + "failure": true + }, + { + "input": "http://0x1.2.3.4.5.", + "base": null, + "failure": true + }, + { + "input": "http://foo.1.2.3.4", + "base": null, + "failure": true + }, + { + "input": "http://foo.1.2.3.4.", + "base": null, + "failure": true + }, + { + "input": "http://foo.2.3.4", + "base": null, + "failure": true + }, + { + "input": "http://foo.2.3.4.", + "base": null, + "failure": true + }, + { + "input": "http://foo.09", + "base": null, + "failure": true + }, + { + "input": "http://foo.09.", + "base": null, + "failure": true + }, + { + "input": "http://foo.0x4", + "base": null, + "failure": true + }, + { + "input": "http://foo.0x4.", + "base": null, + "failure": true + }, + { + "input": "http://foo.09..", + "base": null, + "hash": "", + "host": "foo.09..", + "hostname": "foo.09..", + "href": "http://foo.09../", + "password": "", + "pathname": "/", + "port": "", + "protocol": "http:", + "search": "", + "username": "" + }, + { + "input": "http://0999999999999999999/", + "base": null, + "failure": true + }, + { + "input": "http://foo.0x", + "base": null, + "failure": true + }, + { + "input": "http://foo.0XFfFfFfFfFfFfFfFfFfAcE123", + "base": null, + "failure": true + }, + { + "input": "http://💩.123/", + "base": null, + "failure": true + }, + "U+0000 and U+FFFF in various places", + { + "input": "https://\u0000y", + "base": null, + "failure": true + }, + { + "input": "https://x/\u0000y", + "base": null, + "hash": "", + "host": "x", + "hostname": "x", + "href": "https://x/%00y", + "password": "", + "pathname": "/%00y", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "input": "https://x/?\u0000y", + "base": null, + "hash": "", + "host": "x", + "hostname": "x", + "href": "https://x/?%00y", + "password": "", + "pathname": "/", + "port": "", + "protocol": "https:", + "search": "?%00y", + "username": "" + }, + { + "input": "https://x/?#\u0000y", + "base": null, + "hash": "#%00y", + "host": "x", + "hostname": "x", + "href": "https://x/?#%00y", + "password": "", + "pathname": "/", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "input": "https://￿y", + "base": null, + "failure": true + }, + { + "input": "https://x/￿y", + "base": null, + "hash": "", + "host": "x", + "hostname": "x", + "href": "https://x/%EF%BF%BFy", + "password": "", + "pathname": "/%EF%BF%BFy", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "input": "https://x/?￿y", + "base": null, + "hash": "", + "host": "x", + "hostname": "x", + "href": "https://x/?%EF%BF%BFy", + "password": "", + "pathname": "/", + "port": "", + "protocol": "https:", + "search": "?%EF%BF%BFy", + "username": "" + }, + { + "input": "https://x/?#￿y", + "base": null, + "hash": "#%EF%BF%BFy", + "host": "x", + "hostname": "x", + "href": "https://x/?#%EF%BF%BFy", + "password": "", + "pathname": "/", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "input": "non-special:\u0000y", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:%00y", + "password": "", + "pathname": "%00y", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "non-special:x/\u0000y", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:x/%00y", + "password": "", + "pathname": "x/%00y", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "non-special:x/?\u0000y", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:x/?%00y", + "password": "", + "pathname": "x/", + "port": "", + "protocol": "non-special:", + "search": "?%00y", + "username": "" + }, + { + "input": "non-special:x/?#\u0000y", + "base": null, + "hash": "#%00y", + "host": "", + "hostname": "", + "href": "non-special:x/?#%00y", + "password": "", + "pathname": "x/", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "non-special:￿y", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:%EF%BF%BFy", + "password": "", + "pathname": "%EF%BF%BFy", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "non-special:x/￿y", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:x/%EF%BF%BFy", + "password": "", + "pathname": "x/%EF%BF%BFy", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "non-special:x/?￿y", + "base": null, + "hash": "", + "host": "", + "hostname": "", + "href": "non-special:x/?%EF%BF%BFy", + "password": "", + "pathname": "x/", + "port": "", + "protocol": "non-special:", + "search": "?%EF%BF%BFy", + "username": "" + }, + { + "input": "non-special:x/?#￿y", + "base": null, + "hash": "#%EF%BF%BFy", + "host": "", + "hostname": "", + "href": "non-special:x/?#%EF%BF%BFy", + "password": "", + "pathname": "x/", + "port": "", + "protocol": "non-special:", + "search": "", + "username": "" + }, + { + "input": "", + "base": null, + "failure": true, + "relativeTo": "non-opaque-path-base" + }, + { + "input": "https://example.com/\"quoted\"", + "base": null, + "hash": "", + "host": "example.com", + "hostname": "example.com", + "href": "https://example.com/%22quoted%22", + "origin": "https://example.com", + "password": "", + "pathname": "/%22quoted%22", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "input": "https://a%C2%ADb/", + "base": null, + "hash": "", + "host": "ab", + "hostname": "ab", + "href": "https://ab/", + "origin": "https://ab", + "password": "", + "pathname": "/", + "port": "", + "protocol": "https:", + "search": "", + "username": "" + }, + { + "comment": "Empty host after domain to ASCII", + "input": "https://­/", + "base": null, + "failure": true + }, + { + "input": "https://%C2%AD/", + "base": null, + "failure": true + }, + { + "input": "https://xn--/", + "base": null, + "failure": true + }, + "Non-special schemes that some implementations might incorrectly treat as special", + { + "input": "data://example.com:8080/pathname?search#hash", + "base": null, + "href": "data://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "data:///test", + "base": null, + "href": "data:///test", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "data://test/a/../b", + "base": null, + "href": "data://test/b", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "data://:443", + "base": null, + "failure": true + }, + { + "input": "data://test:test", + "base": null, + "failure": true + }, + { + "input": "data://[:1]", + "base": null, + "failure": true + }, + { + "input": "javascript://example.com:8080/pathname?search#hash", + "base": null, + "href": "javascript://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "javascript:///test", + "base": null, + "href": "javascript:///test", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "javascript://test/a/../b", + "base": null, + "href": "javascript://test/b", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "javascript://:443", + "base": null, + "failure": true + }, + { + "input": "javascript://test:test", + "base": null, + "failure": true + }, + { + "input": "javascript://[:1]", + "base": null, + "failure": true + }, + { + "input": "mailto://example.com:8080/pathname?search#hash", + "base": null, + "href": "mailto://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "mailto:///test", + "base": null, + "href": "mailto:///test", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "mailto://test/a/../b", + "base": null, + "href": "mailto://test/b", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "mailto://:443", + "base": null, + "failure": true + }, + { + "input": "mailto://test:test", + "base": null, + "failure": true + }, + { + "input": "mailto://[:1]", + "base": null, + "failure": true + }, + { + "input": "intent://example.com:8080/pathname?search#hash", + "base": null, + "href": "intent://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "intent:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "intent:///test", + "base": null, + "href": "intent:///test", + "origin": "null", + "protocol": "intent:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "intent://test/a/../b", + "base": null, + "href": "intent://test/b", + "origin": "null", + "protocol": "intent:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "intent://:443", + "base": null, + "failure": true + }, + { + "input": "intent://test:test", + "base": null, + "failure": true + }, + { + "input": "intent://[:1]", + "base": null, + "failure": true + }, + { + "input": "urn://example.com:8080/pathname?search#hash", + "base": null, + "href": "urn://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "urn:///test", + "base": null, + "href": "urn:///test", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "urn://test/a/../b", + "base": null, + "href": "urn://test/b", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "urn://:443", + "base": null, + "failure": true + }, + { + "input": "urn://test:test", + "base": null, + "failure": true + }, + { + "input": "urn://[:1]", + "base": null, + "failure": true + }, + { + "input": "turn://example.com:8080/pathname?search#hash", + "base": null, + "href": "turn://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "turn:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "turn:///test", + "base": null, + "href": "turn:///test", + "origin": "null", + "protocol": "turn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "turn://test/a/../b", + "base": null, + "href": "turn://test/b", + "origin": "null", + "protocol": "turn:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "turn://:443", + "base": null, + "failure": true + }, + { + "input": "turn://test:test", + "base": null, + "failure": true + }, + { + "input": "turn://[:1]", + "base": null, + "failure": true + }, + { + "input": "stun://example.com:8080/pathname?search#hash", + "base": null, + "href": "stun://example.com:8080/pathname?search#hash", + "origin": "null", + "protocol": "stun:", + "username": "", + "password": "", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080", + "pathname": "/pathname", + "search": "?search", + "hash": "#hash" + }, + { + "input": "stun:///test", + "base": null, + "href": "stun:///test", + "origin": "null", + "protocol": "stun:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "stun://test/a/../b", + "base": null, + "href": "stun://test/b", + "origin": "null", + "protocol": "stun:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/b", + "search": "", + "hash": "" + }, + { + "input": "stun://:443", + "base": null, + "failure": true + }, + { + "input": "stun://test:test", + "base": null, + "failure": true + }, + { + "input": "stun://[:1]", + "base": null, + "failure": true + }, + { + "input": "w://x:0", + "base": null, + "href": "w://x:0", + "origin": "null", + "protocol": "w:", + "username": "", + "password": "", + "host": "x:0", + "hostname": "x", + "port": "0", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "west://x:0", + "base": null, + "href": "west://x:0", + "origin": "null", + "protocol": "west:", + "username": "", + "password": "", + "host": "x:0", + "hostname": "x", + "port": "0", + "pathname": "", + "search": "", + "hash": "" + }, + "Scheme relative path starting with multiple slashes", + { + "input": "///test", + "base": "http://example.org/", + "href": "http://test/", + "protocol": "http:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///\\//\\//test", + "base": "http://example.org/", + "href": "http://test/", + "protocol": "http:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///example.org/path", + "base": "http://example.org/", + "href": "http://example.org/path", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + { + "input": "///example.org/../path", + "base": "http://example.org/", + "href": "http://example.org/path", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + { + "input": "///example.org/../../", + "base": "http://example.org/", + "href": "http://example.org/", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///example.org/../path/../../", + "base": "http://example.org/", + "href": "http://example.org/", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///example.org/../path/../../path", + "base": "http://example.org/", + "href": "http://example.org/path", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + { + "input": "/\\/\\//example.org/../path", + "base": "http://example.org/", + "href": "http://example.org/path", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + { + "input": "///abcdef/../", + "base": "file:///", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "/\\//\\/a/../", + "base": "file:///", + "href": "file://////", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "////", + "search": "", + "hash": "" + }, + { + "input": "//a/../", + "base": "file:///", + "href": "file://a/", + "protocol": "file:", + "username": "", + "password": "", + "host": "a", + "hostname": "a", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + } +] \ No newline at end of file diff --git a/transfer-protocol/vendor/autoload.php b/transfer-protocol/vendor/autoload.php new file mode 100644 index 0000000..ce87254 --- /dev/null +++ b/transfer-protocol/vendor/autoload.php @@ -0,0 +1,12 @@ += 7.2 (#55). + +## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19 + +✨ New features + +- `BigInteger::not()` returns the bitwise `NOT` value + +🐛 **Bug fixes** + +- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers +- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available + +## [0.9.0](https://github.com/brick/math/releases/tag/0.9.0) - 2020-08-18 + +👌 **Improvements** + +- `BigNumber::of()` now accepts `.123` and `123.` formats, both of which return a `BigDecimal` + +💥 **Breaking changes** + +- Deprecated method `BigInteger::powerMod()` has been removed - use `modPow()` instead +- Deprecated method `BigInteger::parse()` has been removed - use `fromBase()` instead + +## [0.8.17](https://github.com/brick/math/releases/tag/0.8.17) - 2020-08-19 + +🐛 **Bug fix** + +- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers +- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available + +## [0.8.16](https://github.com/brick/math/releases/tag/0.8.16) - 2020-08-18 + +🚑 **Critical fix** + +- This version reintroduces the deprecated `BigInteger::parse()` method, that has been removed by mistake in version `0.8.9` and should have lasted for the whole `0.8` release cycle. + +✨ **New features** + +- `BigInteger::modInverse()` calculates a modular multiplicative inverse +- `BigInteger::fromBytes()` creates a `BigInteger` from a byte string +- `BigInteger::toBytes()` converts a `BigInteger` to a byte string +- `BigInteger::randomBits()` creates a pseudo-random `BigInteger` of a given bit length +- `BigInteger::randomRange()` creates a pseudo-random `BigInteger` between two bounds + +💩 **Deprecations** + +- `BigInteger::powerMod()` is now deprecated in favour of `modPow()` + +## [0.8.15](https://github.com/brick/math/releases/tag/0.8.15) - 2020-04-15 + +🐛 **Fixes** + +- added missing `ext-json` requirement, due to `BigNumber` implementing `JsonSerializable` + +⚡️ **Optimizations** + +- additional optimization in `BigInteger::remainder()` + +## [0.8.14](https://github.com/brick/math/releases/tag/0.8.14) - 2020-02-18 + +✨ **New features** + +- `BigInteger::getLowestSetBit()` returns the index of the rightmost one bit + +## [0.8.13](https://github.com/brick/math/releases/tag/0.8.13) - 2020-02-16 + +✨ **New features** + +- `BigInteger::isEven()` tests whether the number is even +- `BigInteger::isOdd()` tests whether the number is odd +- `BigInteger::testBit()` tests if a bit is set +- `BigInteger::getBitLength()` returns the number of bits in the minimal representation of the number + +## [0.8.12](https://github.com/brick/math/releases/tag/0.8.12) - 2020-02-03 + +🛠️ **Maintenance release** + +Classes are now annotated for better static analysis with [psalm](https://psalm.dev/). + +This is a maintenance release: no bug fixes, no new features, no breaking changes. + +## [0.8.11](https://github.com/brick/math/releases/tag/0.8.11) - 2020-01-23 + +✨ **New feature** + +`BigInteger::powerMod()` performs a power-with-modulo operation. Useful for crypto. + +## [0.8.10](https://github.com/brick/math/releases/tag/0.8.10) - 2020-01-21 + +✨ **New feature** + +`BigInteger::mod()` returns the **modulo** of two numbers. The *modulo* differs from the *remainder* when the signs of the operands are different. + +## [0.8.9](https://github.com/brick/math/releases/tag/0.8.9) - 2020-01-08 + +⚡️ **Performance improvements** + +A few additional optimizations in `BigInteger` and `BigDecimal` when one of the operands can be returned as is. Thanks to @tomtomsen in #24. + +## [0.8.8](https://github.com/brick/math/releases/tag/0.8.8) - 2019-04-25 + +🐛 **Bug fixes** + +- `BigInteger::toBase()` could return an empty string for zero values (BCMath & Native calculators only, GMP calculator unaffected) + +✨ **New features** + +- `BigInteger::toArbitraryBase()` converts a number to an arbitrary base, using a custom alphabet +- `BigInteger::fromArbitraryBase()` converts a string in an arbitrary base, using a custom alphabet, back to a number + +These methods can be used as the foundation to convert strings between different bases/alphabets, using BigInteger as an intermediate representation. + +💩 **Deprecations** + +- `BigInteger::parse()` is now deprecated in favour of `fromBase()` + +`BigInteger::fromBase()` works the same way as `parse()`, with 2 minor differences: + +- the `$base` parameter is required, it does not default to `10` +- it throws a `NumberFormatException` instead of an `InvalidArgumentException` when the number is malformed + +## [0.8.7](https://github.com/brick/math/releases/tag/0.8.7) - 2019-04-20 + +**Improvements** + +- Safer conversion from `float` when using custom locales +- **Much faster** `NativeCalculator` implementation 🚀 + +You can expect **at least a 3x performance improvement** for common arithmetic operations when using the library on systems without GMP or BCMath; it gets exponentially faster on multiplications with a high number of digits. This is due to calculations now being performed on whole blocks of digits (the block size depending on the platform, 32-bit or 64-bit) instead of digit-by-digit as before. + +## [0.8.6](https://github.com/brick/math/releases/tag/0.8.6) - 2019-04-11 + +**New method** + +`BigNumber::sum()` returns the sum of one or more numbers. + +## [0.8.5](https://github.com/brick/math/releases/tag/0.8.5) - 2019-02-12 + +**Bug fix**: `of()` factory methods could fail when passing a `float` in environments using a `LC_NUMERIC` locale with a decimal separator other than `'.'` (#20). + +Thanks @manowark 👍 + +## [0.8.4](https://github.com/brick/math/releases/tag/0.8.4) - 2018-12-07 + +**New method** + +`BigDecimal::sqrt()` calculates the square root of a decimal number, to a given scale. + +## [0.8.3](https://github.com/brick/math/releases/tag/0.8.3) - 2018-12-06 + +**New method** + +`BigInteger::sqrt()` calculates the square root of a number (thanks @peter279k). + +**New exception** + +`NegativeNumberException` is thrown when calling `sqrt()` on a negative number. + +## [0.8.2](https://github.com/brick/math/releases/tag/0.8.2) - 2018-11-08 + +**Performance update** + +- Further improvement of `toInt()` performance +- `NativeCalculator` can now perform some multiplications more efficiently + +## [0.8.1](https://github.com/brick/math/releases/tag/0.8.1) - 2018-11-07 + +Performance optimization of `toInt()` methods. + +## [0.8.0](https://github.com/brick/math/releases/tag/0.8.0) - 2018-10-13 + +**Breaking changes** + +The following deprecated methods have been removed. Use the new method name instead: + +| Method removed | Replacement method | +| --- | --- | +| `BigDecimal::getIntegral()` | `BigDecimal::getIntegralPart()` | +| `BigDecimal::getFraction()` | `BigDecimal::getFractionalPart()` | + +--- + +**New features** + +`BigInteger` has been augmented with 5 new methods for bitwise operations: + +| New method | Description | +| --- | --- | +| `and()` | performs a bitwise `AND` operation on two numbers | +| `or()` | performs a bitwise `OR` operation on two numbers | +| `xor()` | performs a bitwise `XOR` operation on two numbers | +| `shiftedLeft()` | returns the number shifted left by a number of bits | +| `shiftedRight()` | returns the number shifted right by a number of bits | + +Thanks to @DASPRiD 👍 + +## [0.7.3](https://github.com/brick/math/releases/tag/0.7.3) - 2018-08-20 + +**New method:** `BigDecimal::hasNonZeroFractionalPart()` + +**Renamed/deprecated methods:** + +- `BigDecimal::getIntegral()` has been renamed to `getIntegralPart()` and is now deprecated +- `BigDecimal::getFraction()` has been renamed to `getFractionalPart()` and is now deprecated + +## [0.7.2](https://github.com/brick/math/releases/tag/0.7.2) - 2018-07-21 + +**Performance update** + +`BigInteger::parse()` and `toBase()` now use GMP's built-in base conversion features when available. + +## [0.7.1](https://github.com/brick/math/releases/tag/0.7.1) - 2018-03-01 + +This is a maintenance release, no code has been changed. + +- When installed with `--no-dev`, the autoloader does not autoload tests anymore +- Tests and other files unnecessary for production are excluded from the dist package + +This will help make installations more compact. + +## [0.7.0](https://github.com/brick/math/releases/tag/0.7.0) - 2017-10-02 + +Methods renamed: + +- `BigNumber:sign()` has been renamed to `getSign()` +- `BigDecimal::unscaledValue()` has been renamed to `getUnscaledValue()` +- `BigDecimal::scale()` has been renamed to `getScale()` +- `BigDecimal::integral()` has been renamed to `getIntegral()` +- `BigDecimal::fraction()` has been renamed to `getFraction()` +- `BigRational::numerator()` has been renamed to `getNumerator()` +- `BigRational::denominator()` has been renamed to `getDenominator()` + +Classes renamed: + +- `ArithmeticException` has been renamed to `MathException` + +## [0.6.2](https://github.com/brick/math/releases/tag/0.6.2) - 2017-10-02 + +The base class for all exceptions is now `MathException`. +`ArithmeticException` has been deprecated, and will be removed in 0.7.0. + +## [0.6.1](https://github.com/brick/math/releases/tag/0.6.1) - 2017-10-02 + +A number of methods have been renamed: + +- `BigNumber:sign()` is deprecated; use `getSign()` instead +- `BigDecimal::unscaledValue()` is deprecated; use `getUnscaledValue()` instead +- `BigDecimal::scale()` is deprecated; use `getScale()` instead +- `BigDecimal::integral()` is deprecated; use `getIntegral()` instead +- `BigDecimal::fraction()` is deprecated; use `getFraction()` instead +- `BigRational::numerator()` is deprecated; use `getNumerator()` instead +- `BigRational::denominator()` is deprecated; use `getDenominator()` instead + +The old methods will be removed in version 0.7.0. + +## [0.6.0](https://github.com/brick/math/releases/tag/0.6.0) - 2017-08-25 + +- Minimum PHP version is now [7.1](https://gophp71.org/); for PHP 5.6 and PHP 7.0 support, use version `0.5` +- Deprecated method `BigDecimal::withScale()` has been removed; use `toScale()` instead +- Method `BigNumber::toInteger()` has been renamed to `toInt()` + +## [0.5.4](https://github.com/brick/math/releases/tag/0.5.4) - 2016-10-17 + +`BigNumber` classes now implement [JsonSerializable](http://php.net/manual/en/class.jsonserializable.php). +The JSON output is always a string. + +## [0.5.3](https://github.com/brick/math/releases/tag/0.5.3) - 2016-03-31 + +This is a bugfix release. Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. + +## [0.5.2](https://github.com/brick/math/releases/tag/0.5.2) - 2015-08-06 + +The `$scale` parameter of `BigDecimal::dividedBy()` is now optional again. + +## [0.5.1](https://github.com/brick/math/releases/tag/0.5.1) - 2015-07-05 + +**New method: `BigNumber::toScale()`** + +This allows to convert any `BigNumber` to a `BigDecimal` with a given scale, using rounding if necessary. + +## [0.5.0](https://github.com/brick/math/releases/tag/0.5.0) - 2015-07-04 + +**New features** +- Common `BigNumber` interface for all classes, with the following methods: + - `sign()` and derived methods (`isZero()`, `isPositive()`, ...) + - `compareTo()` and derived methods (`isEqualTo()`, `isGreaterThan()`, ...) that work across different `BigNumber` types + - `toBigInteger()`, `toBigDecimal()`, `toBigRational`() conversion methods + - `toInteger()` and `toFloat()` conversion methods to native types +- Unified `of()` behaviour: every class now accepts any type of number, provided that it can be safely converted to the current type +- New method: `BigDecimal::exactlyDividedBy()`; this method automatically computes the scale of the result, provided that the division yields a finite number of digits +- New methods: `BigRational::quotient()` and `remainder()` +- Fine-grained exceptions: `DivisionByZeroException`, `RoundingNecessaryException`, `NumberFormatException` +- Factory methods `zero()`, `one()` and `ten()` available in all classes +- Rounding mode reintroduced in `BigInteger::dividedBy()` + +This release also comes with many performance improvements. + +--- + +**Breaking changes** +- `BigInteger`: + - `getSign()` is renamed to `sign()` + - `toString()` is renamed to `toBase()` + - `BigInteger::dividedBy()` now throws an exception by default if the remainder is not zero; use `quotient()` to get the previous behaviour +- `BigDecimal`: + - `getSign()` is renamed to `sign()` + - `getUnscaledValue()` is renamed to `unscaledValue()` + - `getScale()` is renamed to `scale()` + - `getIntegral()` is renamed to `integral()` + - `getFraction()` is renamed to `fraction()` + - `divideAndRemainder()` is renamed to `quotientAndRemainder()` + - `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode + - `toBigInteger()` does not accept a `$roundingMode` parameter any more + - `toBigRational()` does not simplify the fraction any more; explicitly add `->simplified()` to get the previous behaviour +- `BigRational`: + - `getSign()` is renamed to `sign()` + - `getNumerator()` is renamed to `numerator()` + - `getDenominator()` is renamed to `denominator()` + - `of()` is renamed to `nd()`, while `parse()` is renamed to `of()` +- Miscellaneous: + - `ArithmeticException` is moved to an `Exception\` sub-namespace + - `of()` factory methods now throw `NumberFormatException` instead of `InvalidArgumentException` + +## [0.4.3](https://github.com/brick/math/releases/tag/0.4.3) - 2016-03-31 + +Backport of two bug fixes from the 0.5 branch: +- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected +- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. + +## [0.4.2](https://github.com/brick/math/releases/tag/0.4.2) - 2015-06-16 + +New method: `BigDecimal::stripTrailingZeros()` + +## [0.4.1](https://github.com/brick/math/releases/tag/0.4.1) - 2015-06-12 + +Introducing a `BigRational` class, to perform calculations on fractions of any size. + +## [0.4.0](https://github.com/brick/math/releases/tag/0.4.0) - 2015-06-12 + +Rounding modes have been removed from `BigInteger`, and are now a concept specific to `BigDecimal`. + +`BigInteger::dividedBy()` now always returns the quotient of the division. + +## [0.3.5](https://github.com/brick/math/releases/tag/0.3.5) - 2016-03-31 + +Backport of two bug fixes from the 0.5 branch: + +- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected +- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6. + +## [0.3.4](https://github.com/brick/math/releases/tag/0.3.4) - 2015-06-11 + +New methods: +- `BigInteger::remainder()` returns the remainder of a division only +- `BigInteger::gcd()` returns the greatest common divisor of two numbers + +## [0.3.3](https://github.com/brick/math/releases/tag/0.3.3) - 2015-06-07 + +Fix `toString()` not handling negative numbers. + +## [0.3.2](https://github.com/brick/math/releases/tag/0.3.2) - 2015-06-07 + +`BigInteger` and `BigDecimal` now have a `getSign()` method that returns: +- `-1` if the number is negative +- `0` if the number is zero +- `1` if the number is positive + +## [0.3.1](https://github.com/brick/math/releases/tag/0.3.1) - 2015-06-05 + +Minor performance improvements + +## [0.3.0](https://github.com/brick/math/releases/tag/0.3.0) - 2015-06-04 + +The `$roundingMode` and `$scale` parameters have been swapped in `BigDecimal::dividedBy()`. + +## [0.2.2](https://github.com/brick/math/releases/tag/0.2.2) - 2015-06-04 + +Stronger immutability guarantee for `BigInteger` and `BigDecimal`. + +So far, it would have been possible to break immutability of these classes by calling the `unserialize()` internal function. This release fixes that. + +## [0.2.1](https://github.com/brick/math/releases/tag/0.2.1) - 2015-06-02 + +Added `BigDecimal::divideAndRemainder()` + +## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22 + +- `min()` and `max()` do not accept an `array` any more, but a variable number of parameters +- **minimum PHP version is now 5.6** +- continuous integration with PHP 7 + +## [0.1.1](https://github.com/brick/math/releases/tag/0.1.1) - 2014-09-01 + +- Added `BigInteger::power()` +- Added HHVM support + +## [0.1.0](https://github.com/brick/math/releases/tag/0.1.0) - 2014-08-31 + +First beta release. + diff --git a/transfer-protocol/vendor/brick/math/LICENSE b/transfer-protocol/vendor/brick/math/LICENSE new file mode 100644 index 0000000..f9b724f --- /dev/null +++ b/transfer-protocol/vendor/brick/math/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-present Benjamin Morel + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/transfer-protocol/vendor/brick/math/SECURITY.md b/transfer-protocol/vendor/brick/math/SECURITY.md new file mode 100644 index 0000000..cc8289b --- /dev/null +++ b/transfer-protocol/vendor/brick/math/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported Versions + +Only the last two release streams are supported. + +| Version | Supported | +| ------- | ------------------ | +| 0.9.x | :white_check_mark: | +| 0.8.x | :white_check_mark: | +| < 0.8 | :x: | + +## Reporting a Vulnerability + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. diff --git a/transfer-protocol/vendor/brick/math/composer.json b/transfer-protocol/vendor/brick/math/composer.json new file mode 100644 index 0000000..ec19663 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/composer.json @@ -0,0 +1,35 @@ +{ + "name": "brick/math", + "description": "Arbitrary-precision arithmetic library", + "type": "library", + "keywords": [ + "Brick", + "Math", + "Arbitrary-precision", + "Arithmetic", + "BigInteger", + "BigDecimal", + "BigRational", + "Bignum" + ], + "license": "MIT", + "require": { + "php": "^7.1 || ^8.0", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "php-coveralls/php-coveralls": "^2.2", + "vimeo/psalm": "4.9.2" + }, + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Brick\\Math\\Tests\\": "tests/" + } + } +} diff --git a/transfer-protocol/vendor/brick/math/src/BigDecimal.php b/transfer-protocol/vendor/brick/math/src/BigDecimal.php new file mode 100644 index 0000000..7824650 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/BigDecimal.php @@ -0,0 +1,895 @@ +value = $value; + $this->scale = $scale; + } + + /** + * Creates a BigDecimal of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigDecimal + * + * @throws MathException If the value cannot be converted to a BigDecimal. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigDecimal(); + } + + /** + * Creates a BigDecimal from an unscaled value and a scale. + * + * Example: `(12345, 3)` will result in the BigDecimal `12.345`. + * + * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger. + * @param int $scale The scale of the number, positive or zero. + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale is negative. + * + * @psalm-pure + */ + public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal + { + if ($scale < 0) { + throw new \InvalidArgumentException('The scale cannot be negative.'); + } + + return new BigDecimal((string) BigInteger::of($value), $scale); + } + + /** + * Returns a BigDecimal representing zero, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function zero() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigDecimal('0'); + } + + return $zero; + } + + /** + * Returns a BigDecimal representing one, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function one() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $one + */ + static $one; + + if ($one === null) { + $one = new BigDecimal('1'); + } + + return $one; + } + + /** + * Returns a BigDecimal representing ten, with a scale of zero. + * + * @return BigDecimal + * + * @psalm-pure + */ + public static function ten() : BigDecimal + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigDecimal|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigDecimal('10'); + } + + return $ten; + } + + /** + * Returns the sum of this number and the given one. + * + * The result has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function plus($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0' && $that->scale <= $this->scale) { + return $this; + } + + if ($this->value === '0' && $this->scale <= $that->scale) { + return $that; + } + + [$a, $b] = $this->scaleValues($this, $that); + + $value = Calculator::get()->add($a, $b); + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the difference of this number and the given one. + * + * The result has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function minus($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0' && $that->scale <= $this->scale) { + return $this; + } + + [$a, $b] = $this->scaleValues($this, $that); + + $value = Calculator::get()->sub($a, $b); + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the product of this number and the given one. + * + * The result has a scale of `$this->scale + $that->scale`. + * + * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal. + */ + public function multipliedBy($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '1' && $that->scale === 0) { + return $this; + } + + if ($this->value === '1' && $this->scale === 0) { + return $that; + } + + $value = Calculator::get()->mul($this->value, $that->value); + $scale = $this->scale + $that->scale; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the result of the division of this number by the given one, at the given scale. + * + * @param BigNumber|int|float|string $that The divisor. + * @param int|null $scale The desired scale, or null to use the scale of this number. + * @param int $roundingMode An optional rounding mode. + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale or rounding mode is invalid. + * @throws MathException If the number is invalid, is zero, or rounding was necessary. + */ + public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + if ($scale === null) { + $scale = $this->scale; + } elseif ($scale < 0) { + throw new \InvalidArgumentException('Scale cannot be negative.'); + } + + if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) { + return $this; + } + + $p = $this->valueWithMinScale($that->scale + $scale); + $q = $that->valueWithMinScale($this->scale - $scale); + + $result = Calculator::get()->divRound($p, $q, $roundingMode); + + return new BigDecimal($result, $scale); + } + + /** + * Returns the exact result of the division of this number by the given one. + * + * The scale of the result is automatically calculated to fit all the fraction digits. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The result. + * + * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero, + * or the result yields an infinite number of digits. + */ + public function exactlyDividedBy($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + [, $b] = $this->scaleValues($this, $that); + + $d = \rtrim($b, '0'); + $scale = \strlen($b) - \strlen($d); + + $calculator = Calculator::get(); + + foreach ([5, 2] as $prime) { + for (;;) { + $lastDigit = (int) $d[-1]; + + if ($lastDigit % $prime !== 0) { + break; + } + + $d = $calculator->divQ($d, (string) $prime); + $scale++; + } + } + + return $this->dividedBy($that, $scale)->stripTrailingZeros(); + } + + /** + * Returns this number exponentiated to the given value. + * + * The result has a scale of `$this->scale * $exponent`. + * + * @param int $exponent The exponent. + * + * @return BigDecimal The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigDecimal + { + if ($exponent === 0) { + return BigDecimal::one(); + } + + if ($exponent === 1) { + return $this; + } + + if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { + throw new \InvalidArgumentException(\sprintf( + 'The exponent %d is not in the range 0 to %d.', + $exponent, + Calculator::MAX_POWER + )); + } + + return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent); + } + + /** + * Returns the quotient of the division of this number by this given one. + * + * The quotient has a scale of `0`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The quotient. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotient($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + $quotient = Calculator::get()->divQ($p, $q); + + return new BigDecimal($quotient, 0); + } + + /** + * Returns the remainder of the division of this number by this given one. + * + * The remainder has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal The remainder. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function remainder($that) : BigDecimal + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + $remainder = Calculator::get()->divR($p, $q); + + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + return new BigDecimal($remainder, $scale); + } + + /** + * Returns the quotient and remainder of the division of this number by the given one. + * + * The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal. + * + * @return BigDecimal[] An array containing the quotient and the remainder. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotientAndRemainder($that) : array + { + $that = BigDecimal::of($that); + + if ($that->isZero()) { + throw DivisionByZeroException::divisionByZero(); + } + + $p = $this->valueWithMinScale($that->scale); + $q = $that->valueWithMinScale($this->scale); + + [$quotient, $remainder] = Calculator::get()->divQR($p, $q); + + $scale = $this->scale > $that->scale ? $this->scale : $that->scale; + + $quotient = new BigDecimal($quotient, 0); + $remainder = new BigDecimal($remainder, $scale); + + return [$quotient, $remainder]; + } + + /** + * Returns the square root of this number, rounded down to the given number of decimals. + * + * @param int $scale + * + * @return BigDecimal + * + * @throws \InvalidArgumentException If the scale is negative. + * @throws NegativeNumberException If this number is negative. + */ + public function sqrt(int $scale) : BigDecimal + { + if ($scale < 0) { + throw new \InvalidArgumentException('Scale cannot be negative.'); + } + + if ($this->value === '0') { + return new BigDecimal('0', $scale); + } + + if ($this->value[0] === '-') { + throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); + } + + $value = $this->value; + $addDigits = 2 * $scale - $this->scale; + + if ($addDigits > 0) { + // add zeros + $value .= \str_repeat('0', $addDigits); + } elseif ($addDigits < 0) { + // trim digits + if (-$addDigits >= \strlen($this->value)) { + // requesting a scale too low, will always yield a zero result + return new BigDecimal('0', $scale); + } + + $value = \substr($value, 0, $addDigits); + } + + $value = Calculator::get()->sqrt($value); + + return new BigDecimal($value, $scale); + } + + /** + * Returns a copy of this BigDecimal with the decimal point moved $n places to the left. + * + * @param int $n + * + * @return BigDecimal + */ + public function withPointMovedLeft(int $n) : BigDecimal + { + if ($n === 0) { + return $this; + } + + if ($n < 0) { + return $this->withPointMovedRight(-$n); + } + + return new BigDecimal($this->value, $this->scale + $n); + } + + /** + * Returns a copy of this BigDecimal with the decimal point moved $n places to the right. + * + * @param int $n + * + * @return BigDecimal + */ + public function withPointMovedRight(int $n) : BigDecimal + { + if ($n === 0) { + return $this; + } + + if ($n < 0) { + return $this->withPointMovedLeft(-$n); + } + + $value = $this->value; + $scale = $this->scale - $n; + + if ($scale < 0) { + if ($value !== '0') { + $value .= \str_repeat('0', -$scale); + } + $scale = 0; + } + + return new BigDecimal($value, $scale); + } + + /** + * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part. + * + * @return BigDecimal + */ + public function stripTrailingZeros() : BigDecimal + { + if ($this->scale === 0) { + return $this; + } + + $trimmedValue = \rtrim($this->value, '0'); + + if ($trimmedValue === '') { + return BigDecimal::zero(); + } + + $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue); + + if ($trimmableZeros === 0) { + return $this; + } + + if ($trimmableZeros > $this->scale) { + $trimmableZeros = $this->scale; + } + + $value = \substr($this->value, 0, -$trimmableZeros); + $scale = $this->scale - $trimmableZeros; + + return new BigDecimal($value, $scale); + } + + /** + * Returns the absolute value of this number. + * + * @return BigDecimal + */ + public function abs() : BigDecimal + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the negated value of this number. + * + * @return BigDecimal + */ + public function negated() : BigDecimal + { + return new BigDecimal(Calculator::get()->neg($this->value), $this->scale); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + $that = $that->toBigDecimal(); + } + + if ($that instanceof BigDecimal) { + [$a, $b] = $this->scaleValues($this, $that); + + return Calculator::get()->cmp($a, $b); + } + + return - $that->compareTo($this); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + /** + * @return BigInteger + */ + public function getUnscaledValue() : BigInteger + { + return BigInteger::create($this->value); + } + + /** + * @return int + */ + public function getScale() : int + { + return $this->scale; + } + + /** + * Returns a string representing the integral part of this decimal number. + * + * Example: `-123.456` => `-123`. + * + * @return string + */ + public function getIntegralPart() : string + { + if ($this->scale === 0) { + return $this->value; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, 0, -$this->scale); + } + + /** + * Returns a string representing the fractional part of this decimal number. + * + * If the scale is zero, an empty string is returned. + * + * Examples: `-123.456` => '456', `123` => ''. + * + * @return string + */ + public function getFractionalPart() : string + { + if ($this->scale === 0) { + return ''; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, -$this->scale); + } + + /** + * Returns whether this decimal number has a non-zero fractional part. + * + * @return bool + */ + public function hasNonZeroFractionalPart() : bool + { + return $this->getFractionalPart() !== \str_repeat('0', $this->scale); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0); + + return BigInteger::create($zeroScaleDecimal->value); + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + $numerator = BigInteger::create($this->value); + $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale)); + + return BigRational::create($numerator, $denominator, false); + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + if ($scale === $this->scale) { + return $this; + } + + return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return (float) (string) $this; + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + if ($this->scale === 0) { + return $this->value; + } + + $value = $this->getUnscaledValueWithLeadingZeros(); + + return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale); + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{value: string, scale: int} + */ + public function __serialize(): array + { + return ['value' => $this->value, 'scale' => $this->scale]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{value: string, scale: int} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->value)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $data['value']; + $this->scale = $data['scale']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->value . ':' . $this->scale; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->value)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + [$value, $scale] = \explode(':', $value); + + $this->value = $value; + $this->scale = (int) $scale; + } + + /** + * Puts the internal values of the given decimal numbers on the same scale. + * + * @param BigDecimal $x The first decimal number. + * @param BigDecimal $y The second decimal number. + * + * @return array{string, string} The scaled integer values of $x and $y. + */ + private function scaleValues(BigDecimal $x, BigDecimal $y) : array + { + $a = $x->value; + $b = $y->value; + + if ($b !== '0' && $x->scale > $y->scale) { + $b .= \str_repeat('0', $x->scale - $y->scale); + } elseif ($a !== '0' && $x->scale < $y->scale) { + $a .= \str_repeat('0', $y->scale - $x->scale); + } + + return [$a, $b]; + } + + /** + * @param int $scale + * + * @return string + */ + private function valueWithMinScale(int $scale) : string + { + $value = $this->value; + + if ($this->value !== '0' && $scale > $this->scale) { + $value .= \str_repeat('0', $scale - $this->scale); + } + + return $value; + } + + /** + * Adds leading zeros if necessary to the unscaled value to represent the full decimal number. + * + * @return string + */ + private function getUnscaledValueWithLeadingZeros() : string + { + $value = $this->value; + $targetLength = $this->scale + 1; + $negative = ($value[0] === '-'); + $length = \strlen($value); + + if ($negative) { + $length--; + } + + if ($length >= $targetLength) { + return $this->value; + } + + if ($negative) { + $value = \substr($value, 1); + } + + $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT); + + if ($negative) { + $value = '-' . $value; + } + + return $value; + } +} diff --git a/transfer-protocol/vendor/brick/math/src/BigInteger.php b/transfer-protocol/vendor/brick/math/src/BigInteger.php new file mode 100644 index 0000000..f213fbe --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/BigInteger.php @@ -0,0 +1,1184 @@ +value = $value; + } + + /** + * Creates a BigInteger of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigInteger + * + * @throws MathException If the value cannot be converted to a BigInteger. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigInteger(); + } + + /** + * Creates a number from a string in a given base. + * + * The string can optionally be prefixed with the `+` or `-` sign. + * + * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase + * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not + * differentiate lowercase and uppercase characters, which are considered equal. + * + * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method. + * + * @param string $number The number to convert, in the given base. + * @param int $base The base of the number, between 2 and 36. + * + * @return BigInteger + * + * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base. + * @throws \InvalidArgumentException If the base is out of range. + * + * @psalm-pure + */ + public static function fromBase(string $number, int $base) : BigInteger + { + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + if ($base < 2 || $base > 36) { + throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base)); + } + + if ($number[0] === '-') { + $sign = '-'; + $number = \substr($number, 1); + } elseif ($number[0] === '+') { + $sign = ''; + $number = \substr($number, 1); + } else { + $sign = ''; + } + + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + $number = \ltrim($number, '0'); + + if ($number === '') { + // The result will be the same in any base, avoid further calculation. + return BigInteger::zero(); + } + + if ($number === '1') { + // The result will be the same in any base, avoid further calculation. + return new BigInteger($sign . '1'); + } + + $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/'; + + if (\preg_match($pattern, \strtolower($number), $matches) === 1) { + throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base)); + } + + if ($base === 10) { + // The number is usable as is, avoid further calculation. + return new BigInteger($sign . $number); + } + + $result = Calculator::get()->fromBase($number, $base); + + return new BigInteger($sign . $result); + } + + /** + * Parses a string containing an integer in an arbitrary base, using a custom alphabet. + * + * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers. + * + * @param string $number The number to parse. + * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. + * + * @return BigInteger + * + * @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet. + * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars. + * + * @psalm-pure + */ + public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger + { + if ($number === '') { + throw new NumberFormatException('The number cannot be empty.'); + } + + $base = \strlen($alphabet); + + if ($base < 2) { + throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.'); + } + + $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/'; + + if (\preg_match($pattern, $number, $matches) === 1) { + throw NumberFormatException::charNotInAlphabet($matches[0]); + } + + $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base); + + return new BigInteger($number); + } + + /** + * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger. + * + * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element. + * + * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is + * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the + * resulting BigInteger will always be positive or zero. + * + * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match. + * + * @param string $value The byte string. + * @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading + * sign bit. + * + * @return BigInteger + * + * @throws NumberFormatException If the string is empty. + */ + public static function fromBytes(string $value, bool $signed = true) : BigInteger + { + if ($value === '') { + throw new NumberFormatException('The byte string must not be empty.'); + } + + $twosComplement = false; + + if ($signed) { + $x = \ord($value[0]); + + if (($twosComplement = ($x >= 0x80))) { + $value = ~$value; + } + } + + $number = self::fromBase(\bin2hex($value), 16); + + if ($twosComplement) { + return $number->plus(1)->negated(); + } + + return $number; + } + + /** + * Generates a pseudo-random number in the range 0 to 2^numBits - 1. + * + * Using the default random bytes generator, this method is suitable for cryptographic use. + * + * @psalm-param callable(int): string $randomBytesGenerator + * + * @param int $numBits The number of bits. + * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a + * string of random bytes of the given length. Defaults to the + * `random_bytes()` function. + * + * @return BigInteger + * + * @throws \InvalidArgumentException If $numBits is negative. + */ + public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger + { + if ($numBits < 0) { + throw new \InvalidArgumentException('The number of bits cannot be negative.'); + } + + if ($numBits === 0) { + return BigInteger::zero(); + } + + if ($randomBytesGenerator === null) { + $randomBytesGenerator = 'random_bytes'; + } + + $byteLength = \intdiv($numBits - 1, 8) + 1; + + $extraBits = ($byteLength * 8 - $numBits); + $bitmask = \chr(0xFF >> $extraBits); + + $randomBytes = $randomBytesGenerator($byteLength); + $randomBytes[0] = $randomBytes[0] & $bitmask; + + return self::fromBytes($randomBytes, false); + } + + /** + * Generates a pseudo-random number between `$min` and `$max`. + * + * Using the default random bytes generator, this method is suitable for cryptographic use. + * + * @psalm-param (callable(int): string)|null $randomBytesGenerator + * + * @param BigNumber|int|float|string $min The lower bound. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $max The upper bound. Must be convertible to a BigInteger. + * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, + * and returns a string of random bytes of the given length. + * Defaults to the `random_bytes()` function. + * + * @return BigInteger + * + * @throws MathException If one of the parameters cannot be converted to a BigInteger, + * or `$min` is greater than `$max`. + */ + public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger + { + $min = BigInteger::of($min); + $max = BigInteger::of($max); + + if ($min->isGreaterThan($max)) { + throw new MathException('$min cannot be greater than $max.'); + } + + if ($min->isEqualTo($max)) { + return $min; + } + + $diff = $max->minus($min); + $bitLength = $diff->getBitLength(); + + // try until the number is in range (50% to 100% chance of success) + do { + $randomNumber = self::randomBits($bitLength, $randomBytesGenerator); + } while ($randomNumber->isGreaterThan($diff)); + + return $randomNumber->plus($min); + } + + /** + * Returns a BigInteger representing zero. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function zero() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigInteger('0'); + } + + return $zero; + } + + /** + * Returns a BigInteger representing one. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function one() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $one + */ + static $one; + + if ($one === null) { + $one = new BigInteger('1'); + } + + return $one; + } + + /** + * Returns a BigInteger representing ten. + * + * @return BigInteger + * + * @psalm-pure + */ + public static function ten() : BigInteger + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigInteger|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigInteger('10'); + } + + return $ten; + } + + /** + * Returns the sum of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function plus($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + return $this; + } + + if ($this->value === '0') { + return $that; + } + + $value = Calculator::get()->add($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the difference of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function minus($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + return $this; + } + + $value = Calculator::get()->sub($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the product of this number and the given one. + * + * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger. + * + * @return BigInteger The result. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger. + */ + public function multipliedBy($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($this->value === '1') { + return $that; + } + + $value = Calculator::get()->mul($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the result of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * @param int $roundingMode An optional rounding mode. + * + * @return BigInteger The result. + * + * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero, + * or RoundingMode::UNNECESSARY is used and the remainder is not zero. + */ + public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode); + + return new BigInteger($result); + } + + /** + * Returns this number exponentiated to the given value. + * + * @param int $exponent The exponent. + * + * @return BigInteger The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigInteger + { + if ($exponent === 0) { + return BigInteger::one(); + } + + if ($exponent === 1) { + return $this; + } + + if ($exponent < 0 || $exponent > Calculator::MAX_POWER) { + throw new \InvalidArgumentException(\sprintf( + 'The exponent %d is not in the range 0 to %d.', + $exponent, + Calculator::MAX_POWER + )); + } + + return new BigInteger(Calculator::get()->pow($this->value, $exponent)); + } + + /** + * Returns the quotient of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotient($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return $this; + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $quotient = Calculator::get()->divQ($this->value, $that->value); + + return new BigInteger($quotient); + } + + /** + * Returns the remainder of the division of this number by the given one. + * + * The remainder, when non-zero, has the same sign as the dividend. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function remainder($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '1') { + return BigInteger::zero(); + } + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + $remainder = Calculator::get()->divR($this->value, $that->value); + + return new BigInteger($remainder); + } + + /** + * Returns the quotient and remainder of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger[] An array containing the quotient and the remainder. + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotientAndRemainder($that) : array + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::divisionByZero(); + } + + [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value); + + return [ + new BigInteger($quotient), + new BigInteger($remainder) + ]; + } + + /** + * Returns the modulo of this number and the given one. + * + * The modulo operation yields the same result as the remainder operation when both operands are of the same sign, + * and may differ when signs are different. + * + * The result of the modulo operation, when non-zero, has the same sign as the divisor. + * + * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger. + * + * @return BigInteger + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function mod($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0') { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + $value = Calculator::get()->mod($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the modular multiplicative inverse of this BigInteger modulo $m. + * + * @param BigInteger $m + * + * @return BigInteger + * + * @throws DivisionByZeroException If $m is zero. + * @throws NegativeNumberException If $m is negative. + * @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger + * is not relatively prime to m). + */ + public function modInverse(BigInteger $m) : BigInteger + { + if ($m->value === '0') { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + if ($m->isNegative()) { + throw new NegativeNumberException('Modulus must not be negative.'); + } + + if ($m->value === '1') { + return BigInteger::zero(); + } + + $value = Calculator::get()->modInverse($this->value, $m->value); + + if ($value === null) { + throw new MathException('Unable to compute the modInverse for the given modulus.'); + } + + return new BigInteger($value); + } + + /** + * Returns this number raised into power with modulo. + * + * This operation only works on positive numbers. + * + * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero. + * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive. + * + * @return BigInteger + * + * @throws NegativeNumberException If any of the operands is negative. + * @throws DivisionByZeroException If the modulus is zero. + */ + public function modPow($exp, $mod) : BigInteger + { + $exp = BigInteger::of($exp); + $mod = BigInteger::of($mod); + + if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) { + throw new NegativeNumberException('The operands cannot be negative.'); + } + + if ($mod->isZero()) { + throw DivisionByZeroException::modulusMustNotBeZero(); + } + + $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value); + + return new BigInteger($result); + } + + /** + * Returns the greatest common divisor of this number and the given one. + * + * The GCD is always positive, unless both operands are zero, in which case it is zero. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function gcd($that) : BigInteger + { + $that = BigInteger::of($that); + + if ($that->value === '0' && $this->value[0] !== '-') { + return $this; + } + + if ($this->value === '0' && $that->value[0] !== '-') { + return $that; + } + + $value = Calculator::get()->gcd($this->value, $that->value); + + return new BigInteger($value); + } + + /** + * Returns the integer square root number of this number, rounded down. + * + * The result is the largest x such that x² ≤ n. + * + * @return BigInteger + * + * @throws NegativeNumberException If this number is negative. + */ + public function sqrt() : BigInteger + { + if ($this->value[0] === '-') { + throw new NegativeNumberException('Cannot calculate the square root of a negative number.'); + } + + $value = Calculator::get()->sqrt($this->value); + + return new BigInteger($value); + } + + /** + * Returns the absolute value of this number. + * + * @return BigInteger + */ + public function abs() : BigInteger + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the inverse of this number. + * + * @return BigInteger + */ + public function negated() : BigInteger + { + return new BigInteger(Calculator::get()->neg($this->value)); + } + + /** + * Returns the integer bitwise-and combined with another integer. + * + * This method returns a negative BigInteger if and only if both operands are negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function and($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->and($this->value, $that->value)); + } + + /** + * Returns the integer bitwise-or combined with another integer. + * + * This method returns a negative BigInteger if and only if either of the operands is negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function or($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->or($this->value, $that->value)); + } + + /** + * Returns the integer bitwise-xor combined with another integer. + * + * This method returns a negative BigInteger if and only if exactly one of the operands is negative. + * + * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number. + * + * @return BigInteger + */ + public function xor($that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->xor($this->value, $that->value)); + } + + /** + * Returns the bitwise-not of this BigInteger. + * + * @return BigInteger + */ + public function not() : BigInteger + { + return $this->negated()->minus(1); + } + + /** + * Returns the integer left shifted by a given number of bits. + * + * @param int $distance The distance to shift. + * + * @return BigInteger + */ + public function shiftedLeft(int $distance) : BigInteger + { + if ($distance === 0) { + return $this; + } + + if ($distance < 0) { + return $this->shiftedRight(- $distance); + } + + return $this->multipliedBy(BigInteger::of(2)->power($distance)); + } + + /** + * Returns the integer right shifted by a given number of bits. + * + * @param int $distance The distance to shift. + * + * @return BigInteger + */ + public function shiftedRight(int $distance) : BigInteger + { + if ($distance === 0) { + return $this; + } + + if ($distance < 0) { + return $this->shiftedLeft(- $distance); + } + + $operand = BigInteger::of(2)->power($distance); + + if ($this->isPositiveOrZero()) { + return $this->quotient($operand); + } + + return $this->dividedBy($operand, RoundingMode::UP); + } + + /** + * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit. + * + * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation. + * Computes (ceil(log2(this < 0 ? -this : this+1))). + * + * @return int + */ + public function getBitLength() : int + { + if ($this->value === '0') { + return 0; + } + + if ($this->isNegative()) { + return $this->abs()->minus(1)->getBitLength(); + } + + return \strlen($this->toBase(2)); + } + + /** + * Returns the index of the rightmost (lowest-order) one bit in this BigInteger. + * + * Returns -1 if this BigInteger contains no one bits. + * + * @return int + */ + public function getLowestSetBit() : int + { + $n = $this; + $bitLength = $this->getBitLength(); + + for ($i = 0; $i <= $bitLength; $i++) { + if ($n->isOdd()) { + return $i; + } + + $n = $n->shiftedRight(1); + } + + return -1; + } + + /** + * Returns whether this number is even. + * + * @return bool + */ + public function isEven() : bool + { + return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true); + } + + /** + * Returns whether this number is odd. + * + * @return bool + */ + public function isOdd() : bool + { + return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], true); + } + + /** + * Returns true if and only if the designated bit is set. + * + * Computes ((this & (1<shiftedRight($n)->isOdd(); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + return Calculator::get()->cmp($this->value, $that->value); + } + + return - $that->compareTo($this); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return BigDecimal::create($this->value); + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + return BigRational::create($this, BigInteger::one(), false); + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->toBigDecimal()->toScale($scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + $intValue = (int) $this->value; + + if ($this->value !== (string) $intValue) { + throw IntegerOverflowException::toIntOverflow($this); + } + + return $intValue; + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return (float) $this->value; + } + + /** + * Returns a string representation of this number in the given base. + * + * The output will always be lowercase for bases greater than 10. + * + * @param int $base + * + * @return string + * + * @throws \InvalidArgumentException If the base is out of range. + */ + public function toBase(int $base) : string + { + if ($base === 10) { + return $this->value; + } + + if ($base < 2 || $base > 36) { + throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base)); + } + + return Calculator::get()->toBase($this->value, $base); + } + + /** + * Returns a string representation of this number in an arbitrary base with a custom alphabet. + * + * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers; + * a NegativeNumberException will be thrown when attempting to call this method on a negative number. + * + * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8. + * + * @return string + * + * @throws NegativeNumberException If this number is negative. + * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars. + */ + public function toArbitraryBase(string $alphabet) : string + { + $base = \strlen($alphabet); + + if ($base < 2) { + throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.'); + } + + if ($this->value[0] === '-') { + throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.'); + } + + return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base); + } + + /** + * Returns a string of bytes containing the binary representation of this BigInteger. + * + * The string is in big-endian byte-order: the most significant byte is in the zeroth element. + * + * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to + * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the + * number is negative. + * + * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit + * if `$signed` is true. + * + * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match. + * + * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit. + * + * @return string + * + * @throws NegativeNumberException If $signed is false, and the number is negative. + */ + public function toBytes(bool $signed = true) : string + { + if (! $signed && $this->isNegative()) { + throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.'); + } + + $hex = $this->abs()->toBase(16); + + if (\strlen($hex) % 2 !== 0) { + $hex = '0' . $hex; + } + + $baseHexLength = \strlen($hex); + + if ($signed) { + if ($this->isNegative()) { + $bin = \hex2bin($hex); + assert($bin !== false); + + $hex = \bin2hex(~$bin); + $hex = self::fromBase($hex, 16)->plus(1)->toBase(16); + + $hexLength = \strlen($hex); + + if ($hexLength < $baseHexLength) { + $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex; + } + + if ($hex[0] < '8') { + $hex = 'FF' . $hex; + } + } else { + if ($hex[0] >= '8') { + $hex = '00' . $hex; + } + } + } + + return \hex2bin($hex); + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + return $this->value; + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{value: string} + */ + public function __serialize(): array + { + return ['value' => $this->value]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{value: string} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->value)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $data['value']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->value; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->value)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + $this->value = $value; + } +} diff --git a/transfer-protocol/vendor/brick/math/src/BigNumber.php b/transfer-protocol/vendor/brick/math/src/BigNumber.php new file mode 100644 index 0000000..38c8c55 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/BigNumber.php @@ -0,0 +1,572 @@ +[\-\+])?' . + '(?:' . + '(?:' . + '(?[0-9]+)?' . + '(?\.)?' . + '(?[0-9]+)?' . + '(?:[eE](?[\-\+]?[0-9]+))?' . + ')|(?:' . + '(?[0-9]+)' . + '\/?' . + '(?[0-9]+)' . + ')' . + ')' . + '$/'; + + /** + * Creates a BigNumber of the given value. + * + * The concrete return type is dependent on the given value, with the following rules: + * + * - BigNumber instances are returned as is + * - integer numbers are returned as BigInteger + * - floating point numbers are converted to a string then parsed as such + * - strings containing a `/` character are returned as BigRational + * - strings containing a `.` character or using an exponential notation are returned as BigDecimal + * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger + * + * @param BigNumber|int|float|string $value + * + * @return BigNumber + * + * @throws NumberFormatException If the format of the number is not valid. + * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + if ($value instanceof BigNumber) { + return $value; + } + + if (\is_int($value)) { + return new BigInteger((string) $value); + } + + /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */ + $value = \is_float($value) ? self::floatToString($value) : (string) $value; + + $throw = static function() use ($value) : void { + throw new NumberFormatException(\sprintf( + 'The given value "%s" does not represent a valid number.', + $value + )); + }; + + if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) { + $throw(); + } + + $getMatch = static function(string $value) use ($matches) : ?string { + return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null; + }; + + $sign = $getMatch('sign'); + $numerator = $getMatch('numerator'); + $denominator = $getMatch('denominator'); + + if ($numerator !== null) { + assert($denominator !== null); + + if ($sign !== null) { + $numerator = $sign . $numerator; + } + + $numerator = self::cleanUp($numerator); + $denominator = self::cleanUp($denominator); + + if ($denominator === '0') { + throw DivisionByZeroException::denominatorMustNotBeZero(); + } + + return new BigRational( + new BigInteger($numerator), + new BigInteger($denominator), + false + ); + } + + $point = $getMatch('point'); + $integral = $getMatch('integral'); + $fractional = $getMatch('fractional'); + $exponent = $getMatch('exponent'); + + if ($integral === null && $fractional === null) { + $throw(); + } + + if ($integral === null) { + $integral = '0'; + } + + if ($point !== null || $exponent !== null) { + $fractional = ($fractional ?? ''); + $exponent = ($exponent !== null) ? (int) $exponent : 0; + + if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) { + throw new NumberFormatException('Exponent too large.'); + } + + $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional); + + $scale = \strlen($fractional) - $exponent; + + if ($scale < 0) { + if ($unscaledValue !== '0') { + $unscaledValue .= \str_repeat('0', - $scale); + } + $scale = 0; + } + + return new BigDecimal($unscaledValue, $scale); + } + + $integral = self::cleanUp(($sign ?? '') . $integral); + + return new BigInteger($integral); + } + + /** + * Safely converts float to string, avoiding locale-dependent issues. + * + * @see https://github.com/brick/math/pull/20 + * + * @param float $float + * + * @return string + * + * @psalm-pure + * @psalm-suppress ImpureFunctionCall + */ + private static function floatToString(float $float) : string + { + $currentLocale = \setlocale(LC_NUMERIC, '0'); + \setlocale(LC_NUMERIC, 'C'); + + $result = (string) $float; + + \setlocale(LC_NUMERIC, $currentLocale); + + return $result; + } + + /** + * Proxy method to access protected constructors from sibling classes. + * + * @internal + * + * @param mixed ...$args The arguments to the constructor. + * + * @return static + * + * @psalm-pure + * @psalm-suppress TooManyArguments + * @psalm-suppress UnsafeInstantiation + */ + protected static function create(... $args) : BigNumber + { + return new static(... $args); + } + + /** + * Returns the minimum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The minimum value. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function min(...$values) : BigNumber + { + $min = null; + + foreach ($values as $value) { + $value = static::of($value); + + if ($min === null || $value->isLessThan($min)) { + $min = $value; + } + } + + if ($min === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $min; + } + + /** + * Returns the maximum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The maximum value. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function max(...$values) : BigNumber + { + $max = null; + + foreach ($values as $value) { + $value = static::of($value); + + if ($max === null || $value->isGreaterThan($max)) { + $max = $value; + } + } + + if ($max === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $max; + } + + /** + * Returns the sum of the given values. + * + * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible + * to an instance of the class this method is called on. + * + * @return static The sum. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-suppress LessSpecificReturnStatement + * @psalm-suppress MoreSpecificReturnType + * @psalm-pure + */ + public static function sum(...$values) : BigNumber + { + /** @var BigNumber|null $sum */ + $sum = null; + + foreach ($values as $value) { + $value = static::of($value); + + $sum = $sum === null ? $value : self::add($sum, $value); + } + + if ($sum === null) { + throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.'); + } + + return $sum; + } + + /** + * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException. + * + * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to + * concrete classes the responsibility to perform the addition themselves or delegate it to the given number, + * depending on their ability to perform the operation. This will also require a version bump because we're + * potentially breaking custom BigNumber implementations (if any...) + * + * @param BigNumber $a + * @param BigNumber $b + * + * @return BigNumber + * + * @psalm-pure + */ + private static function add(BigNumber $a, BigNumber $b) : BigNumber + { + if ($a instanceof BigRational) { + return $a->plus($b); + } + + if ($b instanceof BigRational) { + return $b->plus($a); + } + + if ($a instanceof BigDecimal) { + return $a->plus($b); + } + + if ($b instanceof BigDecimal) { + return $b->plus($a); + } + + /** @var BigInteger $a */ + + return $a->plus($b); + } + + /** + * Removes optional leading zeros and + sign from the given number. + * + * @param string $number The number, validated as a non-empty string of digits with optional leading sign. + * + * @return string + * + * @psalm-pure + */ + private static function cleanUp(string $number) : string + { + $firstChar = $number[0]; + + if ($firstChar === '+' || $firstChar === '-') { + $number = \substr($number, 1); + } + + $number = \ltrim($number, '0'); + + if ($number === '') { + return '0'; + } + + if ($firstChar === '-') { + return '-' . $number; + } + + return $number; + } + + /** + * Checks if this number is equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isEqualTo($that) : bool + { + return $this->compareTo($that) === 0; + } + + /** + * Checks if this number is strictly lower than the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isLessThan($that) : bool + { + return $this->compareTo($that) < 0; + } + + /** + * Checks if this number is lower than or equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isLessThanOrEqualTo($that) : bool + { + return $this->compareTo($that) <= 0; + } + + /** + * Checks if this number is strictly greater than the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isGreaterThan($that) : bool + { + return $this->compareTo($that) > 0; + } + + /** + * Checks if this number is greater than or equal to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return bool + */ + public function isGreaterThanOrEqualTo($that) : bool + { + return $this->compareTo($that) >= 0; + } + + /** + * Checks if this number equals zero. + * + * @return bool + */ + public function isZero() : bool + { + return $this->getSign() === 0; + } + + /** + * Checks if this number is strictly negative. + * + * @return bool + */ + public function isNegative() : bool + { + return $this->getSign() < 0; + } + + /** + * Checks if this number is negative or zero. + * + * @return bool + */ + public function isNegativeOrZero() : bool + { + return $this->getSign() <= 0; + } + + /** + * Checks if this number is strictly positive. + * + * @return bool + */ + public function isPositive() : bool + { + return $this->getSign() > 0; + } + + /** + * Checks if this number is positive or zero. + * + * @return bool + */ + public function isPositiveOrZero() : bool + { + return $this->getSign() >= 0; + } + + /** + * Returns the sign of this number. + * + * @return int -1 if the number is negative, 0 if zero, 1 if positive. + */ + abstract public function getSign() : int; + + /** + * Compares this number to the given one. + * + * @param BigNumber|int|float|string $that + * + * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`. + * + * @throws MathException If the number is not valid. + */ + abstract public function compareTo($that) : int; + + /** + * Converts this number to a BigInteger. + * + * @return BigInteger The converted number. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding. + */ + abstract public function toBigInteger() : BigInteger; + + /** + * Converts this number to a BigDecimal. + * + * @return BigDecimal The converted number. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding. + */ + abstract public function toBigDecimal() : BigDecimal; + + /** + * Converts this number to a BigRational. + * + * @return BigRational The converted number. + */ + abstract public function toBigRational() : BigRational; + + /** + * Converts this number to a BigDecimal with the given scale, using rounding if necessary. + * + * @param int $scale The scale of the resulting `BigDecimal`. + * @param int $roundingMode A `RoundingMode` constant. + * + * @return BigDecimal + * + * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding. + * This only applies when RoundingMode::UNNECESSARY is used. + */ + abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal; + + /** + * Returns the exact value of this number as a native integer. + * + * If this number cannot be converted to a native integer without losing precision, an exception is thrown. + * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit. + * + * @return int The converted value. + * + * @throws MathException If this number cannot be exactly converted to a native integer. + */ + abstract public function toInt() : int; + + /** + * Returns an approximation of this number as a floating-point value. + * + * Note that this method can discard information as the precision of a floating-point value + * is inherently limited. + * + * If the number is greater than the largest representable floating point number, positive infinity is returned. + * If the number is less than the smallest representable floating point number, negative infinity is returned. + * + * @return float The converted value. + */ + abstract public function toFloat() : float; + + /** + * Returns a string representation of this number. + * + * The output of this method can be parsed by the `of()` factory method; + * this will yield an object equal to this one, without any information loss. + * + * @return string + */ + abstract public function __toString() : string; + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : string + { + return $this->__toString(); + } +} diff --git a/transfer-protocol/vendor/brick/math/src/BigRational.php b/transfer-protocol/vendor/brick/math/src/BigRational.php new file mode 100644 index 0000000..bee094f --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/BigRational.php @@ -0,0 +1,523 @@ +isZero()) { + throw DivisionByZeroException::denominatorMustNotBeZero(); + } + + if ($denominator->isNegative()) { + $numerator = $numerator->negated(); + $denominator = $denominator->negated(); + } + } + + $this->numerator = $numerator; + $this->denominator = $denominator; + } + + /** + * Creates a BigRational of the given value. + * + * @param BigNumber|int|float|string $value + * + * @return BigRational + * + * @throws MathException If the value cannot be converted to a BigRational. + * + * @psalm-pure + */ + public static function of($value) : BigNumber + { + return parent::of($value)->toBigRational(); + } + + /** + * Creates a BigRational out of a numerator and a denominator. + * + * If the denominator is negative, the signs of both the numerator and the denominator + * will be inverted to ensure that the denominator is always positive. + * + * @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger. + * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger. + * + * @return BigRational + * + * @throws NumberFormatException If an argument does not represent a valid number. + * @throws RoundingNecessaryException If an argument represents a non-integer number. + * @throws DivisionByZeroException If the denominator is zero. + * + * @psalm-pure + */ + public static function nd($numerator, $denominator) : BigRational + { + $numerator = BigInteger::of($numerator); + $denominator = BigInteger::of($denominator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns a BigRational representing zero. + * + * @return BigRational + * + * @psalm-pure + */ + public static function zero() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $zero + */ + static $zero; + + if ($zero === null) { + $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false); + } + + return $zero; + } + + /** + * Returns a BigRational representing one. + * + * @return BigRational + * + * @psalm-pure + */ + public static function one() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $one + */ + static $one; + + if ($one === null) { + $one = new BigRational(BigInteger::one(), BigInteger::one(), false); + } + + return $one; + } + + /** + * Returns a BigRational representing ten. + * + * @return BigRational + * + * @psalm-pure + */ + public static function ten() : BigRational + { + /** + * @psalm-suppress ImpureStaticVariable + * @var BigRational|null $ten + */ + static $ten; + + if ($ten === null) { + $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false); + } + + return $ten; + } + + /** + * @return BigInteger + */ + public function getNumerator() : BigInteger + { + return $this->numerator; + } + + /** + * @return BigInteger + */ + public function getDenominator() : BigInteger + { + return $this->denominator; + } + + /** + * Returns the quotient of the division of the numerator by the denominator. + * + * @return BigInteger + */ + public function quotient() : BigInteger + { + return $this->numerator->quotient($this->denominator); + } + + /** + * Returns the remainder of the division of the numerator by the denominator. + * + * @return BigInteger + */ + public function remainder() : BigInteger + { + return $this->numerator->remainder($this->denominator); + } + + /** + * Returns the quotient and remainder of the division of the numerator by the denominator. + * + * @return BigInteger[] + */ + public function quotientAndRemainder() : array + { + return $this->numerator->quotientAndRemainder($this->denominator); + } + + /** + * Returns the sum of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to add. + * + * @return BigRational The result. + * + * @throws MathException If the number is not valid. + */ + public function plus($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator)); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the difference of this number and the given one. + * + * @param BigNumber|int|float|string $that The number to subtract. + * + * @return BigRational The result. + * + * @throws MathException If the number is not valid. + */ + public function minus($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator)); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the product of this number and the given one. + * + * @param BigNumber|int|float|string $that The multiplier. + * + * @return BigRational The result. + * + * @throws MathException If the multiplier is not a valid number. + */ + public function multipliedBy($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->numerator); + $denominator = $this->denominator->multipliedBy($that->denominator); + + return new BigRational($numerator, $denominator, false); + } + + /** + * Returns the result of the division of this number by the given one. + * + * @param BigNumber|int|float|string $that The divisor. + * + * @return BigRational The result. + * + * @throws MathException If the divisor is not a valid number, or is zero. + */ + public function dividedBy($that) : BigRational + { + $that = BigRational::of($that); + + $numerator = $this->numerator->multipliedBy($that->denominator); + $denominator = $this->denominator->multipliedBy($that->numerator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns this number exponentiated to the given value. + * + * @param int $exponent The exponent. + * + * @return BigRational The result. + * + * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000. + */ + public function power(int $exponent) : BigRational + { + if ($exponent === 0) { + $one = BigInteger::one(); + + return new BigRational($one, $one, false); + } + + if ($exponent === 1) { + return $this; + } + + return new BigRational( + $this->numerator->power($exponent), + $this->denominator->power($exponent), + false + ); + } + + /** + * Returns the reciprocal of this BigRational. + * + * The reciprocal has the numerator and denominator swapped. + * + * @return BigRational + * + * @throws DivisionByZeroException If the numerator is zero. + */ + public function reciprocal() : BigRational + { + return new BigRational($this->denominator, $this->numerator, true); + } + + /** + * Returns the absolute value of this BigRational. + * + * @return BigRational + */ + public function abs() : BigRational + { + return new BigRational($this->numerator->abs(), $this->denominator, false); + } + + /** + * Returns the negated value of this BigRational. + * + * @return BigRational + */ + public function negated() : BigRational + { + return new BigRational($this->numerator->negated(), $this->denominator, false); + } + + /** + * Returns the simplified value of this BigRational. + * + * @return BigRational + */ + public function simplified() : BigRational + { + $gcd = $this->numerator->gcd($this->denominator); + + $numerator = $this->numerator->quotient($gcd); + $denominator = $this->denominator->quotient($gcd); + + return new BigRational($numerator, $denominator, false); + } + + /** + * {@inheritdoc} + */ + public function compareTo($that) : int + { + return $this->minus($that)->getSign(); + } + + /** + * {@inheritdoc} + */ + public function getSign() : int + { + return $this->numerator->getSign(); + } + + /** + * {@inheritdoc} + */ + public function toBigInteger() : BigInteger + { + $simplified = $this->simplified(); + + if (! $simplified->denominator->isEqualTo(1)) { + throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.'); + } + + return $simplified->numerator; + } + + /** + * {@inheritdoc} + */ + public function toBigDecimal() : BigDecimal + { + return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator); + } + + /** + * {@inheritdoc} + */ + public function toBigRational() : BigRational + { + return $this; + } + + /** + * {@inheritdoc} + */ + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); + } + + /** + * {@inheritdoc} + */ + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + /** + * {@inheritdoc} + */ + public function toFloat() : float + { + return $this->numerator->toFloat() / $this->denominator->toFloat(); + } + + /** + * {@inheritdoc} + */ + public function __toString() : string + { + $numerator = (string) $this->numerator; + $denominator = (string) $this->denominator; + + if ($denominator === '1') { + return $numerator; + } + + return $this->numerator . '/' . $this->denominator; + } + + /** + * This method is required for serializing the object and SHOULD NOT be accessed directly. + * + * @internal + * + * @return array{numerator: BigInteger, denominator: BigInteger} + */ + public function __serialize(): array + { + return ['numerator' => $this->numerator, 'denominator' => $this->denominator]; + } + + /** + * This method is only here to allow unserializing the object and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param array{numerator: BigInteger, denominator: BigInteger} $data + * + * @return void + * + * @throws \LogicException + */ + public function __unserialize(array $data): void + { + if (isset($this->numerator)) { + throw new \LogicException('__unserialize() is an internal function, it must not be called directly.'); + } + + $this->numerator = $data['numerator']; + $this->denominator = $data['denominator']; + } + + /** + * This method is required by interface Serializable and SHOULD NOT be accessed directly. + * + * @internal + * + * @return string + */ + public function serialize() : string + { + return $this->numerator . '/' . $this->denominator; + } + + /** + * This method is only here to implement interface Serializable and cannot be accessed directly. + * + * @internal + * @psalm-suppress RedundantPropertyInitializationCheck + * + * @param string $value + * + * @return void + * + * @throws \LogicException + */ + public function unserialize($value) : void + { + if (isset($this->numerator)) { + throw new \LogicException('unserialize() is an internal function, it must not be called directly.'); + } + + [$numerator, $denominator] = \explode('/', $value); + + $this->numerator = BigInteger::of($numerator); + $this->denominator = BigInteger::of($denominator); + } +} diff --git a/transfer-protocol/vendor/brick/math/src/Exception/DivisionByZeroException.php b/transfer-protocol/vendor/brick/math/src/Exception/DivisionByZeroException.php new file mode 100644 index 0000000..a4e4431 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/Exception/DivisionByZeroException.php @@ -0,0 +1,41 @@ + 126) { + $char = \strtoupper(\dechex($ord)); + + if ($ord < 10) { + $char = '0' . $char; + } + } else { + $char = '"' . $char . '"'; + } + + return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char)); + } +} diff --git a/transfer-protocol/vendor/brick/math/src/Exception/RoundingNecessaryException.php b/transfer-protocol/vendor/brick/math/src/Exception/RoundingNecessaryException.php new file mode 100644 index 0000000..1c61005 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/Exception/RoundingNecessaryException.php @@ -0,0 +1,21 @@ +init($a, $b); + + if ($aNeg && ! $bNeg) { + return -1; + } + + if ($bNeg && ! $aNeg) { + return 1; + } + + $aLen = \strlen($aDig); + $bLen = \strlen($bDig); + + if ($aLen < $bLen) { + $result = -1; + } elseif ($aLen > $bLen) { + $result = 1; + } else { + $result = $aDig <=> $bDig; + } + + return $aNeg ? -$result : $result; + } + + /** + * Adds two numbers. + * + * @param string $a The augend. + * @param string $b The addend. + * + * @return string The sum. + */ + abstract public function add(string $a, string $b) : string; + + /** + * Subtracts two numbers. + * + * @param string $a The minuend. + * @param string $b The subtrahend. + * + * @return string The difference. + */ + abstract public function sub(string $a, string $b) : string; + + /** + * Multiplies two numbers. + * + * @param string $a The multiplicand. + * @param string $b The multiplier. + * + * @return string The product. + */ + abstract public function mul(string $a, string $b) : string; + + /** + * Returns the quotient of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string The quotient. + */ + abstract public function divQ(string $a, string $b) : string; + + /** + * Returns the remainder of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string The remainder. + */ + abstract public function divR(string $a, string $b) : string; + + /** + * Returns the quotient and remainder of the division of two numbers. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * + * @return string[] An array containing the quotient and remainder. + */ + abstract public function divQR(string $a, string $b) : array; + + /** + * Exponentiates a number. + * + * @param string $a The base number. + * @param int $e The exponent, validated as an integer between 0 and MAX_POWER. + * + * @return string The power. + */ + abstract public function pow(string $a, int $e) : string; + + /** + * @param string $a + * @param string $b The modulus; must not be zero. + * + * @return string + */ + public function mod(string $a, string $b) : string + { + return $this->divR($this->add($this->divR($a, $b), $b), $b); + } + + /** + * Returns the modular multiplicative inverse of $x modulo $m. + * + * If $x has no multiplicative inverse mod m, this method must return null. + * + * This method can be overridden by the concrete implementation if the underlying library has built-in support. + * + * @param string $x + * @param string $m The modulus; must not be negative or zero. + * + * @return string|null + */ + public function modInverse(string $x, string $m) : ?string + { + if ($m === '1') { + return '0'; + } + + $modVal = $x; + + if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) { + $modVal = $this->mod($x, $m); + } + + $x = '0'; + $y = '0'; + $g = $this->gcdExtended($modVal, $m, $x, $y); + + if ($g !== '1') { + return null; + } + + return $this->mod($this->add($this->mod($x, $m), $m), $m); + } + + /** + * Raises a number into power with modulo. + * + * @param string $base The base number; must be positive or zero. + * @param string $exp The exponent; must be positive or zero. + * @param string $mod The modulus; must be strictly positive. + * + * @return string The power. + */ + abstract public function modPow(string $base, string $exp, string $mod) : string; + + /** + * Returns the greatest common divisor of the two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for GCD calculations. + * + * @param string $a The first number. + * @param string $b The second number. + * + * @return string The GCD, always positive, or zero if both arguments are zero. + */ + public function gcd(string $a, string $b) : string + { + if ($a === '0') { + return $this->abs($b); + } + + if ($b === '0') { + return $this->abs($a); + } + + return $this->gcd($b, $this->divR($a, $b)); + } + + private function gcdExtended(string $a, string $b, string &$x, string &$y) : string + { + if ($a === '0') { + $x = '0'; + $y = '1'; + + return $b; + } + + $x1 = '0'; + $y1 = '0'; + + $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1); + + $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1)); + $y = $x1; + + return $gcd; + } + + /** + * Returns the square root of the given number, rounded down. + * + * The result is the largest x such that x² ≤ n. + * The input MUST NOT be negative. + * + * @param string $n The number. + * + * @return string The square root. + */ + abstract public function sqrt(string $n) : string; + + /** + * Converts a number from an arbitrary base. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for base conversion. + * + * @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base. + * @param int $base The base of the number, validated from 2 to 36. + * + * @return string The converted number, following the Calculator conventions. + */ + public function fromBase(string $number, int $base) : string + { + return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base); + } + + /** + * Converts a number to an arbitrary base. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for base conversion. + * + * @param string $number The number to convert, following the Calculator conventions. + * @param int $base The base to convert to, validated from 2 to 36. + * + * @return string The converted number, lowercase. + */ + public function toBase(string $number, int $base) : string + { + $negative = ($number[0] === '-'); + + if ($negative) { + $number = \substr($number, 1); + } + + $number = $this->toArbitraryBase($number, self::ALPHABET, $base); + + if ($negative) { + return '-' . $number; + } + + return $number; + } + + /** + * Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10. + * + * @param string $number The number to convert, validated as a non-empty string, + * containing only chars in the given alphabet/base. + * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. + * @param int $base The base of the number, validated from 2 to alphabet length. + * + * @return string The number in base 10, following the Calculator conventions. + */ + final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string + { + // remove leading "zeros" + $number = \ltrim($number, $alphabet[0]); + + if ($number === '') { + return '0'; + } + + // optimize for "one" + if ($number === $alphabet[1]) { + return '1'; + } + + $result = '0'; + $power = '1'; + + $base = (string) $base; + + for ($i = \strlen($number) - 1; $i >= 0; $i--) { + $index = \strpos($alphabet, $number[$i]); + + if ($index !== 0) { + $result = $this->add($result, ($index === 1) + ? $power + : $this->mul($power, (string) $index) + ); + } + + if ($i !== 0) { + $power = $this->mul($power, $base); + } + } + + return $result; + } + + /** + * Converts a non-negative number to an arbitrary base using a custom alphabet. + * + * @param string $number The number to convert, positive or zero, following the Calculator conventions. + * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum. + * @param int $base The base to convert to, validated from 2 to alphabet length. + * + * @return string The converted number in the given alphabet. + */ + final public function toArbitraryBase(string $number, string $alphabet, int $base) : string + { + if ($number === '0') { + return $alphabet[0]; + } + + $base = (string) $base; + $result = ''; + + while ($number !== '0') { + [$number, $remainder] = $this->divQR($number, $base); + $remainder = (int) $remainder; + + $result .= $alphabet[$remainder]; + } + + return \strrev($result); + } + + /** + * Performs a rounded division. + * + * Rounding is performed when the remainder of the division is not zero. + * + * @param string $a The dividend. + * @param string $b The divisor, must not be zero. + * @param int $roundingMode The rounding mode. + * + * @return string + * + * @throws \InvalidArgumentException If the rounding mode is invalid. + * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. + */ + final public function divRound(string $a, string $b, int $roundingMode) : string + { + [$quotient, $remainder] = $this->divQR($a, $b); + + $hasDiscardedFraction = ($remainder !== '0'); + $isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-'); + + $discardedFractionSign = function() use ($remainder, $b) : int { + $r = $this->abs($this->mul($remainder, '2')); + $b = $this->abs($b); + + return $this->cmp($r, $b); + }; + + $increment = false; + + switch ($roundingMode) { + case RoundingMode::UNNECESSARY: + if ($hasDiscardedFraction) { + throw RoundingNecessaryException::roundingNecessary(); + } + break; + + case RoundingMode::UP: + $increment = $hasDiscardedFraction; + break; + + case RoundingMode::DOWN: + break; + + case RoundingMode::CEILING: + $increment = $hasDiscardedFraction && $isPositiveOrZero; + break; + + case RoundingMode::FLOOR: + $increment = $hasDiscardedFraction && ! $isPositiveOrZero; + break; + + case RoundingMode::HALF_UP: + $increment = $discardedFractionSign() >= 0; + break; + + case RoundingMode::HALF_DOWN: + $increment = $discardedFractionSign() > 0; + break; + + case RoundingMode::HALF_CEILING: + $increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0; + break; + + case RoundingMode::HALF_FLOOR: + $increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; + break; + + case RoundingMode::HALF_EVEN: + $lastDigit = (int) $quotient[-1]; + $lastDigitIsEven = ($lastDigit % 2 === 0); + $increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0; + break; + + default: + throw new \InvalidArgumentException('Invalid rounding mode.'); + } + + if ($increment) { + return $this->add($quotient, $isPositiveOrZero ? '1' : '-1'); + } + + return $quotient; + } + + /** + * Calculates bitwise AND of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function and(string $a, string $b) : string + { + return $this->bitwise('and', $a, $b); + } + + /** + * Calculates bitwise OR of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function or(string $a, string $b) : string + { + return $this->bitwise('or', $a, $b); + } + + /** + * Calculates bitwise XOR of two numbers. + * + * This method can be overridden by the concrete implementation if the underlying library + * has built-in support for bitwise operations. + * + * @param string $a + * @param string $b + * + * @return string + */ + public function xor(string $a, string $b) : string + { + return $this->bitwise('xor', $a, $b); + } + + /** + * Performs a bitwise operation on a decimal number. + * + * @param string $operator The operator to use, must be "and", "or" or "xor". + * @param string $a The left operand. + * @param string $b The right operand. + * + * @return string + */ + private function bitwise(string $operator, string $a, string $b) : string + { + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $aBin = $this->toBinary($aDig); + $bBin = $this->toBinary($bDig); + + $aLen = \strlen($aBin); + $bLen = \strlen($bBin); + + if ($aLen > $bLen) { + $bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin; + } elseif ($bLen > $aLen) { + $aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin; + } + + if ($aNeg) { + $aBin = $this->twosComplement($aBin); + } + if ($bNeg) { + $bBin = $this->twosComplement($bBin); + } + + switch ($operator) { + case 'and': + $value = $aBin & $bBin; + $negative = ($aNeg and $bNeg); + break; + + case 'or': + $value = $aBin | $bBin; + $negative = ($aNeg or $bNeg); + break; + + case 'xor': + $value = $aBin ^ $bBin; + $negative = ($aNeg xor $bNeg); + break; + + // @codeCoverageIgnoreStart + default: + throw new \InvalidArgumentException('Invalid bitwise operator.'); + // @codeCoverageIgnoreEnd + } + + if ($negative) { + $value = $this->twosComplement($value); + } + + $result = $this->toDecimal($value); + + return $negative ? $this->neg($result) : $result; + } + + /** + * @param string $number A positive, binary number. + * + * @return string + */ + private function twosComplement(string $number) : string + { + $xor = \str_repeat("\xff", \strlen($number)); + + $number ^= $xor; + + for ($i = \strlen($number) - 1; $i >= 0; $i--) { + $byte = \ord($number[$i]); + + if (++$byte !== 256) { + $number[$i] = \chr($byte); + break; + } + + $number[$i] = "\x00"; + + if ($i === 0) { + $number = "\x01" . $number; + } + } + + return $number; + } + + /** + * Converts a decimal number to a binary string. + * + * @param string $number The number to convert, positive or zero, only digits. + * + * @return string + */ + private function toBinary(string $number) : string + { + $result = ''; + + while ($number !== '0') { + [$number, $remainder] = $this->divQR($number, '256'); + $result .= \chr((int) $remainder); + } + + return \strrev($result); + } + + /** + * Returns the positive decimal representation of a binary number. + * + * @param string $bytes The bytes representing the number. + * + * @return string + */ + private function toDecimal(string $bytes) : string + { + $result = '0'; + $power = '1'; + + for ($i = \strlen($bytes) - 1; $i >= 0; $i--) { + $index = \ord($bytes[$i]); + + if ($index !== 0) { + $result = $this->add($result, ($index === 1) + ? $power + : $this->mul($power, (string) $index) + ); + } + + if ($i !== 0) { + $power = $this->mul($power, '256'); + } + } + + return $result; + } +} diff --git a/transfer-protocol/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php b/transfer-protocol/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php new file mode 100644 index 0000000..6632b37 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php @@ -0,0 +1,116 @@ += 0) { + return \bcmod($a, $b, 0); + } + + return \bcmod($a, $b); + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + $q = \bcdiv($a, $b, 0); + + if (version_compare(PHP_VERSION, '7.2') >= 0) { + $r = \bcmod($a, $b, 0); + } else { + $r = \bcmod($a, $b); + } + + assert($q !== null); + assert($r !== null); + + return [$q, $r]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + return \bcpow($a, (string) $e, 0); + } + + /** + * {@inheritdoc} + * + * @psalm-suppress InvalidNullableReturnType + * @psalm-suppress NullableReturnStatement + */ + public function modPow(string $base, string $exp, string $mod) : string + { + return \bcpowmod($base, $exp, $mod, 0); + } + + /** + * {@inheritDoc} + * + * @psalm-suppress NullableReturnStatement + * @psalm-suppress InvalidNullableReturnType + */ + public function sqrt(string $n) : string + { + return \bcsqrt($n, 0); + } +} diff --git a/transfer-protocol/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php b/transfer-protocol/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php new file mode 100644 index 0000000..52d1880 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php @@ -0,0 +1,156 @@ +maxDigits = 9; + break; + + case 8: + $this->maxDigits = 18; + break; + + default: + throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.'); + } + } + + /** + * {@inheritdoc} + */ + public function add(string $a, string $b) : string + { + /** + * @psalm-var numeric-string $a + * @psalm-var numeric-string $b + */ + $result = $a + $b; + + if (is_int($result)) { + return (string) $result; + } + + if ($a === '0') { + return $b; + } + + if ($b === '0') { + return $a; + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $result = $aNeg === $bNeg ? $this->doAdd($aDig, $bDig) : $this->doSub($aDig, $bDig); + + if ($aNeg) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function sub(string $a, string $b) : string + { + return $this->add($a, $this->neg($b)); + } + + /** + * {@inheritdoc} + */ + public function mul(string $a, string $b) : string + { + /** + * @psalm-var numeric-string $a + * @psalm-var numeric-string $b + */ + $result = $a * $b; + + if (is_int($result)) { + return (string) $result; + } + + if ($a === '0' || $b === '0') { + return '0'; + } + + if ($a === '1') { + return $b; + } + + if ($b === '1') { + return $a; + } + + if ($a === '-1') { + return $this->neg($b); + } + + if ($b === '-1') { + return $this->neg($a); + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + $result = $this->doMul($aDig, $bDig); + + if ($aNeg !== $bNeg) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function divQ(string $a, string $b) : string + { + return $this->divQR($a, $b)[0]; + } + + /** + * {@inheritdoc} + */ + public function divR(string $a, string $b): string + { + return $this->divQR($a, $b)[1]; + } + + /** + * {@inheritdoc} + */ + public function divQR(string $a, string $b) : array + { + if ($a === '0') { + return ['0', '0']; + } + + if ($a === $b) { + return ['1', '0']; + } + + if ($b === '1') { + return [$a, '0']; + } + + if ($b === '-1') { + return [$this->neg($a), '0']; + } + + /** @psalm-var numeric-string $a */ + $na = $a * 1; // cast to number + + if (is_int($na)) { + /** @psalm-var numeric-string $b */ + $nb = $b * 1; + + if (is_int($nb)) { + // the only division that may overflow is PHP_INT_MIN / -1, + // which cannot happen here as we've already handled a divisor of -1 above. + $r = $na % $nb; + $q = ($na - $r) / $nb; + + assert(is_int($q)); + + return [ + (string) $q, + (string) $r + ]; + } + } + + [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b); + + [$q, $r] = $this->doDiv($aDig, $bDig); + + if ($aNeg !== $bNeg) { + $q = $this->neg($q); + } + + if ($aNeg) { + $r = $this->neg($r); + } + + return [$q, $r]; + } + + /** + * {@inheritdoc} + */ + public function pow(string $a, int $e) : string + { + if ($e === 0) { + return '1'; + } + + if ($e === 1) { + return $a; + } + + $odd = $e % 2; + $e -= $odd; + + $aa = $this->mul($a, $a); + + /** @psalm-suppress PossiblyInvalidArgument We're sure that $e / 2 is an int now */ + $result = $this->pow($aa, $e / 2); + + if ($odd === 1) { + $result = $this->mul($result, $a); + } + + return $result; + } + + /** + * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/ + * + * {@inheritdoc} + */ + public function modPow(string $base, string $exp, string $mod) : string + { + // special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0) + if ($base === '0' && $exp === '0' && $mod === '1') { + return '0'; + } + + // special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0) + if ($exp === '0' && $mod === '1') { + return '0'; + } + + $x = $base; + + $res = '1'; + + // numbers are positive, so we can use remainder instead of modulo + $x = $this->divR($x, $mod); + + while ($exp !== '0') { + if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd + $res = $this->divR($this->mul($res, $x), $mod); + } + + $exp = $this->divQ($exp, '2'); + $x = $this->divR($this->mul($x, $x), $mod); + } + + return $res; + } + + /** + * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html + * + * {@inheritDoc} + */ + public function sqrt(string $n) : string + { + if ($n === '0') { + return '0'; + } + + // initial approximation + $x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1); + + $decreased = false; + + for (;;) { + $nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2'); + + if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) { + break; + } + + $decreased = $this->cmp($nx, $x) < 0; + $x = $nx; + } + + return $x; + } + + /** + * Performs the addition of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doAdd(string $a, string $b) : string + { + [$a, $b, $length] = $this->pad($a, $b); + + $carry = 0; + $result = ''; + + for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { + $blockLength = $this->maxDigits; + + if ($i < 0) { + $blockLength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + /** @psalm-var numeric-string $blockA */ + $blockA = \substr($a, $i, $blockLength); + + /** @psalm-var numeric-string $blockB */ + $blockB = \substr($b, $i, $blockLength); + + $sum = (string) ($blockA + $blockB + $carry); + $sumLength = \strlen($sum); + + if ($sumLength > $blockLength) { + $sum = \substr($sum, 1); + $carry = 1; + } else { + if ($sumLength < $blockLength) { + $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; + } + $carry = 0; + } + + $result = $sum . $result; + + if ($i === 0) { + break; + } + } + + if ($carry === 1) { + $result = '1' . $result; + } + + return $result; + } + + /** + * Performs the subtraction of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doSub(string $a, string $b) : string + { + if ($a === $b) { + return '0'; + } + + // Ensure that we always subtract to a positive result: biggest minus smallest. + $cmp = $this->doCmp($a, $b); + + $invert = ($cmp === -1); + + if ($invert) { + $c = $a; + $a = $b; + $b = $c; + } + + [$a, $b, $length] = $this->pad($a, $b); + + $carry = 0; + $result = ''; + + $complement = 10 ** $this->maxDigits; + + for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) { + $blockLength = $this->maxDigits; + + if ($i < 0) { + $blockLength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + /** @psalm-var numeric-string $blockA */ + $blockA = \substr($a, $i, $blockLength); + + /** @psalm-var numeric-string $blockB */ + $blockB = \substr($b, $i, $blockLength); + + $sum = $blockA - $blockB - $carry; + + if ($sum < 0) { + $sum += $complement; + $carry = 1; + } else { + $carry = 0; + } + + $sum = (string) $sum; + $sumLength = \strlen($sum); + + if ($sumLength < $blockLength) { + $sum = \str_repeat('0', $blockLength - $sumLength) . $sum; + } + + $result = $sum . $result; + + if ($i === 0) { + break; + } + } + + // Carry cannot be 1 when the loop ends, as a > b + assert($carry === 0); + + $result = \ltrim($result, '0'); + + if ($invert) { + $result = $this->neg($result); + } + + return $result; + } + + /** + * Performs the multiplication of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string + */ + private function doMul(string $a, string $b) : string + { + $x = \strlen($a); + $y = \strlen($b); + + $maxDigits = \intdiv($this->maxDigits, 2); + $complement = 10 ** $maxDigits; + + $result = '0'; + + for ($i = $x - $maxDigits;; $i -= $maxDigits) { + $blockALength = $maxDigits; + + if ($i < 0) { + $blockALength += $i; + /** @psalm-suppress LoopInvalidation */ + $i = 0; + } + + $blockA = (int) \substr($a, $i, $blockALength); + + $line = ''; + $carry = 0; + + for ($j = $y - $maxDigits;; $j -= $maxDigits) { + $blockBLength = $maxDigits; + + if ($j < 0) { + $blockBLength += $j; + /** @psalm-suppress LoopInvalidation */ + $j = 0; + } + + $blockB = (int) \substr($b, $j, $blockBLength); + + $mul = $blockA * $blockB + $carry; + $value = $mul % $complement; + $carry = ($mul - $value) / $complement; + + $value = (string) $value; + $value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT); + + $line = $value . $line; + + if ($j === 0) { + break; + } + } + + if ($carry !== 0) { + $line = $carry . $line; + } + + $line = \ltrim($line, '0'); + + if ($line !== '') { + $line .= \str_repeat('0', $x - $blockALength - $i); + $result = $this->add($result, $line); + } + + if ($i === 0) { + break; + } + } + + return $result; + } + + /** + * Performs the division of two non-signed large integers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return string[] The quotient and remainder. + */ + private function doDiv(string $a, string $b) : array + { + $cmp = $this->doCmp($a, $b); + + if ($cmp === -1) { + return ['0', $a]; + } + + $x = \strlen($a); + $y = \strlen($b); + + // we now know that a >= b && x >= y + + $q = '0'; // quotient + $r = $a; // remainder + $z = $y; // focus length, always $y or $y+1 + + for (;;) { + $focus = \substr($a, 0, $z); + + $cmp = $this->doCmp($focus, $b); + + if ($cmp === -1) { + if ($z === $x) { // remainder < dividend + break; + } + + $z++; + } + + $zeros = \str_repeat('0', $x - $z); + + $q = $this->add($q, '1' . $zeros); + $a = $this->sub($a, $b . $zeros); + + $r = $a; + + if ($r === '0') { // remainder == 0 + break; + } + + $x = \strlen($a); + + if ($x < $y) { // remainder < dividend + break; + } + + $z = $y; + } + + return [$q, $r]; + } + + /** + * Compares two non-signed large numbers. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return int [-1, 0, 1] + */ + private function doCmp(string $a, string $b) : int + { + $x = \strlen($a); + $y = \strlen($b); + + $cmp = $x <=> $y; + + if ($cmp !== 0) { + return $cmp; + } + + return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1] + } + + /** + * Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length. + * + * The numbers must only consist of digits, without leading minus sign. + * + * @param string $a The first operand. + * @param string $b The second operand. + * + * @return array{string, string, int} + */ + private function pad(string $a, string $b) : array + { + $x = \strlen($a); + $y = \strlen($b); + + if ($x > $y) { + $b = \str_repeat('0', $x - $y) . $b; + + return [$a, $b, $x]; + } + + if ($x < $y) { + $a = \str_repeat('0', $y - $x) . $a; + + return [$a, $b, $y]; + } + + return [$a, $b, $x]; + } +} diff --git a/transfer-protocol/vendor/brick/math/src/RoundingMode.php b/transfer-protocol/vendor/brick/math/src/RoundingMode.php new file mode 100644 index 0000000..06936d8 --- /dev/null +++ b/transfer-protocol/vendor/brick/math/src/RoundingMode.php @@ -0,0 +1,107 @@ += 0.5; otherwise, behaves as for DOWN. + * Note that this is the rounding mode commonly taught at school. + */ + public const HALF_UP = 5; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down. + * + * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN. + */ + public const HALF_DOWN = 6; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity. + * + * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN. + */ + public const HALF_CEILING = 7; + + /** + * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity. + * + * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP. + */ + public const HALF_FLOOR = 8; + + /** + * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor. + * + * Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd; + * behaves as for HALF_DOWN if it's even. + * + * Note that this is the rounding mode that statistically minimizes + * cumulative error when applied repeatedly over a sequence of calculations. + * It is sometimes known as "Banker's rounding", and is chiefly used in the USA. + */ + public const HALF_EVEN = 9; +} diff --git a/transfer-protocol/vendor/composer/ClassLoader.php b/transfer-protocol/vendor/composer/ClassLoader.php new file mode 100644 index 0000000..afef3fa --- /dev/null +++ b/transfer-protocol/vendor/composer/ClassLoader.php @@ -0,0 +1,572 @@ + + * 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; +} diff --git a/transfer-protocol/vendor/composer/InstalledVersions.php b/transfer-protocol/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..c6b54af --- /dev/null +++ b/transfer-protocol/vendor/composer/InstalledVersions.php @@ -0,0 +1,352 @@ + + * 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; + } +} diff --git a/transfer-protocol/vendor/composer/LICENSE b/transfer-protocol/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/transfer-protocol/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +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. + diff --git a/transfer-protocol/vendor/composer/autoload_classmap.php b/transfer-protocol/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..9bb846c --- /dev/null +++ b/transfer-protocol/vendor/composer/autoload_classmap.php @@ -0,0 +1,11 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', +); diff --git a/transfer-protocol/vendor/composer/autoload_files.php b/transfer-protocol/vendor/composer/autoload_files.php new file mode 100644 index 0000000..f122ba0 --- /dev/null +++ b/transfer-protocol/vendor/composer/autoload_files.php @@ -0,0 +1,10 @@ + $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', +); diff --git a/transfer-protocol/vendor/composer/autoload_namespaces.php b/transfer-protocol/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..15a2ff3 --- /dev/null +++ b/transfer-protocol/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/src'), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => array($vendorDir . '/symfony/polyfill-intl-normalizer'), + 'Rowbot\\URL\\' => array($vendorDir . '/rowbot/url/src'), + 'Rowbot\\Punycode\\' => array($vendorDir . '/rowbot/punycode/src'), + 'Rowbot\\Idna\\Resource\\' => array($vendorDir . '/rowbot/idna/resources'), + 'Rowbot\\Idna\\' => array($vendorDir . '/rowbot/idna/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), + 'Brick\\Math\\' => array($vendorDir . '/brick/math/src'), +); diff --git a/transfer-protocol/vendor/composer/autoload_real.php b/transfer-protocol/vendor/composer/autoload_real.php new file mode 100644 index 0000000..cd98ff9 --- /dev/null +++ b/transfer-protocol/vendor/composer/autoload_real.php @@ -0,0 +1,57 @@ +register(true); + + $includeFiles = \Composer\Autoload\ComposerStaticInit82edd3a9af4afbf739dd8113cfd69f11::$files; + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire82edd3a9af4afbf739dd8113cfd69f11($fileIdentifier, $file); + } + + return $loader; + } +} + +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ +function composerRequire82edd3a9af4afbf739dd8113cfd69f11($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } +} diff --git a/transfer-protocol/vendor/composer/autoload_static.php b/transfer-protocol/vendor/composer/autoload_static.php new file mode 100644 index 0000000..56aed4e --- /dev/null +++ b/transfer-protocol/vendor/composer/autoload_static.php @@ -0,0 +1,88 @@ + __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'W' => + array ( + 'Wordpress\\TransferProtocol\\' => 27, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => 33, + ), + 'R' => + array ( + 'Rowbot\\URL\\' => 11, + 'Rowbot\\Punycode\\' => 16, + 'Rowbot\\Idna\\Resource\\' => 21, + 'Rowbot\\Idna\\' => 12, + ), + 'P' => + array ( + 'Psr\\Log\\' => 8, + ), + 'B' => + array ( + 'Brick\\Math\\' => 11, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Wordpress\\TransferProtocol\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + 'Symfony\\Polyfill\\Intl\\Normalizer\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer', + ), + 'Rowbot\\URL\\' => + array ( + 0 => __DIR__ . '/..' . '/rowbot/url/src', + ), + 'Rowbot\\Punycode\\' => + array ( + 0 => __DIR__ . '/..' . '/rowbot/punycode/src', + ), + 'Rowbot\\Idna\\Resource\\' => + array ( + 0 => __DIR__ . '/..' . '/rowbot/idna/resources', + ), + 'Rowbot\\Idna\\' => + array ( + 0 => __DIR__ . '/..' . '/rowbot/idna/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/src', + ), + 'Brick\\Math\\' => + array ( + 0 => __DIR__ . '/..' . '/brick/math/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit82edd3a9af4afbf739dd8113cfd69f11::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit82edd3a9af4afbf739dd8113cfd69f11::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit82edd3a9af4afbf739dd8113cfd69f11::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/transfer-protocol/vendor/composer/installed.json b/transfer-protocol/vendor/composer/installed.json new file mode 100644 index 0000000..78f3a97 --- /dev/null +++ b/transfer-protocol/vendor/composer/installed.json @@ -0,0 +1,393 @@ +{ + "packages": [ + { + "name": "brick/math", + "version": "0.9.3", + "version_normalized": "0.9.3.0", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.9.2" + }, + "time": "2021-08-15T20:50:18+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.3" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" + } + ], + "install-path": "../brick/math" + }, + { + "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": "rowbot/idna", + "version": "0.1.5", + "version_normalized": "0.1.5.0", + "source": { + "type": "git", + "url": "https://github.com/TRowbotham/idna.git", + "reference": "02d94e4caa435547d2027086c57c69d34e6ed4fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TRowbotham/idna/zipball/02d94e4caa435547d2027086c57c69d34e6ed4fa", + "reference": "02d94e4caa435547d2027086c57c69d34e6ed4fa", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "rowbot/punycode": "^1.0", + "symfony/polyfill-intl-normalizer": "^1.18" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.5 || ^7.0", + "phpstan/phpstan": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.5.1", + "symfony/cache": "^4.3 || ^5.0" + }, + "time": "2022-01-10T19:51:24+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Rowbot\\Idna\\": "src/", + "Rowbot\\Idna\\Resource\\": "resources/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Trevor Rowbotham" + } + ], + "description": "An implementation of UTS#46 Unicode IDNA Compatibility Processing.", + "keywords": [ + "idn", + "idna", + "international domain names", + "iri", + "tr46", + "unicode", + "uts46" + ], + "support": { + "issues": "https://github.com/TRowbotham/idna/issues", + "source": "https://github.com/TRowbotham/idna/tree/0.1.5" + }, + "install-path": "../rowbot/idna" + }, + { + "name": "rowbot/punycode", + "version": "1.0.4", + "version_normalized": "1.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/TRowbotham/punycode.git", + "reference": "ec116e99cb089a25d45147813d61bfa2deb29328" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TRowbotham/punycode/zipball/ec116e99cb089a25d45147813d61bfa2deb29328", + "reference": "ec116e99cb089a25d45147813d61bfa2deb29328", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "ext-mbstring": "*", + "phpstan/phpstan": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.5.1" + }, + "time": "2024-05-03T00:56:10+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Rowbot\\Punycode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Trevor Rowbotham", + "homepage": "https://trowbotham.com", + "role": "Developer" + } + ], + "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA).", + "keywords": [ + "punycode", + "rfc-3492", + "rfc3492" + ], + "support": { + "issues": "https://github.com/TRowbotham/punycode/issues", + "source": "https://github.com/TRowbotham/punycode/tree/1.0.4" + }, + "install-path": "../rowbot/punycode" + }, + { + "name": "rowbot/url", + "version": "4.0.0", + "version_normalized": "4.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/TRowbotham/URL-Parser.git", + "reference": "b81e4b4f55ba4fdefaaedebf22d5a060080809f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TRowbotham/URL-Parser/zipball/b81e4b4f55ba4fdefaaedebf22d5a060080809f4", + "reference": "b81e4b4f55ba4fdefaaedebf22d5a060080809f4", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.13 || ^0.9", + "ext-mbstring": "*", + "php": ">=8.1", + "psr/log": "^3.0", + "rowbot/idna": "^0.1.5" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.0", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^10.0 || ^11.0", + "slevomat/coding-standard": "^8.0", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/cache": "^5.0 || ^6.0" + }, + "time": "2024-06-21T01:00:47+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Rowbot\\URL\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Trevor Rowbotham", + "homepage": "https://trowbotham.com", + "role": "Developer" + } + ], + "description": "A WHATWG URL spec compliant URL parser for working with URLs and their query strings.", + "keywords": [ + "WHATWG", + "query-string", + "querystring", + "uri", + "url", + "url-parser", + "url-parsing" + ], + "support": { + "issues": "https://github.com/TRowbotham/URL-Parser/issues", + "source": "https://github.com/TRowbotham/URL-Parser/tree/4.0.0" + }, + "install-path": "../rowbot/url" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.30.0", + "version_normalized": "1.30.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-05-31T15:07:36+00:00", + "type": "library", + "extra": { + "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.30.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" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/transfer-protocol/vendor/composer/installed.php b/transfer-protocol/vendor/composer/installed.php new file mode 100644 index 0000000..def5464 --- /dev/null +++ b/transfer-protocol/vendor/composer/installed.php @@ -0,0 +1,77 @@ + array( + 'name' => 'wordpress/transfer-protocol', + 'pretty_version' => 'dev-trunk', + 'version' => 'dev-trunk', + 'reference' => 'd9cd270d5abf0741f8773bc01010cff1d558d79e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'brick/math' => array( + 'pretty_version' => '0.9.3', + 'version' => '0.9.3.0', + 'reference' => 'ca57d18f028f84f777b2168cd1911b0dee2343ae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../brick/math', + 'aliases' => array(), + 'dev_requirement' => false, + ), + '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, + ), + 'rowbot/idna' => array( + 'pretty_version' => '0.1.5', + 'version' => '0.1.5.0', + 'reference' => '02d94e4caa435547d2027086c57c69d34e6ed4fa', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rowbot/idna', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rowbot/punycode' => array( + 'pretty_version' => '1.0.4', + 'version' => '1.0.4.0', + 'reference' => 'ec116e99cb089a25d45147813d61bfa2deb29328', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rowbot/punycode', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rowbot/url' => array( + 'pretty_version' => '4.0.0', + 'version' => '4.0.0.0', + 'reference' => 'b81e4b4f55ba4fdefaaedebf22d5a060080809f4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../rowbot/url', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-intl-normalizer' => array( + 'pretty_version' => 'v1.30.0', + 'version' => '1.30.0.0', + 'reference' => 'a95281b0be0d9ab48050ebd988b967875cdb9fdb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'wordpress/transfer-protocol' => array( + 'pretty_version' => 'dev-trunk', + 'version' => 'dev-trunk', + 'reference' => 'd9cd270d5abf0741f8773bc01010cff1d558d79e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/transfer-protocol/vendor/composer/platform_check.php b/transfer-protocol/vendor/composer/platform_check.php new file mode 100644 index 0000000..4c3a5d6 --- /dev/null +++ b/transfer-protocol/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 80100)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.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 + ); +} diff --git a/transfer-protocol/vendor/psr/log/LICENSE b/transfer-protocol/vendor/psr/log/LICENSE new file mode 100644 index 0000000..474c952 --- /dev/null +++ b/transfer-protocol/vendor/psr/log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/transfer-protocol/vendor/psr/log/README.md b/transfer-protocol/vendor/psr/log/README.md new file mode 100644 index 0000000..a9f20c4 --- /dev/null +++ b/transfer-protocol/vendor/psr/log/README.md @@ -0,0 +1,58 @@ +PSR Log +======= + +This repository holds all interfaces/classes/traits related to +[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). + +Note that this is not a logger of its own. It is merely an interface that +describes a logger. See the specification for more details. + +Installation +------------ + +```bash +composer require psr/log +``` + +Usage +----- + +If you need a logger, you can use the interface like this: + +```php +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/transfer-protocol/vendor/psr/log/composer.json b/transfer-protocol/vendor/psr/log/composer.json new file mode 100644 index 0000000..879fc6f --- /dev/null +++ b/transfer-protocol/vendor/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + } +} diff --git a/transfer-protocol/vendor/psr/log/src/AbstractLogger.php b/transfer-protocol/vendor/psr/log/src/AbstractLogger.php new file mode 100644 index 0000000..d60a091 --- /dev/null +++ b/transfer-protocol/vendor/psr/log/src/AbstractLogger.php @@ -0,0 +1,15 @@ +logger = $logger; + } +} diff --git a/transfer-protocol/vendor/psr/log/src/LoggerInterface.php b/transfer-protocol/vendor/psr/log/src/LoggerInterface.php new file mode 100644 index 0000000..b3a24b5 --- /dev/null +++ b/transfer-protocol/vendor/psr/log/src/LoggerInterface.php @@ -0,0 +1,125 @@ +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; +} diff --git a/transfer-protocol/vendor/psr/log/src/NullLogger.php b/transfer-protocol/vendor/psr/log/src/NullLogger.php new file mode 100644 index 0000000..c1cc3c0 --- /dev/null +++ b/transfer-protocol/vendor/psr/log/src/NullLogger.php @@ -0,0 +1,30 @@ +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 + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/.gitattributes b/transfer-protocol/vendor/rowbot/idna/.gitattributes new file mode 100755 index 0000000..dfe0770 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/transfer-protocol/vendor/rowbot/idna/.github/workflows/tests.yml b/transfer-protocol/vendor/rowbot/idna/.github/workflows/tests.yml new file mode 100644 index 0000000..9238c1d --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/.github/workflows/tests.yml @@ -0,0 +1,272 @@ +name: Tests + +on: + pull_request: + push: + paths-ignore: + - "**.md" + +jobs: + tests: + name: Tests without intl + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - 7.1 + - 7.2 + - 7.3 + - 7.4 + - 8.0 + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: :intl + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Cache test data + uses: actions/cache@v2 + env: + test-data-files: tests/data/unicode-idna-test-data + with: + path: ${{ env.test-data-files }} + key: unicode-test-data-${{ hashFiles(env.test-data-files) }} + restore-keys: unicode-test-data- + + - name: Install dependencies + run: composer install + + - name: Run PHPStan + run: vendor/bin/phpstan analyse + + - name: Run PHPCS + run: vendor/bin/phpcs + + - name: Tests + run: vendor/bin/phpunit + + tests-intl: + name: Tests with intl + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - 7.1 + - 7.2 + - 7.3 + - 7.4 + - 8.0 + - 8.1 + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: intl + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Cache test data + uses: actions/cache@v2 + env: + test-data-files: tests/data/unicode-idna-test-data + with: + path: ${{ env.test-data-files }} + key: unicode-test-data-${{ hashFiles(env.test-data-files) }} + restore-keys: unicode-test-data- + + - name: Install dependencies + run: composer install + + - name: Run PHPStan + run: vendor/bin/phpstan analyse + + - name: Run PHPCS + run: vendor/bin/phpcs + + - name: Tests + run: vendor/bin/phpunit + + tests-unstable: + name: Test Unstable + runs-on: ${{ matrix.operating-system }} + continue-on-error: true + + strategy: + fail-fast: false + matrix: + php-version: + - nightly + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: :intl + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Cache test data + uses: actions/cache@v2 + env: + test-data-files: tests/data/unicode-idna-test-data + with: + path: ${{ env.test-data-files }} + key: unicode-test-data-${{ hashFiles(env.test-data-files) }} + restore-keys: unicode-test-data- + + - name: Install dependencies + run: composer install --ignore-platform-reqs + + - name: Tests + run: vendor/bin/phpunit + + tests-code-coverage: + name: Code Coverage + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: :intl + coverage: pcov + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Cache test data + uses: actions/cache@v2 + env: + test-data-files: tests/data/unicode-idna-test-data + with: + path: ${{ env.test-data-files }} + key: unicode-test-data-${{ hashFiles(env.test-data-files) }} + restore-keys: unicode-test-data- + + - name: Install dependencies + run: composer install + + - name: Tests with code coverage + run: | + mkdir -p ./build/coverage/ + vendor/bin/phpunit --coverage-clover ./build/coverage/clover.xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./build/coverage/clover.xml + + tests-jit: + name: Test JIT + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - 8.0 + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: none + extensions: :intl + ini-values: opcache.enable_cli=1, opcache.jit=1255, opcache.jit_buffer_size=64M + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Cache test data + uses: actions/cache@v2 + env: + test-data-files: tests/data/unicode-idna-test-data + with: + path: ${{ env.test-data-files }} + key: unicode-test-data-${{ hashFiles(env.test-data-files) }} + restore-keys: unicode-test-data- + + - name: Install dependencies + run: composer install + + - name: Tests + run: vendor/bin/phpunit diff --git a/transfer-protocol/vendor/rowbot/idna/.gitignore b/transfer-protocol/vendor/rowbot/idna/.gitignore new file mode 100755 index 0000000..da38513 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/.gitignore @@ -0,0 +1,7 @@ +composer.phar +composer.lock +/vendor/ +/.vscode/ +/build/ +/tests/data/ +.phpunit.result.cache diff --git a/transfer-protocol/vendor/rowbot/idna/.phpcs.xml b/transfer-protocol/vendor/rowbot/idna/.phpcs.xml new file mode 100644 index 0000000..8a8c927 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/.phpcs.xml @@ -0,0 +1,14 @@ + + + src + */tests/* + */data/* + */Data/* + */build/* + src/Regex.php + + + + + + diff --git a/transfer-protocol/vendor/rowbot/idna/CHANGELOG.md b/transfer-protocol/vendor/rowbot/idna/CHANGELOG.md new file mode 100644 index 0000000..5bef769 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/CHANGELOG.md @@ -0,0 +1,47 @@ +# Changelog + +## [Unreleased] + +## [0.1.5] - 2022-01-10 + +### Added + +* Add `UNICODE_VERSION` constant to `Idna` class that returns a string with the Unicode version of the data files used + +### Changed + +* Update data files to Unicode 14 +* Update PHPStan to 1.0 + +## [0.1.4] - 2021-02-11 + +### Added + +* Test on PHP 8 release + +### Fixed + +* Handle the rare possibility that string nomalization can fail + +## [0.1.3] - 2020-08-03 + +### Fixed + +* Fix bug with domain names containing a URL delimiter + +## [0.1.2] - 2020-07-15 + +### Added + +* Performance improvements + +## [0.1.1] - 2020-07-10 + +### Added + +* Performance improvements +* Reduced memory footprint + +## [0.1.0] - 2020-06-10 + +* Initial release diff --git a/transfer-protocol/vendor/rowbot/idna/LICENSE b/transfer-protocol/vendor/rowbot/idna/LICENSE new file mode 100755 index 0000000..06a800e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Trevor Rowbotham + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/transfer-protocol/vendor/rowbot/idna/README.md b/transfer-protocol/vendor/rowbot/idna/README.md new file mode 100644 index 0000000..995225b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/README.md @@ -0,0 +1,347 @@ +# IDNA + +[![License](https://img.shields.io/github/license/TRowbotham/idna?style=flat-square)](https://github.com/TRowbotham/URL-Parser/blob/master/LICENSE) +[![Build Status](https://img.shields.io/travis/com/TRowbotham/idna/master?style=flat-square)](https://travis-ci.com/github/TRowbotham/idna) +[![Code Coverage](https://img.shields.io/codecov/c/github/TRowbotham/idna/master?style=flat-square)](https://codecov.io/gh/TRowbotham/idna) +[![Version](https://img.shields.io/packagist/v/rowbot/idna?style=flat-square)](https://packagist.org/packages/rowbot/idna) +[![Downloads](https://img.shields.io/packagist/dt/rowbot/idna?style=flat-square)](https://packagist.org/packages/rowbot/idna) + +A fully compliant implementation of [UTS#46](https://www.unicode.org/reports/tr46/), otherwise known +as Unicode IDNA Compatibility Processing. You can read more about the differences between IDNA2003, +IDNA2008, and UTS#46 in [Section 7. IDNA Comparison](https://www.unicode.org/reports/tr46/#IDNAComparison) +of the specification. + +This library currently ships with Unicode 14.0.0 support and implements Version 14.0.0, Revision 27 of IDNA Compatibility +Processing. It has the ability to use Unicode 11.0.0 to Unicode 14.0.0. While this library likely supports versions of +Unicode less than 11.0.0, the format of the Unicode test files were changed beginning in 11.0.0 and as a result, versions +of Unicode less than 11.0.0 have not been tested. + +* [Requirements](#requirements) +* [Installation](#installation) +* [API](#api) +* [Error Codes](#error-codes) +* [The WTFs of Unicode Support in PHP](#the-wtfs-of-unicode-support-in-php) +* [FAQs](#faqs) +* [Internals](#internals) + +## Requirements + +* PHP 7.1+ +* `rowbot/punycode` +* `symfony/polyfill-intl-normalizer` + +## Installation + +```bash +composer require rowbot/idna +``` + +## API + +### Idna::UNICODE_VERSION + +The Unicode version of the data files used, as a string. + +### Idna::toAscii(string $domain, array $options = []): IdnaResult + +Converts a domain name to its ASCII form. Anytime an error is recorded while doing an ASCII +transformation, the transformation is considered to have failed and whatever domain name string is +returned is considered "garbage". What you do with that result is entirely up to you. + +#### toAscii Parameters + +* $domain - A domain name to convert to ASCII. +* $options - An array of options for customizing the behavior of the transformation. Possible +options include: + * `"CheckBidi"` - Checks the domain name string for errors with bi-directional characters. + Defaults to true. + * `"CheckHyphens"` - Checks the domain name string for the positioning of hypens. Defaults to + true. + * `"CheckJoiners"` - Checks the domain name string for errors with joining code points. Defaults + to true. + * `"UseSTD3ASCIIRules"` - Disallows the use of ASCII characters other than `[a-zA-Z0-9-]`. + Defaults to true. + * `"Transitional_Processing"` - Whether transitional or non-transitional processing is used. When + enabled, processing behaves more like IDNA2003 and when disabled behaves like IDNA2008. Defaults + to false, which means that non-transitional processing is used by default. + * `"VerifyDnsLength"` - Validates the length of the domain name string and it's individual labels. + Defaults to true. + + **Note**: All options are case-sensitive. + + ```php + use Rowbot\Idna\Idna; + + $result = Idna::toAscii('x-.xn--nxa'); + + // You must not use an ASCII domain that has errors. + if ($result->hasErrors()) { + throw new \Exception(); + } + + echo $result->getDomain(); // x-.xn--nxa + ``` + +### Idna::toUnicode(string $domain, array $options = []): IdnaResult + +Converts the domain name to its Unicode form. Unlike the toAscii transformation, toUnicode does not +have a failure concept. This means that you can always use the returned string. However, deciding +what to do with the returned domain name string when an error is recorded is entirely up to you. + +* $domain - A domain name to convert to UTF-8. +* $options - An array of options for customizing the behavior of the transformation. Possible +options include: + * `"CheckBidi"` - Checks the domain name string for errors with bi-directional characters. + Defaults to true. + * `"CheckHyphens"` - Checks the domain name string for the positioning of hypens. Defaults to + true. + * `"CheckJoiners"` - Checks the domain name string for errors with joining code points. Defaults + to true. + * `"UseSTD3ASCIIRules"` - Disallows the use of ASCII characters other than `[a-zA-Z0-9-]`. + Defaults to true. + * `"Transitional_Processing"` - Whether transitional or non-transitional processing is used. When + enabled, processing behaves more like IDNA2003 and when disabled behaves like IDNA2008. Defaults + to false, which means that non-transitional processing is used by default. + + **Note**: All options are case-sensitive. + + **Note**: `"VerifyDnsLength"` is not a valid option here. + + ```php + use Rowbot\Idna\Idna; + + $result = Idna::toUnicode('xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n.com'); + echo $result->getDomain(); // 安室奈美恵-with-super-monkeys.com + ``` + +### IdnaResult object + +#### Members + +##### IdnaResult::getDomain(): string + +Returns the transformed domain name string. + +##### IdnaResult::getErrors(): int + +Returns a bitmask representing all errors that were recorded while processing the input domain name +string. + +##### IdnaResult::hasError(int $error): bool + +Returns whether or not a specific error was recorded. + +##### IdnaResult::hasErrors(): bool + +Returns whether or not an error was recorded while processing the input domain name string. + +##### IdnaResult::isTransitionalDifferent(): bool + +Returns `true` if the input domain name contains a code point that has a status of `"deviation"`. +This status indicates that the code points are handled differently in IDNA2003 than they are in +IDNA2008. At the time of writing, there are only 4 code points that have this status. They are +U+00DF, U+03C2, U+200C, and U+200D. + +## Error Codes + +* `Idna::ERROR_EMPTY_LABEL` + + The domain name or one of it's labels are an empty string. + +* `Idna::ERROR_LABEL_TOO_LONG` + + One of the domain's labels exceeds 63 bytes. + +* `Idna::ERROR_DOMAIN_NAME_TOO_LONG` + + The length of the domain name exceeds 253 bytes. + +* `Idna::ERROR_LEADING_HYPHEN` + + One of the domain name's labels starts with a hyphen-minus character (-). + +* `Idna::ERROR_TRAILING_HYPHEN` + + One of the domain name's labels ends with a hyphen-minus character (-). + +* `Idna::ERROR_HYPHEN_3_4` + + One of the domain name's labels contains a hyphen-minus character in the 3rd and 4th position. + +* `Idna::ERROR_LEADING_COMBINING_MARK` + + One of the domain name's labels starts with a combining mark. + +* `Idna::ERROR_DISALLOWED` + + The domain name contains characters that are disallowed. + +* `Idna::ERROR_PUNYCODE` + + One of the domain name's labels starts with "xn--", but is not valid punycode. + +* `Idna::ERROR_LABEL_HAS_DOT` + + One of the domain name's labels contains a full stop character (.). + +* `Idna::ERROR_INVALID_ACE_LABEL` + + One of the domain name's labels is an invalid ACE label. + +* `Idna::ERROR_BIDI` + + The domain name does not meet the BiDi requirements for IDNA. + +* `Idna::ERROR_CONTEXTJ` + + One of the domain name's labels does not meet the CONTEXTJ requirements for IDNA. + +## The WTFs of Unicode Support in PHP + +In any given version of PHP, there can be a multitude of different versions of Unicode in use. +So... WTF? + +* What does this mean? + + This means that if I ask the same question, each of the extensions listed below can give me a + different answer. This is compounded by the fact that the versions of Unicode used in the below + extensions can also be different given the same version of PHP. For example, the `intl` extension + being used by my installation of PHP 7.2 could be using Unicode version 11, but the `intl` + extension in your web hosts installation of PHP 7.2 could be using Unicode version 6. + +* How does this happen? + * The `mbstring` extension uses its own version of Unicode. + * The `Onigurama` library, which is behind `mbstring`'s regular expression functions, uses its + own version of Unicode. + * The `PCRE` extension, which is the primary extension for working with regular extensions in + PHP, uses its own version of Unicode. + * The `intl` extension uses its own version of Unicode. + * Any other extensions that add their own versions of Unicode. + * Userland libraries use their own version of Unicode (including this library). + +* This library + + Being able to use `mbstring` or `intl` extensions would be helpful, but we cannot depend on them + being installed or them having a consistent version of Unicode when they are installed. + Additionally, extensions like `PCRE` could be compiled without Unicode support entirely, though we + do rely on `PCRE`'s `u` modifier. For this reason we have to include our own Unicode data. + +## FAQs + +* **I'm confused! Is this IDNA2003 or IDNA2008?** + + The answer to this is somewhat convoluted. TL;DR; It is neither. + + Here is what the spec says: + + > To satisfy user expectations for mapping, and provide maximal compatibility with IDNA2003, this + > document specifies a mapping for use with IDNA2008. In addition, to transition more smoothly to + > IDNA2008, this document provides a Unicode algorithm for a standardized processing that allows + > conformant implementations to minimize the security and interoperability problems caused by the + > differences between IDNA2003 and IDNA2008. This Unicode IDNA Compatibility Processing is + > structured according to IDNA2003 principles, but extends those principles to Unicode 5.2 and + > later. It also incorporates the repertoire extensions provided by IDNA2008. + + More information can be found in [Section 2. Unicode IDNA Compatibility Processing](https://www.unicode.org/reports/tr46/#Compatibility_Processing) + and [Section 7. IDNA Comparison](https://www.unicode.org/reports/tr46/#IDNAComparison). + +* **What are the recommended options?** + + The default options are the recommended options, which are also the strictest. + + ```php + // Default options. + [ + 'CheckHyphens' => true, + 'CheckBidi' => true, + 'CheckJoiners' => true, + 'UseSTD3ASCIIRules' => true, + 'Transitional_Processing' => false, + 'VerifyDnsLength' => true, // Only for Idna::toAscii() + ]; + ``` + +* **Do I have to provide all the options?** + + No. You only need to specifiy the options that you wish to change. Any option you specify will + overwrite the default options. + + ```php + use Rowbot\Idna\Idna; + + $result = Idna::toAscii('x-.xn--nxa', ['CheckHyphens' => true]); + $result->hasErrors(); // true + $result->hasError(Idna::ERROR_TRAILING_HYPHEN); // true + + $result = Idna::toAscii('x-.xn--nxa', ['CheckHyphens' => false]); + $result->hasErrors(); // false + $result->hasError(Idna::ERROR_TRAILING_HYPHEN); // false + ``` + +* **What is the difference between `Transitional` and `Non-transitional` processing?** + + `Transitional` processing is designed to mimic IDNA2003. It is highly recommended to use + `Non-transitional` processing, which tries to mimic IDNA2008. You can always check if a domain + name would be different between the two processing modes by checking + `IdnaResult::isTransitionalDifferent()`. + +* **Wouldn't it be neat if you also tested against the `idn_to_ascii()` and `idn_to_utf8()` +functions from the `intl` extension?** + + Yes. Yes, it would be neat if we could do an additional check for parity with the ICU + implementation, however, for the reasons outlined above in + [The WTFs of Unicode Support in PHP](#the-wtfs-of-unicode-support-in-php), testing against these + functions would be unreliable at best. + +* **Why does the `intl` extension show weird characters that look like diamonds with question marks +inside in invalid domains, but your implementation doesn't?** + + ```php + $input = '憡?Ⴔ.XN--1UG73GL146A'; + + idn_to_utf8($input, 0, IDNA_INTL_VARIANT_UTS46, $info); + echo $info['result']; // 憡��.xn--1ug73gl146a� + echo ($info['errors'] & IDNA_ERROR_DISALLOWED) !== 0; // true + + $result = \Rowbot\Idna\Idna::toUnicode($input); + echo $result->getDomain(); // 憡?Ⴔ.xn--1ug73gl146a + echo $result->hasError(\Rowbot\Idna\Idna::ERROR_DISALLOWED); // true + ``` + + From [Section 4. Processing](https://www.unicode.org/reports/tr46/#Processing): + + > Implementations may make further modifications to the resulting Unicode string when showing it to + > the user. For example, it is recommended that disallowed characters be replaced by a U+FFFD to + > make them visible to the user. Similarly, labels that fail processing during steps 4 or 5 may be + > marked by the insertion of a U+FFFD or other visual device. + + This implementation currently does not make these recommended modifications. + +## Internals + +### Building + +Unicode data files are fetched from https://www.unicode.org/Public. Currently, Unicode version +11.0.0-14.0.0 are supported. To change the version of Unicode that the library is built with, you +must first change the value of the `\Rowbot\Idna::UNICODE_VERSION` constant, like so: + +```diff +class Idna +{ +- public const UNICODE_VERSION = '13.0.0'; ++ public const UNICODE_VERSION = '14.0.0'; +``` + +Then to generate the necessary data files, you execute the following command: + +```bash +php bin/generateDataFiles.php +``` + +If no assertions or exceptions have occured, then you have successfully changed the Unicode version. +You should now execute the tests to make sure everything is good to go. The tests will automatically +fetch the version appropriate tests as the test files are not generated by the above command. + +```bash +vendor/bin/phpunit +``` diff --git a/transfer-protocol/vendor/rowbot/idna/bin/Builder.php b/transfer-protocol/vendor/rowbot/idna/bin/Builder.php new file mode 100644 index 0000000..2de7da4 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/bin/Builder.php @@ -0,0 +1,90 @@ + + */ + protected static function parseCodePoints(string $codePoints): array + { + $range = explode('..', $codePoints); + $start = intval($range[0], 16); + $end = isset($range[1]) ? intval($range[1], 16) : $start; + + return [$start, $end]; + } + + /** + * @return array|string>> + */ + protected static function parseProperties(string $file): array + { + $handle = self::getUnicodeDataResource($file); + $retVal = []; + + while (($line = fgets($handle)) !== false) { + if ($line === "\n" || $line[0] === '#') { + continue; + } + + [$data] = explode('#', $line); + $data = array_map('trim', explode(';', $data)); + $data[0] = self::parseCodePoints($data[0]); + $retVal[] = $data; + } + + fclose($handle); + usort($retVal, static function (array $a, array $b): int { + return $a[0][0] <=> $b[0][0]; + }); + + return $retVal; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/bin/IdnaDataBuilder.php b/transfer-protocol/vendor/rowbot/idna/bin/IdnaDataBuilder.php new file mode 100755 index 0000000..a0fce8f --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/bin/IdnaDataBuilder.php @@ -0,0 +1,129 @@ + [], + 'ignored' => [], + 'deviation' => [], + 'disallowed' => [], + 'disallowed_STD3_mapped' => [], + 'disallowed_STD3_valid' => [], + ]; + $rangeFallback = ''; + + while (($line = fgets($handle)) !== false) { + if ($line === "\n" || $line[0] === '#') { + continue; + } + + [$data] = explode('#', $line); + $data = array_map('trim', explode(';', $data)); + [$codePoints, $status] = $data; + $codePoints = self::parseCodePoints($codePoints); + $diff = $codePoints[1] - $codePoints[0] + 1; + + switch ($status) { + case 'valid': + // skip valid. + break; + + case 'mapped': + case 'deviation': + case 'disallowed_STD3_mapped': + if (preg_match_all('/[[:xdigit:]]+/', $data[2], $matches) === false) { + throw new RuntimeException(); + } + + $mapped = ''; + + foreach ($matches[0] as $codePoint) { + $mapped .= CodePoint::encode(intval($codePoint, 16)); + } + + for ($i = 0; $i < $diff; ++$i) { + $statuses[$status][$codePoints[0] + $i] = $mapped; + } + + break; + + case 'disallowed': + if ($diff > 30) { + if ($rangeFallback !== '') { + $rangeFallback .= "\n\n"; + } + + $rangeFallback .= <<= {$codePoints[0]} && \$codePoint <= {$codePoints[1]}) { + return true; + } +RANGE_FALLBACK; + + continue 2; + } + + for ($i = 0; $i < $diff; ++$i) { + $statuses[$status][$codePoints[0] + $i] = true; + } + + break; + + case 'ignored': + case 'disallowed_STD3_valid': + for ($i = 0; $i < $diff; ++$i) { + $statuses[$status][$codePoints[0] + $i] = true; + } + + break; + } + } + + fclose($handle); + file_put_contents($output . DS . 'mapped.php', "|string>> $data + */ + private static function buildCharacterClass(array $data): string + { + $out = ''; + + foreach ($data as $codePoints) { + assert(is_array($codePoints[0])); + + if ($codePoints[0][0] !== $codePoints[0][1]) { + $out .= sprintf('\x{%04X}-\x{%04X}', ...$codePoints[0]); + + continue; + } + + $out .= sprintf('\x{%04X}', $codePoints[0][0]); + } + + return $out; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/bin/ViramaDataBuilder.php b/transfer-protocol/vendor/rowbot/idna/bin/ViramaDataBuilder.php new file mode 100644 index 0000000..56e4429 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/bin/ViramaDataBuilder.php @@ -0,0 +1,47 @@ +=7.1", + "rowbot/punycode": "^1.0", + "symfony/polyfill-intl-normalizer": "^1.18" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.5 || ^7.0", + "phpstan/phpstan": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.5.1", + "symfony/cache": "^4.3 || ^5.0" + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/phpstan.neon b/transfer-protocol/vendor/rowbot/idna/phpstan.neon new file mode 100644 index 0000000..cf61528 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/phpstan.neon @@ -0,0 +1,16 @@ +includes: + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon + +parameters: + level: max + paths: + - src + - bin + + ignoreErrors: + # This error can safely be ignored as we do these checks when building the data files. + - + message: "#Offset 'mapping' does not exist on array{status: string, mapping\\?: string}\\.#" + path: src/Idna.php + count: 2 diff --git a/transfer-protocol/vendor/rowbot/idna/phpunit.xml b/transfer-protocol/vendor/rowbot/idna/phpunit.xml new file mode 100644 index 0000000..51f55c9 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/phpunit.xml @@ -0,0 +1,23 @@ + + + + tests + + + + + src + + src/Resources + + + + diff --git a/transfer-protocol/vendor/rowbot/idna/resources/DisallowedRanges.php b/transfer-protocol/vendor/rowbot/idna/resources/DisallowedRanges.php new file mode 100644 index 0000000..5d64313 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/DisallowedRanges.php @@ -0,0 +1,361 @@ += 128 && $codePoint <= 159) { + 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 >= 6863 && $codePoint <= 6911) { + return true; + } + + if ($codePoint >= 11870 && $codePoint <= 11903) { + 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 >= 67005 && $codePoint <= 67071) { + return true; + } + + if ($codePoint >= 67515 && $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 >= 69514 && $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 >= 71495 && $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 <= 77711) { + return true; + } + + if ($codePoint >= 78905 && $codePoint <= 82943) { + return true; + } + + if ($codePoint >= 83527 && $codePoint <= 92159) { + 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 <= 110575) { + return true; + } + + if ($codePoint >= 110883 && $codePoint <= 110927) { + return true; + } + + if ($codePoint >= 111356 && $codePoint <= 113663) { + return true; + } + + if ($codePoint >= 113828 && $codePoint <= 118527) { + return true; + } + + if ($codePoint >= 118724 && $codePoint <= 118783) { + return true; + } + + if ($codePoint >= 119366 && $codePoint <= 119519) { + return true; + } + + if ($codePoint >= 119673 && $codePoint <= 119807) { + return true; + } + + if ($codePoint >= 121520 && $codePoint <= 122623) { + return true; + } + + if ($codePoint >= 122655 && $codePoint <= 122879) { + return true; + } + + if ($codePoint >= 122923 && $codePoint <= 123135) { + return true; + } + + if ($codePoint >= 123216 && $codePoint <= 123535) { + return true; + } + + if ($codePoint >= 123648 && $codePoint <= 124895) { + 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 >= 129995 && $codePoint <= 130031) { + return true; + } + + if ($codePoint >= 130042 && $codePoint <= 131069) { + return true; + } + + if ($codePoint >= 173792 && $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; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/resources/Regex.php b/transfer-protocol/vendor/rowbot/idna/resources/Regex.php new file mode 100644 index 0000000..bedfe6b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/Regex.php @@ -0,0 +1,32 @@ + 'ss', + 962 => 'σ', + 8204 => '', + 8205 => '', +); diff --git a/transfer-protocol/vendor/rowbot/idna/resources/disallowed.php b/transfer-protocol/vendor/rowbot/idna/resources/disallowed.php new file mode 100644 index 0000000..58bb2a2 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/disallowed.php @@ -0,0 +1,2715 @@ + 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, + 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, + 2155 => true, + 2156 => true, + 2157 => true, + 2158 => true, + 2159 => true, + 2191 => true, + 2192 => true, + 2193 => true, + 2194 => true, + 2195 => true, + 2196 => true, + 2197 => true, + 2198 => true, + 2199 => 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, + 3141 => true, + 3145 => true, + 3150 => true, + 3151 => true, + 3152 => true, + 3153 => true, + 3154 => true, + 3155 => true, + 3156 => true, + 3159 => true, + 3163 => true, + 3164 => 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, + 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, + 5910 => true, + 5911 => true, + 5912 => true, + 5913 => true, + 5914 => true, + 5915 => true, + 5916 => true, + 5917 => true, + 5918 => 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, + 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, + 6989 => true, + 6990 => true, + 6991 => 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, + 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, + 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, + 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, + 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, + 42955 => true, + 42956 => true, + 42957 => true, + 42958 => true, + 42959 => true, + 42962 => true, + 42964 => true, + 42970 => true, + 42971 => true, + 42972 => true, + 42973 => true, + 42974 => true, + 42975 => true, + 42976 => true, + 42977 => true, + 42978 => true, + 42979 => true, + 42980 => true, + 42981 => true, + 42982 => true, + 42983 => true, + 42984 => true, + 42985 => true, + 42986 => true, + 42987 => true, + 42988 => true, + 42989 => true, + 42990 => true, + 42991 => true, + 42992 => true, + 42993 => 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, + 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, + 64912 => true, + 64913 => true, + 64968 => true, + 64969 => true, + 64970 => true, + 64971 => true, + 64972 => true, + 64973 => true, + 64974 => 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, + 66939 => true, + 66955 => true, + 66963 => true, + 66966 => true, + 66978 => true, + 66994 => true, + 67002 => 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, + 67432 => true, + 67433 => true, + 67434 => true, + 67435 => true, + 67436 => true, + 67437 => true, + 67438 => true, + 67439 => true, + 67440 => true, + 67441 => true, + 67442 => true, + 67443 => true, + 67444 => true, + 67445 => true, + 67446 => true, + 67447 => true, + 67448 => true, + 67449 => true, + 67450 => true, + 67451 => true, + 67452 => true, + 67453 => true, + 67454 => true, + 67455 => true, + 67462 => true, + 67505 => 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, + 69466 => true, + 69467 => true, + 69468 => true, + 69469 => true, + 69470 => true, + 69471 => true, + 69472 => true, + 69473 => true, + 69474 => true, + 69475 => true, + 69476 => true, + 69477 => true, + 69478 => true, + 69479 => true, + 69480 => true, + 69481 => true, + 69482 => true, + 69483 => true, + 69484 => true, + 69485 => true, + 69486 => true, + 69487 => 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, + 69750 => true, + 69751 => true, + 69752 => true, + 69753 => true, + 69754 => true, + 69755 => true, + 69756 => true, + 69757 => true, + 69758 => true, + 69821 => 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, + 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, + 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, + 77811 => true, + 77812 => true, + 77813 => true, + 77814 => true, + 77815 => true, + 77816 => true, + 77817 => true, + 77818 => true, + 77819 => true, + 77820 => true, + 77821 => true, + 77822 => true, + 77823 => 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, + 92863 => true, + 92874 => true, + 92875 => true, + 92876 => true, + 92877 => true, + 92878 => true, + 92879 => 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, + 110580 => true, + 110588 => true, + 110591 => 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, + 118574 => true, + 118575 => true, + 118599 => true, + 118600 => true, + 118601 => true, + 118602 => true, + 118603 => true, + 118604 => true, + 118605 => true, + 118606 => true, + 118607 => 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, + 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, + 123567 => true, + 123568 => true, + 123569 => true, + 123570 => true, + 123571 => true, + 123572 => true, + 123573 => true, + 123574 => true, + 123575 => true, + 123576 => true, + 123577 => true, + 123578 => true, + 123579 => true, + 123580 => true, + 123581 => true, + 123582 => true, + 123583 => true, + 123642 => true, + 123643 => true, + 123644 => true, + 123645 => true, + 123646 => true, + 124903 => true, + 124908 => true, + 124911 => true, + 124927 => 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, + 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, + 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, + 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, + 129661 => true, + 129662 => true, + 129663 => true, + 129671 => true, + 129672 => true, + 129673 => true, + 129674 => true, + 129675 => true, + 129676 => true, + 129677 => true, + 129678 => true, + 129679 => true, + 129709 => true, + 129710 => true, + 129711 => true, + 129723 => true, + 129724 => true, + 129725 => true, + 129726 => true, + 129727 => true, + 129734 => true, + 129735 => true, + 129736 => true, + 129737 => true, + 129738 => true, + 129739 => true, + 129740 => true, + 129741 => true, + 129742 => true, + 129743 => true, + 129754 => true, + 129755 => true, + 129756 => true, + 129757 => true, + 129758 => true, + 129759 => true, + 129768 => true, + 129769 => true, + 129770 => true, + 129771 => true, + 129772 => true, + 129773 => true, + 129774 => true, + 129775 => true, + 129783 => true, + 129784 => true, + 129785 => true, + 129786 => true, + 129787 => true, + 129788 => true, + 129789 => true, + 129790 => true, + 129791 => true, + 129939 => true, + 131070 => true, + 131071 => 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, +); diff --git a/transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_mapped.php b/transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_mapped.php new file mode 100644 index 0000000..54f21cc --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_mapped.php @@ -0,0 +1,308 @@ + ' ', + 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)', +); diff --git a/transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_valid.php b/transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_valid.php new file mode 100644 index 0000000..223396e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/disallowed_STD3_valid.php @@ -0,0 +1,71 @@ + 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, +); diff --git a/transfer-protocol/vendor/rowbot/idna/resources/ignored.php b/transfer-protocol/vendor/rowbot/idna/resources/ignored.php new file mode 100644 index 0000000..c421fe3 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/ignored.php @@ -0,0 +1,274 @@ + true, + 847 => true, + 6155 => true, + 6156 => true, + 6157 => true, + 6159 => 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, +); diff --git a/transfer-protocol/vendor/rowbot/idna/resources/mapped.php b/transfer-protocol/vendor/rowbot/idna/resources/mapped.php new file mode 100644 index 0000000..8ff3b91 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/mapped.php @@ -0,0 +1,5877 @@ + '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 => 'ⱞ', + 11311 => 'ⱟ', + 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 => 'ꞿ', + 42944 => 'ꟁ', + 42946 => 'ꟃ', + 42948 => 'ꞔ', + 42949 => 'ʂ', + 42950 => 'ᶎ', + 42951 => 'ꟈ', + 42953 => 'ꟊ', + 42960 => 'ꟑ', + 42966 => 'ꟗ', + 42968 => 'ꟙ', + 42994 => 'c', + 42995 => 'f', + 42996 => 'q', + 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 => '𐓻', + 66928 => '𐖗', + 66929 => '𐖘', + 66930 => '𐖙', + 66931 => '𐖚', + 66932 => '𐖛', + 66933 => '𐖜', + 66934 => '𐖝', + 66935 => '𐖞', + 66936 => '𐖟', + 66937 => '𐖠', + 66938 => '𐖡', + 66940 => '𐖣', + 66941 => '𐖤', + 66942 => '𐖥', + 66943 => '𐖦', + 66944 => '𐖧', + 66945 => '𐖨', + 66946 => '𐖩', + 66947 => '𐖪', + 66948 => '𐖫', + 66949 => '𐖬', + 66950 => '𐖭', + 66951 => '𐖮', + 66952 => '𐖯', + 66953 => '𐖰', + 66954 => '𐖱', + 66956 => '𐖳', + 66957 => '𐖴', + 66958 => '𐖵', + 66959 => '𐖶', + 66960 => '𐖷', + 66961 => '𐖸', + 66962 => '𐖹', + 66964 => '𐖻', + 66965 => '𐖼', + 67457 => 'ː', + 67458 => 'ˑ', + 67459 => 'æ', + 67460 => 'ʙ', + 67461 => 'ɓ', + 67463 => 'ʣ', + 67464 => 'ꭦ', + 67465 => 'ʥ', + 67466 => 'ʤ', + 67467 => 'ɖ', + 67468 => 'ɗ', + 67469 => 'ᶑ', + 67470 => 'ɘ', + 67471 => 'ɞ', + 67472 => 'ʩ', + 67473 => 'ɤ', + 67474 => 'ɢ', + 67475 => 'ɠ', + 67476 => 'ʛ', + 67477 => 'ħ', + 67478 => 'ʜ', + 67479 => 'ɧ', + 67480 => 'ʄ', + 67481 => 'ʪ', + 67482 => 'ʫ', + 67483 => 'ɬ', + 67484 => '𝼄', + 67485 => 'ꞎ', + 67486 => 'ɮ', + 67487 => '𝼅', + 67488 => 'ʎ', + 67489 => '𝼆', + 67490 => 'ø', + 67491 => 'ɶ', + 67492 => 'ɷ', + 67493 => 'q', + 67494 => 'ɺ', + 67495 => '𝼈', + 67496 => 'ɽ', + 67497 => 'ɾ', + 67498 => 'ʀ', + 67499 => 'ʨ', + 67500 => 'ʦ', + 67501 => 'ꭧ', + 67502 => 'ʧ', + 67503 => 'ʈ', + 67504 => 'ⱱ', + 67506 => 'ʏ', + 67507 => 'ʡ', + 67508 => 'ʢ', + 67509 => 'ʘ', + 67510 => 'ǀ', + 67511 => 'ǁ', + 67512 => 'ǂ', + 67513 => '𝼊', + 67514 => '𝼞', + 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 => '𪘀', +); diff --git a/transfer-protocol/vendor/rowbot/idna/resources/virama.php b/transfer-protocol/vendor/rowbot/idna/resources/virama.php new file mode 100644 index 0000000..63c9bbc --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/resources/virama.php @@ -0,0 +1,67 @@ + 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, + 5909 => 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, + 69744 => 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, +); diff --git a/transfer-protocol/vendor/rowbot/idna/src/CodePoint.php b/transfer-protocol/vendor/rowbot/idna/src/CodePoint.php new file mode 100644 index 0000000..d7203e7 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/src/CodePoint.php @@ -0,0 +1,139 @@ += 0x00 && $codePoint <= 0x7F) { + return chr($codePoint); + } + + $count = 0; + $offset = 0; + + if ($codePoint >= 0x0080 && $codePoint <= 0x07FF) { + $count = 1; + $offset = 0xC0; + } elseif ($codePoint >= 0x0800 && $codePoint <= 0xFFFF) { + $count = 2; + $offset = 0xE0; + } elseif ($codePoint >= 0x10000 && $codePoint <= 0x10FFFF) { + $count = 3; + $offset = 0xF0; + } + + $bytes = chr(($codePoint >> (6 * $count)) + $offset); + + while ($count > 0) { + $temp = $codePoint >> (6 * ($count - 1)); + $bytes .= chr(0x80 | ($temp & 0x3F)); + --$count; + } + + return $bytes; + } + + /** + * 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 + * + * @return list + */ + public static function utf8Decode(string $input): array + { + $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 ($bytesNeeded === 0) { + if ($byte >= 0x00 && $byte <= 0x7F) { + $codePoints[] = $byte; + + continue; + } + + if ($byte >= 0xC2 && $byte <= 0xDF) { + $bytesNeeded = 1; + $codePoint = $byte & 0x1F; + } elseif ($byte >= 0xE0 && $byte <= 0xEF) { + if ($byte === 0xE0) { + $lowerBoundary = 0xA0; + } elseif ($byte === 0xED) { + $upperBoundary = 0x9F; + } + + $bytesNeeded = 2; + $codePoint = $byte & 0xF; + } elseif ($byte >= 0xF0 && $byte <= 0xF4) { + if ($byte === 0xF0) { + $lowerBoundary = 0x90; + } elseif ($byte === 0xF4) { + $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 ($bytesNeeded !== 0) { + $codePoints[] = 0xFFFD; + } + + return $codePoints; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/src/CodePointStatus.php b/transfer-protocol/vendor/rowbot/idna/src/CodePointStatus.php new file mode 100755 index 0000000..e48a511 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/src/CodePointStatus.php @@ -0,0 +1,106 @@ + + */ + 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 $dataLoaded = false; + + /** + * @codeCoverageIgnore + */ + private function __construct() + { + } + + /** + * @return array{status: string, mapping?: string} + */ + public static function lookup(int $codePoint, bool $useSTD3ASCIIRules): array + { + if (!self::$dataLoaded) { + self::$dataLoaded = true; + self::$mapped = require self::RESOURCE_DIR . 'mapped.php'; + self::$ignored = require self::RESOURCE_DIR . 'ignored.php'; + self::$deviation = require self::RESOURCE_DIR . 'deviation.php'; + self::$disallowed = require self::RESOURCE_DIR . 'disallowed.php'; + self::$disallowed_STD3_mapped = require self::RESOURCE_DIR . 'disallowed_STD3_mapped.php'; + self::$disallowed_STD3_valid = require self::RESOURCE_DIR . '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']; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/src/DomainInfo.php b/transfer-protocol/vendor/rowbot/idna/src/DomainInfo.php new file mode 100644 index 0000000..c873086 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/src/DomainInfo.php @@ -0,0 +1,82 @@ +bidiDomain = false; + $this->errors = 0; + $this->transitionalDifferent = false; + $this->validBidiDomain = true; + } + + public function addError(int $errors): void + { + $this->errors |= $errors; + } + + public function getErrors(): int + { + return $this->errors; + } + + /** + * A Bidi domain name is a domain name containing at least one character with Bidi_Class R, AL, or AN. + * + * @see https://www.unicode.org/reports/tr46/#Notation + * @see https://www.unicode.org/reports/tr9/#Bidirectional_Character_Types + */ + public function isBidiDomain(): bool + { + return $this->bidiDomain; + } + + public function isTransitionalDifferent(): bool + { + return $this->transitionalDifferent; + } + + public function isValidBidiDomain(): bool + { + return $this->validBidiDomain; + } + + public function setBidiDomain(): void + { + $this->bidiDomain = true; + } + + public function setInvalidBidiDomain(): void + { + $this->validBidiDomain = false; + } + + public function setTransitionalDifferent(): void + { + $this->transitionalDifferent = true; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/src/Idna.php b/transfer-protocol/vendor/rowbot/idna/src/Idna.php new file mode 100644 index 0000000..9d5153e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/src/Idna.php @@ -0,0 +1,268 @@ + true, + 'CheckBidi' => true, + 'CheckJoiners' => true, + 'UseSTD3ASCIIRules' => true, + 'Transitional_Processing' => false, + ]; + private const DEFAULT_ASCII_OPTIONS = self::DEFAULT_UNICODE_OPTIONS + [ + 'VerifyDnsLength' => true, + ]; + + 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; + + private const MAX_DOMAIN_SIZE = 253; + private const MAX_LABEL_SIZE = 63; + + /** + * @codeCoverageIgnore + */ + private function __construct() + { + } + + /** + * @see https://www.unicode.org/reports/tr46/#ProcessingStepMap + * + * @param array $options + */ + private static function mapCodePoints(string $domain, array $options, DomainInfo $info): string + { + $str = ''; + $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules']; + $transitional = $options['Transitional_Processing']; + $errors = 0; + $transitionalDifferent = false; + + foreach (CodePoint::utf8Decode($domain) as $codePoint) { + $data = CodePointStatus::lookup($codePoint, $useSTD3ASCIIRules); + + switch ($data['status']) { + case 'disallowed': + $errors |= Idna::ERROR_DISALLOWED; + + // no break. + + case 'valid': + $str .= CodePoint::encode($codePoint); + + break; + + case 'ignored': + // Do nothing. + break; + + case 'mapped': + $str .= $data['mapping']; + + break; + + case 'deviation': + $transitionalDifferent = true; + $str .= ($transitional ? $data['mapping'] : CodePoint::encode($codePoint)); + + break; + } + } + + $info->addError($errors); + + if ($transitionalDifferent) { + $info->setTransitionalDifferent(); + } + + return $str; + } + + /** + * @see https://www.unicode.org/reports/tr46/#Processing + * + * @param array $options + * + * @return list + */ + private static function process(string $domain, array $options, DomainInfo $info): array + { + // 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->addError(self::ERROR_EMPTY_LABEL); + + return ['']; + } + + // 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)) { + $originalDomain = $domain; + $domain = Normalizer::normalize($domain, Normalizer::FORM_C); + + // This shouldn't be possible since the input string is run through the UTF-8 decoder + // when mapping the code points above, but lets account for it anyway. + if ($domain === false) { + $info->addError(self::ERROR_INVALID_ACE_LABEL); + $domain = $originalDomain; + } + + unset($originalDomain); + } + + // Step 3. Break the string into labels at U+002E (.) FULL STOP. + $labels = explode('.', $domain); + $lastLabelIndex = count($labels) - 1; + $validator = new LabelValidator($info); + + // Step 4. Convert and validate each label in the domain name string. + foreach ($labels as $i => $label) { + $validationOptions = $options; + + if (strncmp($label, 'xn--', 4) === 0) { + try { + $label = Punycode::decode(substr($label, 4)); + } catch (PunycodeException $e) { + $info->addError(self::ERROR_PUNYCODE); + + continue; + } + + $validationOptions['Transitional_Processing'] = false; + $labels[$i] = $label; + } + + $validator->validate($label, $validationOptions, $i > 0 && $i === $lastLabelIndex); + } + + if ($info->isBidiDomain() && !$info->isValidBidiDomain()) { + $info->addError(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://www.unicode.org/reports/tr46/#ToASCII + * + * @param array $options + */ + public static function toAscii(string $domain, array $options = []): IdnaResult + { + $options = array_merge(self::DEFAULT_ASCII_OPTIONS, $options); + $info = new DomainInfo(); + $labels = self::process($domain, $options, $info); + + foreach ($labels as $i => $label) { + // Only convert labels to punycode that contain non-ASCII code points + if (preg_match('/[^\x00-\x7F]/', $label) === 1) { + try { + $label = 'xn--' . Punycode::encode($label); + } catch (PunycodeException $e) { + $info->addError(self::ERROR_PUNYCODE); + } + + $labels[$i] = $label; + } + } + + if ($options['VerifyDnsLength']) { + self::validateDomainAndLabelLength($labels, $info); + } + + return new IdnaResult(implode('.', $labels), $info); + } + + /** + * @see https://www.unicode.org/reports/tr46/#ToUnicode + * + * @param array $options + */ + public static function toUnicode(string $domain, array $options = []): IdnaResult + { + // VerifyDnsLength is not a valid option for toUnicode, so remove it if it exists. + unset($options['VerifyDnsLength']); + $options = array_merge(self::DEFAULT_UNICODE_OPTIONS, $options); + $info = new DomainInfo(); + $labels = self::process($domain, $options, $info); + + return new IdnaResult(implode('.', $labels), $info); + } + + /** + * @param list $labels + */ + private static function validateDomainAndLabelLength(array $labels, DomainInfo $info): void + { + $maxDomainSize = self::MAX_DOMAIN_SIZE; + $length = count($labels); + $totalLength = $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]); + $totalLength += $bytes; + + if ($bytes > self::MAX_LABEL_SIZE) { + $info->addError(self::ERROR_LABEL_TOO_LONG); + } + } + + if ($totalLength > $maxDomainSize) { + $info->addError(self::ERROR_DOMAIN_NAME_TOO_LONG); + } + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/src/IdnaResult.php b/transfer-protocol/vendor/rowbot/idna/src/IdnaResult.php new file mode 100644 index 0000000..71a3c81 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/src/IdnaResult.php @@ -0,0 +1,55 @@ +domain = $domain; + $this->errors = $info->getErrors(); + $this->transitionalDifferent = $info->isTransitionalDifferent(); + } + + public function getDomain(): string + { + return $this->domain; + } + + public function getErrors(): int + { + return $this->errors; + } + + public function hasError(int $error): bool + { + return ($this->errors & $error) !== 0; + } + + public function hasErrors(): bool + { + return $this->errors !== 0; + } + + public function isTransitionalDifferent(): bool + { + return $this->transitionalDifferent; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/src/LabelValidator.php b/transfer-protocol/vendor/rowbot/idna/src/LabelValidator.php new file mode 100644 index 0000000..edacacd --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/src/LabelValidator.php @@ -0,0 +1,237 @@ + + */ + protected static $virama = []; + + public function __construct(DomainInfo $info) + { + $this->info = $info; + + if (self::$virama === []) { + self::$virama = require __DIR__ . DS . '..' . DS . 'resources' . DS . 'virama.php'; + } + } + + /** + * @param list $codePoints + */ + protected function isValidContextJ(string $label, array $codePoints): bool + { + $offset = 0; + + foreach ($codePoints as $i => $codePoint) { + if ($codePoint !== 0x200C && $codePoint !== 0x200D) { + continue; + } + + $prev = $i - 1; + + if (!isset($codePoints[$prev])) { + return false; + } + + // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True; + if (isset(self::$virama[$codePoints[$prev]])) { + 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 ( + $codePoint === 0x200C + && preg_match(Regex::ZWNJ, $label, $matches, PREG_OFFSET_CAPTURE, $offset) === 1 + ) { + $offset += strlen($matches[1][0]); + + continue; + } + + return false; + } + + return true; + } + + /** + * @see https://www.unicode.org/reports/tr46/#Validity_Criteria + * + * @param array $options + */ + public function validate(string $label, array $options, bool $canBeEmpty): void + { + if ($label === '') { + if ( + !$canBeEmpty + && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength']) + ) { + $this->info->addError(Idna::ERROR_EMPTY_LABEL); + } + + return; + } + + $codePoints = CodePoint::utf8Decode($label); + + // Step 1. The label must be in Unicode Normalization Form C. + if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) { + $this->info->addError(Idna::ERROR_INVALID_ACE_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[3]) && $codePoints[2] === 0x2D && $codePoints[3] === 0x2D) { + $this->info->addError(Idna::ERROR_HYPHEN_3_4); + } + + // Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D + // HYPHEN-MINUS character. + if (strncmp($label, '-', 1) === 0) { + $this->info->addError(Idna::ERROR_LEADING_HYPHEN); + } + + if (substr_compare($label, '-', -1) === 0) { + $this->info->addError(Idna::ERROR_TRAILING_HYPHEN); + } + } + + // Step 4. The label must not contain a U+002E (.) FULL STOP. + if (strpos($label, '.') !== false) { + $this->info->addError(Idna::ERROR_LABEL_HAS_DOT); + } + + // Step 5. The label must not begin with a combining mark, that is: General_Category=Mark. + if (preg_match(Regex::COMBINING_MARK, $label, $matches) === 1) { + $this->info->addError(Idna::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 = CodePointStatus::lookup($codePoint, $useSTD3ASCIIRules); + $status = $data['status']; + + if ($status === 'valid' || (!$transitional && $status === 'deviation')) { + continue; + } + + $this->info->addError(Idna::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'] && !$this->isValidContextJ($label, $codePoints)) { + $this->info->addError(Idna::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'] + && (!$this->info->isBidiDomain() || $this->info->isValidBidiDomain()) + ) { + $this->validateBidi($label); + } + } + + /** + * @see https://tools.ietf.org/html/rfc5893#section-2 + */ + protected function validateBidi(string $label): void + { + if (preg_match(Regex::RTL_LABEL, $label) === 1) { + $this->info->setBidiDomain(); + + // 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 (preg_match(Regex::BIDI_STEP_1_RTL, $label) !== 1) { + $this->info->setInvalidBidiDomain(); + + 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 (preg_match(Regex::BIDI_STEP_2, $label) === 1) { + $this->info->setInvalidBidiDomain(); + + 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 (preg_match(Regex::BIDI_STEP_3, $label) !== 1) { + $this->info->setInvalidBidiDomain(); + + return; + } + + // Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa. + if ( + preg_match(Regex::BIDI_STEP_4_AN, $label) === 1 + && preg_match(Regex::BIDI_STEP_4_EN, $label) === 1 + ) { + $this->info->setInvalidBidiDomain(); + + 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 (preg_match(Regex::BIDI_STEP_1_LTR, $label) !== 1) { + $this->info->setInvalidBidiDomain(); + + 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 (preg_match(Regex::BIDI_STEP_5, $label) === 1) { + $this->info->setInvalidBidiDomain(); + + 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 (preg_match(Regex::BIDI_STEP_6, $label) !== 1) { + $this->info->setInvalidBidiDomain(); + + return; + } + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/tests/IdnaV2Test.php b/transfer-protocol/vendor/rowbot/idna/tests/IdnaV2Test.php new file mode 100755 index 0000000..63c79d6 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/tests/IdnaV2Test.php @@ -0,0 +1,258 @@ + true, + 'CheckBidi' => true, + 'CheckJoiners' => true, + 'UseSTD3ASCIIRules' => true, + 'Transitional_Processing' => false, + 'VerifyDnsLength' => true, + ]; + + /** + * @var array + */ + protected static $errorMap; + + public static function setUpBeforeClass(): void + { + if (isset(self::$errorMap)) { + return; + } + + $reflection = new ReflectionClass(Idna::class); + $errors = array_filter($reflection->getConstants(), static function (string $name): bool { + return strncmp($name, 'ERROR_', 6) === 0; + }, ARRAY_FILTER_USE_KEY); + self::$errorMap = array_flip($errors); + } + + /** + * @return array> + */ + public function getData(): array + { + return $this->loadTestData(Idna::UNICODE_VERSION); + } + + /** + * @dataProvider getData + */ + public function testToUnicode( + string $source, + string $toUnicode, + string $toUnicodeStatus, + string $toAsciiN, + string $toAsciiNStatus, + string $toAsciiT, + string $toAsciiTStatus + ): void { + [ + $toUnicode, + $toUnicodeStatus, + $toAsciiN, + $toAsciiNStatus, + $toAsciiT, + $toAsciiTStatus, + ] = $this->translate($source, $toUnicode, $toUnicodeStatus, $toAsciiN, $toAsciiNStatus, $toAsciiT, $toAsciiTStatus); + + $result = Idna::toUnicode($source, self::DEFAULT_OPTIONS); + self::assertSame($toUnicode, $result->getDomain()); + + if ($toUnicodeStatus === []) { + self::assertFalse($result->hasErrors(), sprintf( + 'Expected no errors, but found %s.', + $this->containedErrors($result->getErrors()) + )); + } else { + self::assertTrue($result->hasErrors(), sprintf( + 'Expected to find %s, but found %s', + $this->expectedErrors($toUnicodeStatus), + $this->containedErrors($result->getErrors()) + )); + } + } + + /** + * @dataProvider getData + */ + public function testToAsciiNonTransitional( + string $source, + string $toUnicode, + string $toUnicodeStatus, + string $toAsciiN, + string $toAsciiNStatus, + string $toAsciiT, + string $toAsciiTStatus + ): void { + [ + $toUnicode, + $toUnicodeStatus, + $toAsciiN, + $toAsciiNStatus, + $toAsciiT, + $toAsciiTStatus, + ] = $this->translate($source, $toUnicode, $toUnicodeStatus, $toAsciiN, $toAsciiNStatus, $toAsciiT, $toAsciiTStatus); + $result = Idna::toAscii($source, self::DEFAULT_OPTIONS); + + if ($toAsciiNStatus === []) { + self::assertSame($toAsciiN, $result->getDomain()); + self::assertFalse($result->hasErrors(), sprintf( + 'Expected no errors, but found %s.', + $this->containedErrors($result->getErrors()) + )); + } else { + self::assertTrue($result->hasErrors(), sprintf( + 'Expected %s, but found no errors.', + $this->expectedErrors($toAsciiTStatus) + )); + } + } + + /** + * @dataProvider getData + */ + public function testToAsciiTransitional( + string $source, + string $toUnicode, + string $toUnicodeStatus, + string $toAsciiN, + string $toAsciiNStatus, + string $toAsciiT, + string $toAsciiTStatus + ): void { + [ + $toUnicode, + $toUnicodeStatus, + $toAsciiN, + $toAsciiNStatus, + $toAsciiT, + $toAsciiTStatus, + ] = $this->translate($source, $toUnicode, $toUnicodeStatus, $toAsciiN, $toAsciiNStatus, $toAsciiT, $toAsciiTStatus); + $options = self::DEFAULT_OPTIONS; + $options['Transitional_Processing'] = true; + $result = Idna::toAscii($source, $options); + + // There is currently a bug in the test data, where it is expected that the following 2 + // source strings result in an empty string. However, due to the way the test files are setup + // it currently isn't possible to represent an empty string as an expected value. So, we + // skip these 2 problem tests. I have notified the Unicode Consortium about this and they + // have passed the information along to the spec editors. + if ($source === "\u{200C}" || $source === "\u{200D}") { + $toAsciiT = ''; + } + + if ($toAsciiTStatus === []) { + self::assertSame($toAsciiT, $result->getDomain()); + self::assertFalse($result->hasErrors(), sprintf( + 'Expected no errors, but found %s.', + $this->containedErrors($result->getErrors()) + )); + } else { + self::assertTrue($result->hasErrors(), sprintf( + 'Expected %s, but found no errors.', + $this->expectedErrors($toAsciiTStatus) + )); + } + } + + public function assertErrors(array $expectedErrors, int $errors): void + { + foreach ($expectedErrors as $errorCode) { + if (is_array($errorCode)) { + self::assertTrue($this->matchErrors($errorCode, $errors)); + + continue; + } + + self::assertTrue( + ($errors & $errorCode) !== 0, + sprintf( + 'Expected %s (%d), but only found %s.', + self::$errorMap[$errorCode], + $errorCode, + $this->containedErrors($errors) + ) + ); + } + } + + public function expectedErrors(array $expectedErrors): string + { + $message = ''; + + foreach ($expectedErrors as $i => $errorCode) { + if (is_array($errorCode)) { + $message .= '('; + + foreach ($errorCode as $j => $error) { + if ($j > 0) { + $message .= ' OR '; + } + + $message .= sprintf('%s (%d)', self::$errorMap[$error], $error); + } + + $message .= ')'; + } else { + if ($i > 0) { + $message .= ' | '; + } + + $message .= sprintf('%s (%d)', self::$errorMap[$errorCode], $errorCode); + } + } + + return $message; + } + + public function containedErrors(int $errors): string + { + if ($errors === 0) { + return 'no errors'; + } + + $out = ''; + $count = 0; + + foreach (self::$errorMap as $code => $name) { + if (($errors & $code) !== 0) { + if ($count++ > 0) { + $out .= ' | '; + } + + $out .= sprintf('%s (%d)', $name, $code); + } + } + + return $out; + } + + public function matchErrors(array $potentialErrors, int $errors): bool + { + foreach ($potentialErrors as $error) { + if (($errors & $error) !== 0) { + return true; + } + } + + return false; + } +} diff --git a/transfer-protocol/vendor/rowbot/idna/tests/IdnaV2TestCase.php b/transfer-protocol/vendor/rowbot/idna/tests/IdnaV2TestCase.php new file mode 100644 index 0000000..714b39e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/idna/tests/IdnaV2TestCase.php @@ -0,0 +1,216 @@ + Idna::ERROR_DISALLOWED, + 'P4' => [ + Idna::ERROR_EMPTY_LABEL, + Idna::ERROR_DOMAIN_NAME_TOO_LONG, + Idna::ERROR_LABEL_TOO_LONG, + Idna::ERROR_PUNYCODE, + ], + 'V1' => Idna::ERROR_INVALID_ACE_LABEL, + 'V2' => Idna::ERROR_HYPHEN_3_4, + 'V3' => [Idna::ERROR_LEADING_HYPHEN, Idna::ERROR_TRAILING_HYPHEN], + 'V4' => Idna::ERROR_LABEL_HAS_DOT, + 'V5' => Idna::ERROR_LEADING_COMBINING_MARK, + 'V6' => Idna::ERROR_DISALLOWED, + // V7 and V8 are handled by C* and B* respectively. + 'A3' => Idna::ERROR_PUNYCODE, + 'A4_1' => Idna::ERROR_DOMAIN_NAME_TOO_LONG, + 'A4_2' => [Idna::ERROR_EMPTY_LABEL, Idna::ERROR_LABEL_TOO_LONG], + 'B1' => Idna::ERROR_BIDI, + 'B2' => Idna::ERROR_BIDI, + 'B3' => Idna::ERROR_BIDI, + 'B4' => Idna::ERROR_BIDI, + 'B5' => Idna::ERROR_BIDI, + 'B6' => Idna::ERROR_BIDI, + 'C1' => Idna::ERROR_CONTEXTJ, + 'C2' => Idna::ERROR_CONTEXTJ, + // ContextO isn't tested here. + // 'C3' => Idna::ERROR_CONTEXTO_PUNCTUATION, + // 'C4' => Idna::ERROR_CONTEXTO_PUNCTUATION, + // 'C5' => Idna::ERROR_CONTEXTO_PUNCTUATION, + // 'C6' => Idna::ERROR_CONTEXTO_PUNCTUATION, + // 'C7' => Idna::ERROR_CONTEXTO_PUNCTUATION, + // 'C8' => Idna::ERROR_CONTEXTO_DIGITS, + // 'C9' => Idna::ERROR_CONTEXTO_DIGITS, + 'X4_2' => Idna::ERROR_EMPTY_LABEL, + 'X3' => Idna::ERROR_EMPTY_LABEL, + ]; + + private const BASE_URI = 'https://www.unicode.org/Public/idna/'; + private const TEST_FILE = 'IdnaTestV2.txt'; + private const CACHE_TTL = 86400 * 7; // 7 DAYS + private const TEST_DATA_DIR = __DIR__ . DIRECTORY_SEPARATOR . 'data'; + + /** + * @return array> + */ + public function loadTestData(string $version): array + { + $cache = new FilesystemAdapter( + 'unicode-idna-test-data', + self::CACHE_TTL, + self::TEST_DATA_DIR + ); + $testData = $cache->getItem($version); + + if ($testData->isHit()) { + return $testData->get(); + } + + $client = new Client([ + 'base_uri' => self::BASE_URI + ]); + $response = $client->request('GET', $version . '/' . self::TEST_FILE); + + if ($response->getStatusCode() >= 400) { + throw new RuntimeException(sprintf( + 'Got status code %d trying to retrieve %s for Unicode version %s.', + $response->getStatusCode(), + self::TEST_FILE, + $version + )); + } + + $data = $this->processResponse($response); + $testData->set($data); + $cache->save($testData); + + return $data; + } + + /** + * @return array> + */ + private function processResponse(ResponseInterface $response): array + { + $output = []; + + foreach (explode("\n", (string) $response->getBody()) as $line) { + // Ignore empty lines and comments. + if ($line === '' || $line[0] === '#') { + continue; + } + + [$data] = explode('#', $line); + $columns = array_map('\trim', explode(';', $data)); + assert(count($columns) === 7); + $output[] = $columns; + } + + return $output; + } + + /** + * @param array> $inherit + * + * @return array> + */ + private function resolveErrorCodes(string $statusCodes, array $inherit, array $ignore): array + { + if ($statusCodes === '') { + return $inherit; + } + + if ($statusCodes === '[]') { + return []; + } + + $matchCount = preg_match_all('/[PVUABCX][0-9](?:_[0-9])?/', $statusCodes, $matches); + + if (preg_last_error() !== PREG_NO_ERROR) { + throw new RuntimeException(); + } + + if ($matchCount === 0) { + throw new RuntimeException(); + } + + $errors = []; + + foreach ($matches[0] as $match) { + if ($match[0] === 'U' || in_array($match, $ignore, true)) { + continue; + } + + if (!isset(self::ERROR_CODE_MAP[$match])) { + throw new RuntimeException(sprintf('Unhandled error code %s.', $match)); + } + + $errors[] = self::ERROR_CODE_MAP[$match]; + } + + return $errors; + } + + /** + * @return array{ + * 0: string, + * 1: array>, + * 2: string, + * 3: array>, + * 4: string, + * 5: array> + * } + */ + public function translate( + string $source, + string $toUnicode, + string $toUnicodeStatus, + string $toAsciiN, + string $toAsciiNStatus, + string $toAsciiT, + string $toAsciiTStatus, + array $ignore = [] + ): array { + if ($toUnicode === '') { + $toUnicode = $source; + } + + if ($toAsciiN === '') { + $toAsciiN = $toUnicode; + } + + if ($toAsciiT === '') { + $toAsciiT = $toAsciiN; + } + + $toUnicodeStatus = $this->resolveErrorCodes($toUnicodeStatus, [], $ignore); + $toAsciiNStatus = $this->resolveErrorCodes($toAsciiNStatus, $toUnicodeStatus, $ignore); + $toAsciiTStatus = $this->resolveErrorCodes($toAsciiTStatus, $toAsciiNStatus, $ignore); + + return [ + $toUnicode, + $toUnicodeStatus, + $toAsciiN, + $toAsciiNStatus, + $toAsciiT, + $toAsciiTStatus, + ]; + } +} diff --git a/transfer-protocol/vendor/rowbot/punycode/.gitattributes b/transfer-protocol/vendor/rowbot/punycode/.gitattributes new file mode 100755 index 0000000..dfe0770 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/transfer-protocol/vendor/rowbot/punycode/.github/workflows/tests.yml b/transfer-protocol/vendor/rowbot/punycode/.github/workflows/tests.yml new file mode 100644 index 0000000..242ad2d --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/.github/workflows/tests.yml @@ -0,0 +1,176 @@ +name: Tests + +on: + pull_request: + push: + paths-ignore: + - "**.md" + +jobs: + tests: + name: Tests + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - 7.1 + - 7.2 + - 7.3 + - 7.4 + - 8.0 + - 8.1 + - 8.2 + - 8.3 + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install + + - name: Run PHPStan + run: vendor/bin/phpstan analyse + + - name: Run PHPCS + run: vendor/bin/phpcs + + - name: Tests + run: vendor/bin/phpunit + + tests-unstable: + name: Test Unstable + runs-on: ${{ matrix.operating-system }} + continue-on-error: true + + strategy: + fail-fast: false + matrix: + php-version: + - nightly + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --ignore-platform-reqs + + - name: Tests + run: vendor/bin/phpunit + + tests-code-coverage: + name: Code Coverage + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + coverage: pcov + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install + + - name: Tests with code coverage + run: | + mkdir -p ./build/coverage/ + vendor/bin/phpunit --coverage-clover ./build/coverage/clover.xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./build/coverage/clover.xml + + tests-jit: + name: Test JIT + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - 8.0 + operating-system: [ ubuntu-latest ] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: none + ini-values: opcache.enable_cli=1, opcache.jit=1255, opcache.jit_buffer_size=64M + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install + + - name: Tests + run: vendor/bin/phpunit diff --git a/transfer-protocol/vendor/rowbot/punycode/.gitignore b/transfer-protocol/vendor/rowbot/punycode/.gitignore new file mode 100755 index 0000000..7d6e0d5 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/.gitignore @@ -0,0 +1,6 @@ +composer.phar +composer.lock +/vendor/ +/.vscode/ +/build/ +.phpunit.result.cache diff --git a/transfer-protocol/vendor/rowbot/punycode/.phpcs.xml b/transfer-protocol/vendor/rowbot/punycode/.phpcs.xml new file mode 100644 index 0000000..254d476 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/.phpcs.xml @@ -0,0 +1,9 @@ + + + src + + + + + + diff --git a/transfer-protocol/vendor/rowbot/punycode/CHANGELOG.md b/transfer-protocol/vendor/rowbot/punycode/CHANGELOG.md new file mode 100755 index 0000000..a4e7ec8 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + +## [Unreleased] + +## [1.0.4] - 2024-05-02 + +### Fixed + +* Fix implicit nullable deprecation warning for PHP 8.4 + +## [1.0.3] - 2022-01-10 + +### Changed + +- Update PHPstan to 1.0 +- Switched to GitHub Actions + +## [1.0.2] - 2020-07-15 + +### Added + +* Minor performance improvements + +## [1.0.1] - 2020-06-16 + +### Fixed + +* When calling `Punycode::decode()`, the case flags array would fail to populate when given an empty array. + +## [1.0.0] - 2020-06-09 + +* Initial release diff --git a/transfer-protocol/vendor/rowbot/punycode/LICENSE b/transfer-protocol/vendor/rowbot/punycode/LICENSE new file mode 100755 index 0000000..06a800e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Trevor Rowbotham + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/transfer-protocol/vendor/rowbot/punycode/README.md b/transfer-protocol/vendor/rowbot/punycode/README.md new file mode 100644 index 0000000..0d801aa --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/README.md @@ -0,0 +1,83 @@ +# Punycode + +[![Software License](https://img.shields.io/github/license/TRowbotham/punycode?style=flat-square)](https://github.com/TRowbotham/punycode/blob/master/LICENSE) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/TRowbotham/punycode/Tests?style=flat-square)](https://travis-ci.com/github/TRowbotham/punycode) +[![Code Coverage](https://img.shields.io/codecov/c/github/TRowbotham/punycode/master?style=flat-square)](https://codecov.io/gh/TRowbotham/punycode) +[![PHP Version](https://img.shields.io/packagist/v/rowbot/punycode?style=flat-square)](https://packagist.org/packages/rowbot/punycode) +[![Total Downloads](https://img.shields.io/packagist/dt/rowbot/punycode?style=flat-square)](https://packagist.org/packages/rowbot/punycode) + +An implementation of RFC 3492 Punycode in PHP, based on the sample implementation in [Appendix C](https://tools.ietf.org/html/rfc3492#appendix-C). +This is NOT a substitue for `idn_to_ascii` and `idn_to_utf8`. + +## Requirements + +* PHP 7.1+ + +## Installation + +```bash +composer require rowbot/punycode +``` + +## API + +### Punycode::decode(string $input, int $outLength = null, array &$caseFlags = []) + +The `Punycode::decode()` method takes an ASCII encoded string and decodes it to a UTF-8 encoded +string. Optionally, the second parameter can be specified to place a limit on the size of the +returned string. + +#### Parameters + +* `$input` - An ASCII encoded punycode string to convert to a UTF-8 encoded string. +* `$outLength` - A positive integer representing the maximum length, in code points, of the resulting +output string. Defaults to 2,147,483,647. +* `$caseFlags` - An array, which will have the case flag of each character inserted into it. + +#### Throws + +* `\Rowbot\Punycode\Exception\OutputSizeExceededException` - If the size of the output string +exceeds the maximum size specified. +* `\Rowbot\Punycode\Exception\OverflowException` - If integer overflow occurs. +* `\Rowbot\Punycode\Exception\InvalidInputException` - If input contains non-ASCII bytes or mapping +a code point to a digit fails. + +```php +use Rowbot\Punycode\Punycode; + +try { + echo Punycode::decode('Hello-Another-Way--fc4qua05auwb3674vfr0b'); // Hello-Another-Way-それぞれの場所 +} catch (\Rowbot\Punycode\Exception\PunycodeException $e) { + echo 'An error occured!'; +} +``` + +### Punycode::encode(string $input, int $outLength = null, array $caseFlags = []) + +The `Punycode::encode()` method takes a UTF-8 encoded string and converts it into an ASCII encoded +punycode string. Optionally, the second parameter can be specified to place a limit on the size of +the returned string. + +#### Parameters + +* `$input` - A UTF-8 encoded string to convert to punycode. +* `$outLength` - A positive integer representing the maximum length, in code points, of the resulting +output string. Defaults to 2,147,483,647. +* `$caseFlags` - An array of bools where true indicates that the character should be uppercase and +false indicates that it should be lowercase. This only affects ASCII characters `[a-zA-Z]`. + +#### Throws + +* `\Rowbot\Punycode\Exception\OutputSizeExceededException` - If the size of the output string +exceeds the maximum size specified. +* `\Rowbot\Punycode\Exception\OverflowException` - If integer overflow occurs. + +```php +use Rowbot\Punycode\Punycode; + +try { + echo Punycode::encode('Hello-Another-Way-それぞれの場所'); // Hello-Another-Way--fc4qua05auwb3674vfr0b +} catch (\Rowbot\Punycode\Exception\PunycodeException $e) { + echo 'An error occured!'; +} +``` diff --git a/transfer-protocol/vendor/rowbot/punycode/composer.json b/transfer-protocol/vendor/rowbot/punycode/composer.json new file mode 100755 index 0000000..ff8e20b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/composer.json @@ -0,0 +1,38 @@ +{ + "name": "rowbot/punycode", + "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA).", + "keywords": ["punycode", "rfc3492", "rfc-3492"], + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Trevor Rowbotham", + "role": "Developer", + "homepage": "https://trowbotham.com" + } + ], + "config": { + "sort-packages": true + }, + "autoload": { + "psr-4": { + "Rowbot\\Punycode\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Rowbot\\Punycode\\Test\\": "tests/" + } + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "ext-mbstring": "*", + "phpstan/phpstan": "^1.2", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.5.1" + } +} diff --git a/transfer-protocol/vendor/rowbot/punycode/phpstan.neon b/transfer-protocol/vendor/rowbot/punycode/phpstan.neon new file mode 100644 index 0000000..f6970f6 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/phpstan.neon @@ -0,0 +1,8 @@ +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + +parameters: + level: max + paths: + - src diff --git a/transfer-protocol/vendor/rowbot/punycode/phpunit.xml b/transfer-protocol/vendor/rowbot/punycode/phpunit.xml new file mode 100644 index 0000000..e0ce8df --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/phpunit.xml @@ -0,0 +1,20 @@ + + + + tests + + + + + src + + + diff --git a/transfer-protocol/vendor/rowbot/punycode/src/Exception/InvalidInputException.php b/transfer-protocol/vendor/rowbot/punycode/src/Exception/InvalidInputException.php new file mode 100644 index 0000000..29d3a33 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/src/Exception/InvalidInputException.php @@ -0,0 +1,9 @@ + + */ + 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, + ]; + + /** + * @codeCoverageIgnore + */ + private function __construct() + { + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.1 + */ + private static function adaptBias(int $delta, int $numPoints, bool $firstTime): int + { + // 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); + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.2 + * + * @param array $caseFlags + */ + public static function decode(string $input, ?int $outLength = null, array &$caseFlags = []): string + { + $n = self::INITIAL_N; + $out = 0; + $i = 0; + $maxOut = $outLength ?? self::MAX_INT; + $bias = self::INITIAL_BIAS; + $lastDelimIndex = strrpos($input, self::DELIMITER); + $b = $lastDelimIndex === false ? 0 : $lastDelimIndex; + $inputLength = strlen($input); + $output = []; + $wantsCaseFlags = func_num_args() > 2; + + if ($b > $maxOut) { + throw new OutputSizeExceededException(); + } + + $bytes = array_map('ord', str_split($input)); + + for ($j = 0; $j < $b; ++$j) { + if ($bytes[$j] > 0x7F) { + throw new InvalidInputException(); + } + + if ($wantsCaseFlags) { + $caseFlags[$out] = self::flagged($bytes[$j]); + } + + $output[$out++] = $input[$j]; + } + + if ($b > 0) { + $b += 1; + } + + for ($in = $b; $in < $inputLength; ++$out) { + $oldi = $i; + $w = 1; + + for ($k = self::BASE; /* no condition */; $k += self::BASE) { + if ($in >= $inputLength) { + throw new InvalidInputException(); + } + + $digit = self::$basicToDigit[$bytes[$in++] & 0xFF]; + + if ($digit < 0) { + throw new InvalidInputException(); + } + + if ($digit > intdiv(self::MAX_INT - $i, $w)) { + throw new OverflowException(); + } + + $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 OverflowException(); + } + + $w *= $baseMinusT; + } + + $outPlusOne = $out + 1; + $bias = self::adaptBias($i - $oldi, $outPlusOne, $oldi === 0); + + if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) { + throw new OverflowException(); + } + + $n += intdiv($i, $outPlusOne); + $i %= $outPlusOne; + + if ($out >= $maxOut) { + throw new OutputSizeExceededException(); + } + + if ($wantsCaseFlags) { + array_splice($caseFlags, $i, 0, [self::flagged($bytes[$n - 1])]); + } + + array_splice($output, $i++, 0, [self::encodeCodePoint($n)]); + } + + return implode('', $output); + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.3 + * + * @param array $caseFlags + */ + public static function encode(string $input, ?int $outLength = null, array $caseFlags = []): string + { + $n = self::INITIAL_N; + $delta = 0; + $out = 0; + $maxOut = $outLength ?? self::MAX_INT; + $bias = self::INITIAL_BIAS; + $inputLength = 0; + $output = ''; + $codePoints = self::utf8Decode($input); + + foreach ($codePoints as $j => $codePoint) { + ++$inputLength; + + if ($codePoint < 0x80) { + if ($maxOut - $out < 2) { + throw new OutputSizeExceededException(); + } + + $output .= isset($caseFlags[$j]) + ? self::encodeBasic($codePoint, $caseFlags[$j]) + : chr($codePoint); + ++$out; + } + } + + $h = $out; + $b = $out; + + if ($b > 0) { + $output .= self::DELIMITER; + ++$out; + } + + while ($h < $inputLength) { + $m = self::MAX_INT; + + foreach ($codePoints as $codePoint) { + if ($codePoint >= $n && $codePoint < $m) { + $m = $codePoint; + } + } + + if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) { + throw new OverflowException(); + } + + $delta += ($m - $n) * ($h + 1); + $n = $m; + + foreach ($codePoints as $j => $codePoint) { + if ($codePoint < $n && ++$delta === 0) { + throw new OverflowException(); + } elseif ($codePoint === $n) { + $q = $delta; + + for ($k = self::BASE; /* no condition */; $k += self::BASE) { + if ($out >= $maxOut) { + throw new OutputSizeExceededException(); + } + + 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, $caseFlags[$j] ?? false); + ++$out; + $bias = self::adaptBias($delta, $h + 1, $h === $b); + $delta = 0; + ++$h; + } + } + + ++$delta; + ++$n; + } + + return $output; + } + + private static function encodeBasic(int $codePoint, bool $flag): string + { + $codePoint -= ($codePoint - 97 < 26 ? 1 : 0) << 5; + + return chr($codePoint + ((!$flag && ($codePoint - 65 < 26) ? 1 : 0) << 5)); + } + + /** + * Takes a Unicode code point and encodes it. The return behavior is undefined if the given + * code point is outside the range 0..10FFFF. + * + * @see https://encoding.spec.whatwg.org/#utf-8-encoder + */ + private static function encodeCodePoint(int $codePoint): string + { + if ($codePoint >= 0x00 && $codePoint <= 0x7F) { + return chr($codePoint); + } + + $count = 0; + $offset = 0; + + if ($codePoint >= 0x0080 && $codePoint <= 0x07FF) { + $count = 1; + $offset = 0xC0; + } elseif ($codePoint >= 0x0800 && $codePoint <= 0xFFFF) { + $count = 2; + $offset = 0xE0; + } elseif ($codePoint >= 0x10000 && $codePoint <= 0x10FFFF) { + $count = 3; + $offset = 0xF0; + } + + $bytes = chr(($codePoint >> (6 * $count)) + $offset); + + while ($count > 0) { + $temp = $codePoint >> (6 * ($count - 1)); + $bytes .= chr(0x80 | ($temp & 0x3F)); + --$count; + } + + return $bytes; + } + + private static function encodeDigit(int $d, bool $flag): string + { + return chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5)); + } + + private static function flagged(int $codePoint): bool + { + return $codePoint - 65 < 26; + } + + /** + * 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 + * + * @return array + */ + private static function utf8Decode(string $input): array + { + $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 ($bytesNeeded === 0) { + if ($byte <= 0x7F) { + $codePoints[] = $byte; + + continue; + } + + if ($byte >= 0xC2 && $byte <= 0xDF) { + $bytesNeeded = 1; + $codePoint = $byte & 0x1F; + } elseif ($byte >= 0xE0 && $byte <= 0xEF) { + if ($byte === 0xE0) { + $lowerBoundary = 0xA0; + } elseif ($byte === 0xED) { + $upperBoundary = 0x9F; + } + + $bytesNeeded = 2; + $codePoint = $byte & 0xF; + } elseif ($byte >= 0xF0 && $byte <= 0xF4) { + if ($byte === 0xF0) { + $lowerBoundary = 0x90; + } elseif ($byte === 0xF4) { + $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 ($bytesNeeded !== 0) { + $codePoints[] = 0xFFFD; + } + + return $codePoints; + } +} diff --git a/transfer-protocol/vendor/rowbot/punycode/tests/PunycodeTest.php b/transfer-protocol/vendor/rowbot/punycode/tests/PunycodeTest.php new file mode 100644 index 0000000..b37ebcf --- /dev/null +++ b/transfer-protocol/vendor/rowbot/punycode/tests/PunycodeTest.php @@ -0,0 +1,211 @@ +> + */ + public static function punycodeProvider(): array + { + return [ + [ + 'ليهمابتكلموشعربي؟', + 'egbpdaj6bu4bxfgehfvwxn', + 'Arabic (Egyptian)' + ], + [ + '他们为什么不说中文', + 'ihqwcrb4cv8a8dqg056pqjye', + 'Chinese (simplified)' + ], + [ + '他們爲什麽不說中文', + 'ihqwctvzc91f659drss3x8bo0yb', + 'Chinese (traditional)' + ], + [ + 'Pročprostěnemluvíčesky', + 'Proprostnemluvesky-uyb24dma41a', + 'Czech' + ], + [ + 'למההםפשוטלאמדבריםעברית', + '4dbcagdahymbxekheh6e0a7fei0b', + 'Hebrew' + ], + [ + 'यहलोगहिन्दीक्योंनहींबोलसकतेहैं', + 'i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd', + 'Hindi (Devanagari)' + ], + [ + 'なぜみんな日本語を話してくれないのか', + 'n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa', + 'Japanese (kanji and hiragana)' + ], + [ + '세계의모든사람들이한국어를이해한다면얼마나좋을까', + '989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c', + 'Korean (Hangul syllables)' + ], + [ + 'почемужеонинеговорятпорусски', + 'b1abfaaepdrnnbgefbadotcwatmq2g4l', + 'Russian (Cyrillic)' + ], + [ + 'PorquénopuedensimplementehablarenEspañol', + 'PorqunopuedensimplementehablarenEspaol-fmd56a', + 'Spanish' + ], + [ + 'TạisaohọkhôngthểchỉnóitiếngViệt', + 'TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g', + 'Vietnamese' + ], + [ + '3年B組金八先生', + '3B-ww4c5e180e575a65lsy2b', + '' + ], + [ + '安室奈美恵-with-SUPER-MONKEYS', + '-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n', + '' + ], + [ + 'Hello-Another-Way-それぞれの場所', + 'Hello-Another-Way--fc4qua05auwb3674vfr0b', + '' + ], + [ + 'ひとつ屋根の下2', + '2-u9tlzr9756bt3uc0v', + '' + ], + [ + 'MajiでKoiする5秒前', + 'MajiKoi5-783gue6qz075azm5e', + '' + ], + [ + 'パフィーdeルンバ', + 'de-jg4avhby1noc0d', + '' + ], + [ + 'そのスピードで', + 'd9juau41awczczp', + '' + ], + [ + '-> $1.00 <-', + '-> $1.00 <--', + '' + ], + ]; + } + + /** + * @dataProvider punycodeProvider + */ + public function testEncode(string $decoded, string $encoded, string $comment): void + { + self::assertSame($encoded, Punycode::encode($decoded), $comment); + } + + /** + * @dataProvider punycodeProvider + */ + public function testDecode(string $decoded, string $encoded, string $comment): void + { + self::assertSame($decoded, Punycode::decode($encoded), $comment); + } + + public function encodeMaxLengthDataProvider(): array + { + return array_filter($this->punycodeProvider(), static function (array $data): bool { + return mb_strlen($data[1], 'utf-8') > 10; + }); + } + + /** + * @dataProvider encodeMaxLengthDataProvider + */ + public function testEncodeMaxLength(string $decoded, string $encoded, string $comment): void + { + $this->expectException(OutputSizeExceededException::class); + Punycode::encode($decoded, 10); + } + + /** + * @return array> + */ + public function decodeMaxLengthDataProvider(): array + { + return array_filter($this->punycodeProvider(), static function (array $data): bool { + return mb_strlen($data[0], 'utf-8') > 10; + }); + } + + /** + * @dataProvider decodeMaxLengthDataProvider + */ + public function testDecodeMaxLength(string $decoded, string $encoded, string $comment): void + { + $this->expectException(OutputSizeExceededException::class); + Punycode::decode($encoded, 10); + } + + /** + * @return array> + */ + public function nonAsciiDataProvider(): array + { + return array_filter($this->punycodeProvider(), static function (array $data): bool { + return preg_match('/[^\x00-\x7F]/', $data[0]) === 1; + }) + [ + ["abc\u{FFFD}", '', 'Mixed ASCII and non-ASCII'] + ]; + } + + /** + * @dataProvider nonAsciiDataProvider + */ + public function testDecodeOnlyAcceptsAscii(string $decoded, string $encoded, string $comment): void + { + $this->expectException(InvalidInputException::class); + Punycode::decode($decoded); + } + + public function testCaseFlags(): void + { + $c = [true, true, true]; + $e = Punycode::encode('abc', null, $c); + self::assertSame('ABC-', $e); + + $c = [false, false, false]; + $d = Punycode::decode($e, null, $c); + self::assertSame([true, true, true], $c); + self::assertSame('ABC', $d); + + $c = []; + $d = Punycode::decode($e, null, $c); + self::assertSame([true, true, true], $c); + self::assertSame('ABC', $d); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/.github/workflows/coverage.yml b/transfer-protocol/vendor/rowbot/url/.github/workflows/coverage.yml new file mode 100644 index 0000000..5815511 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/.github/workflows/coverage.yml @@ -0,0 +1,57 @@ +name: Code Coverage +on: + push: + paths-ignore: + - '**.md' + + pull_request: + paths-ignore: + - '**.md' + +jobs: + coverage: + name: PHP ${{ matrix.php }} on ${{ matrix.os }} ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + container: shivammathur/node:latest-${{ matrix.arch }} + defaults: + run: + shell: bash + strategy: + fail-fast: true + matrix: + os: + - ubuntu-latest + arch: + - amd64 + - i386 + php: + - 8.1 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, opcache, pcre, gmp + coverage: pcov + env: + fail-fast: true + + - name: Install dependencies + run: composer update --no-interaction + + - name: Generate Coverage + run: | + mkdir -p ./build/coverage/ + vendor/bin/phpunit --coverage-clover ./build/coverage/clover.xml + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + if: ${{ !env.ACT }} + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./build/coverage/clover.xml + name: PHP ${{ matrix.php }} on ${{ matrix.os }} ${{ matrix.arch }} diff --git a/transfer-protocol/vendor/rowbot/url/.github/workflows/tests.yml b/transfer-protocol/vendor/rowbot/url/.github/workflows/tests.yml new file mode 100644 index 0000000..bd29c26 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/.github/workflows/tests.yml @@ -0,0 +1,70 @@ +name: Test URL +on: + push: + paths-ignore: + - '**.md' + + pull_request: + paths-ignore: + - '**.md' + +jobs: + test: + name: PHP ${{ matrix.php }} ${{ matrix.php-jit == 'on' && 'with' || 'without' }} JIT on ${{ matrix.os }} ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + container: shivammathur/node:latest-${{ matrix.arch }} + continue-on-error: ${{ matrix.php == 'nightly' }} + defaults: + run: + shell: bash + strategy: + fail-fast: true + matrix: + os: + - ubuntu-latest + arch: + - amd64 + - i386 + php: + - 8.1 + - 8.2 + - 8.3 + php-jit: + - on + - off + include: + - php: nightly + os: ubuntu-latest + arch: amd64 + php-jit: on + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, opcache, pcre, gmp + ini-values: zend.assertions=1, opcache.enable_cli=1, opcache.memory_consumption=256, opcache.jit=${{ matrix.php-jit == 'on' && 1255 || 'disable' }}, opcache.jit_buffer_size=${{ matrix.php-jit == 'on' && '256M' || '0' }} + coverage: none + env: + fail-fast: true + + - name: Install dependencies + run: | + if [[ ${{ matrix.php == 'nightly' }} ]]; then + composer update --no-interaction --ignore-platform-reqs + else + composer update --no-interaction + fi + + - name: Run PHPCS + run: vendor/bin/phpcs + + - name: Run PHPStan + run: vendor/bin/phpstan + + - name: Run Tests + run: vendor/bin/phpunit diff --git a/transfer-protocol/vendor/rowbot/url/.gitignore b/transfer-protocol/vendor/rowbot/url/.gitignore new file mode 100644 index 0000000..a8f6aa1 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/.gitignore @@ -0,0 +1,6 @@ +/vendor/ +/composer.lock +.vscode +/build/ +/tests/WhatWg/data/ +/.phpunit.cache/ diff --git a/transfer-protocol/vendor/rowbot/url/.phpcs.xml b/transfer-protocol/vendor/rowbot/url/.phpcs.xml new file mode 100644 index 0000000..3a17c01 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/.phpcs.xml @@ -0,0 +1,199 @@ + + + src + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/transfer-protocol/vendor/rowbot/url/CHANGELOG.md b/transfer-protocol/vendor/rowbot/url/CHANGELOG.md new file mode 100644 index 0000000..0a9c9ee --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/CHANGELOG.md @@ -0,0 +1,302 @@ +# Changelog + +## [Unreleased] + +## [4.0.0] - 2024-06-20 + +### Added + +- Performance improvements +- Validation error logging +- `\Rowbot\URL\URL` and `\Rowbot\URL\URLSearchParams` now implement `\Stringable` +- `\Rowbot\URL\URLSearchParams` constructor now has a native typehint of `array|object|string` +- `\Rowbot\URL\URLSearchParams` now has a `size` getter per [whatwg/url#734](https://github.com/whatwg/url/pull/734) + - `\Rowbot\URL\URLSearchParams` now also implements `\Countable` +- Added `\Rowbot\URL\URL::canParse()`, which returns a boolean if parsing was successful, per [whatwg/url#713](https://github.com/whatwg/url/issues/713) and [whatwg/url#763](https://github.com/whatwg/url/pull/763) +- Add value parameter to `\Rowbot\URL\URLSearchParams::has()` and `\Rowbot\URL\URLSearchParams::delete()` per [whatwg/url#335](https://github.com/whatwg/url/issues/335) and [whatwg/url#735](https://github.com/whatwg/url/pull/735) +- Added `\Rowbot\URL\URL::parse()`, which will return the parsed URL or null on failure, avoiding needing a `try` statement per [whatwg/url#372](https://github.com/whatwg/url/issues/372) and [whatwg/url#825](https://github.com/whatwg/url/pull/825) + +### Changed + +- Bump minimum PHP version to 8.1 +- Lone surrogate code points are no longer treated differently from other invalid code points +- `\Rowbot\URL\String\Exception\UConverterException` has been renamed to `\Rowbot\URL\String\Exception\EncodingException` +- Moved 32-bit tests to GitHub Actions from Appveyor +- `\Rowbot\URL\URL`'s $url and $base parameters now also accept `\Stringable` +- `\Rowbot\URL\URLSearchParams::current()` now returns `null` when the iterator is invalid instead of `['', '']`, which better matches the expected behavior +- Ensure opaque paths can round trip from the API [whatwg/url#651](https://github.com/whatwg/url/issues/651) [whatwg/url#728](https://github.com/whatwg/url/pull/728) +- Blob URL's with an inner non-http(s) URL now returns an opaque origin per [whatwg/url#770](https://github.com/whatwg/url/issues/770) and [whatwg/url#771](https://github.com/whatwg/url/pull/771) + +### Removed + +- Removed `\Rowbot\URL\Exception\JsonException` in favor of `\JsonException` + +### Internals + +- Removed class `\Rowbot\URL\String\IDLString` +- Added method `\Rowbot\URL\String\Utf8String::scrub()` +- Added method `\Rowbot\URL\String\Utf8String::fromUnsafe()` +- Moved method `\Rowbot\URL\String\AbstractUSVString::transcode()` to `\Rowbot\URL\String\Utf8String` +- Removed method `\Rowbot\URL\String\Exception\RegexException::getNameFromLastCode()` +- All objects with a `__toString()` method now implement `\Stringable` +- Added native union typehints where possible +- `\Rowbot\URL\Origin` is now an interface + - Added class `\Rowbot\URL\Component\TupleOrigin` which implements `\Rowbot\URL\Origin` + - Added class `\Rowbot\URL\Component\OpaqueOrigin` which implements `\Rowbot\URL\Origin` +- `\Rowbot\URL\Component\PathListInterface` renamed to `\Rowbot\URL\PathInterface` + - Added class `\Rowbot\URL\Component\OpaquePath` which implements `\Rowbot\URL\PathInterface` +- `\Rowbot\URL\Component\Path` was renamed to `\Rowbot\URL\Component\PathSegment` +- `\Rowbot\URL\State\CannotBeABaseUrlPathState` was renamed to `\Rowbot\URL\State\OpaquePathState` + - Removed property `\Rowbot\URL\URLRecord::$cannotBeABaseUrl` +- Adopted the specs new percent encoding model + - Removed const `\Rowbot\URL\String\CodePoint::C0_CONTROL_PERCENT_ENCODE_SET` + - Removed const `\Rowbot\URL\String\CodePoint::FRAGMENT_PERCENT_ENCODE_SET` + - Removed const `\Rowbot\URL\String\CodePoint::PATH_PERCENT_ENCODE_SET` + - Removed const `\Rowbot\URL\String\CodePoint::USERINFO_PERCENT_ENCODE_SET` + - Removed method `\Rowbot\URL\String\CodePoint::utf8PercentEncode()` + - Added enum `\Rowbot\URL\String\EncodeSet` + - Added class `\Rowbot\URL\String\PercentEncoder` + - `\Rowbot\URL\Component\Host\HostParser` methods are no longer static +- `\Rowbot\URL\String\StringListInterface` extends `\IteratorAggregate` instead of `\Iterator` +- `\Rowbot\URL\Component\QueryList` now implements `\Countable` +- Added enum `\Rowbot\URL\State\StatusCode` + - `\Rowbot\URL\State\State` now has a return type of `\Rowbot\URL\State\StatusCode` instead of `int` + - Removed const `\Rowbot\URL\State\State::RETURN_OK` + - Removed const `\Rowbot\URL\State\State::RETURN_CONTINUE` + - Removed const `\Rowbot\URL\State\State::RETURN_BREAK` + - Removed const `\Rowbot\URL\State\State::RETURN_FAILURE` + +## [3.1.7] - 2022-08-26 + +### Fixed + +- Detection of windows drive letters + +## [3.1.6] - 2022-08-16 + +### Changed + +- Forbid C0 control code points and U+007F DEL code point in non-opaque domain names per [whatwg/url#685](https://github.com/whatwg/url/pull/685) + +## Fixed + +- Fix parsing IPv4-mapped IPv6 addresses due to wrong logical condition + +## [3.1.5] - 2022-01-10 + +### Changed + + - Upgraded to PHPStan 1.0 + +### Fixed + +- Initialization of `URLSearchParams` using an object now behaves the same as when using and iterator or string + +## [3.1.4] - 2021-07-27 + +### Added + +- Support for PHP 8.1 + +### Changed + +- Make the `URL::$hostname` setter do nothing if the host name contains a ":" per [whatwg/url#601](https://github.com/whatwg/url/issues/601) [whatwg/url#604](https://github.com/whatwg/url/pull/604) +- Reject non-IPv4 hostnames that end in numbers per [whatwg/url#560](https://github.com/whatwg/url/issues/560) [whatwg/url#619](https://github.com/whatwg/url/pull/619) + +### Fixed + +- Prevent the pathname setter from erasing the path of path-only URLs [whatwg/url#581](https://github.com/whatwg/url/issues/581) [whatwg/url#582](https://github.com/whatwg/url/pull/582) + +## [3.1.3] - 2021-05-11 + +### Fixed + +- File URL reparse bug with percent encoded windows drive letter [whatwg/url#589](https://github.com/whatwg/url/pull/589) + +### Changed + +- Switched to GitHub Actions for CI +- Minimum PHPUnit version is now 7.5 + +## [3.1.2] - 2021-02-11 + +### Added + +- Performance improvements +- Test on PHP 8 release in CI + +## [3.1.1] - 2020-10-17 + +### Added + +- Support for `brick/math` ^0.9 + +### Changed + +- Serializing non-special URLs is now idempotent per [whatwg/url#505](https://github.com/whatwg/url/pull/505) +- Changes to file URL path normalization per [whatwg/url#544](https://github.com/whatwg/url/pull/544). + +## [3.1.0] - 2020-07-15 + +### Added + +- Added test coverage on Windows 32-bit. +- Dependency on `rowbot/idna` to support international domain names without `ext-intl`. + +### Changed + +- `URLSearchParams::sort()` now correctly sorts by code units instead of trying to fake it using code points. +- Null bytes are now percent encoded in fragments instead of being ignored per [whatwg/url#440](https://github.com/whatwg/url/issues/440). +- Domain names of URLs with special schemes can no longer be an empty string per [whatwg/url#492](https://github.com/whatwg/url/pull/492) and [whatwg/url#497](https://github.com/whatwg/url/pull/497). +- Host names now also forbid the use of the `<`, `>`, and `^` code points per [whatwg/url#458](https://github.com/whatwg/url/issues/458). + +### Fixed + +- Incorrect output encoding used when encoding was overriden to be "replacement", "utf-16", "utf-16le", or "utf-16be". +- `ext-json` is now correctly listed as a dependency. + +### Removed + +- Dependency on `ext-intl` and `lib-ICU`. + +## [3.0.1] - 2020-02-29 + +### Added + +- Improved portability and 32-bit PHP support. +- Dependency on `brick/math` to support 32-bit versions of PHP. + +### Removed + +- Removed `ext-gmp` as a dependency. + +## [3.0.0] - 2020-02-11 + +The majority of this library was rewritten in this update, but the public API has remain unchanged. This should make for a relatively painless upgrade. + +### Added + +- Installation requirement of ICU >= 4.6 to assist with [#6](https://github.com/TRowbotham/URL-Parser/issues/6) +- Support for PHPUnit ^8.0 and ^9.0. +- More test coverage. +- Support for symfony/cache ^5.0. + +### Changed + +- "gopher" was removed from the list of special schemes per [whatwg/url#453](https://github.com/whatwg/url/pull/453) and [whatwg/url#454](https://github.com/whatwg/url/pull/454). +- Coding style has been updated for PSR-12. +- Non-iterable objects passed to the `URLSearchParams` constructor now have their properties iterated over using `\ReflectionObject::getProperties()` rather than directly. There should not be any change in behavior. +- Removed artificial limitation when passing a sequence of sequences to the `URLSearchParams` constructor that required the non-array sub-sequences to implement the `\ArrayAccess` interface. + - Note that sub-sequences must still be countable and only contain exactly 2 items. + - This broadens the type of sequences that can be supplied from `iterable` to `iterable>`, where `stringable` is a scalar value or an object with the `__toString()` method. +- `URLSearchParams` now throws a `\Rowbot\URL\Exception\TypeError` instead of a `\InvalidArgument` exception to match browsers when passed an iterable that does not solely contain other iterables that are countable. +- JSON encoding the `URL` object will now throw a `\Rowbot\URL\Exception\JsonException` when JSON encoding fails. + +### Fixed + +- Documentaion errors. +- Restores expected string conversion behavior on systems using an ICU version >= 60.1 ([#7](https://github.com/TRowbotham/URL-Parser/issues/6)). +- `Origin::getEffectiveDomain()` was incorrectly returning the string `"null"` instead of the actual value `null` when the origin was an opaque origin. + +### Removed + +- `phpstan/phpstan` and associated packages are no longer a dev dependency and is now only run in CI. +- No longer depends on `ext-ctype`, which was an unlisted dependency. +- `php-coveralls/php-coveralls` is no longer a dev dependency. The project has moved to Codecov instead. +- `squizlabs/php_codesniffer` is no longer a dev dependency and is only run in CI now. + +## [2.0.3] - 2019-08-13 + +### Fixed + +- "%2e%2E" and "%2E%2e" were not properly detected as percent encoded double dot path segments. + +## [2.0.2] - 2019-04-28 + +### Added + +- PHP 7.4 compatibility +- Sped up IPv6 address serialization by removing some unncessary type casting. + +## [2.0.1] - 2019-04-15 + +### Fixed + +- Loading cached test data failed when using newer versions of the symfony/cache component. + +## [2.0.0] - 2018-12-08 + +### Added + +- Tests now automatically pull the latest data directly from the Web Platform Tests repository - thanks [@nyamsprod](https://github.com/nyamsprod) + +### Changed + +- The minimum required PHP version is now 7.1. +- Testing environment updated for PHP 7.1 - thanks [@nyamsprod](https://github.com/nyamsprod) +- Native typehints are now used. This which means that an `\TypeError` is now thrown instead of an `\InvalidArgumentException` when a value with an incorrect type is passed. +- `\Rowbot\URL\Exception\TypeError` and `\Rowbot\URL\Exception\InvalidParserState` now inherit from `\Rowbot\URL\Exception\URLException` + +## [1.1.1] - 2018-08-15 + +### Added + +- Sped up `URLSearchParams::has()` when the string does not exist in the list. +- TravisCI automation for tests and code coverage. + +### Fixed + +- The query string sorting algorithm now correctly sorts by code units instead of code points. + +## [1.1.0] - 2018-06-21 + +### Added + +- Updated documentation +- Updated tests + +### Changed + +- Only scalar values (bool, float, int, string) and objects with a `__toString()` method are considered as valid input now for methods and properties that only accept strings. This matches what PHP's string type hint would allow, allowing for an easier upgrade path when adding native type hints in the future. + - A `null` value is no longer considered valid input and will cause an `\InvalidArgumentException` to be thrown. Previously, this was converted to the string `"null"`. + - A `resource` value such as that returned by a call to `fopen()` is no longer considered valid input and will cause an `\InvalidArgumentException` to be thrown. This was previously casted to a string resulting in something like `"Resource id #1"`. + - Previously, the values `true` and `false` were converted to the strings `"true"` and `"false"`. This is no longer the case. They now are now simply cast to a string resulting in the values `"1"` and `""` respectively. +- Passing an `iterable` that does not solely contain other `iterables` to the `URLSearchParams` constructor now causes it to throw an `\InvalidArgumentException`. +- Trying to access an invalid property on the `URL` object will now throw an `\InvalidArgumentException` to help catch typos. + +## [1.0.3] - 2018-06-19 + +### Added + +- Sped up serialization of IPv6 addresses +- Slightly better handling of non-UTF-8 encoded text when parsing query strings. +- A bunch of missing `use` import statements +- Updated tests and test data. + +### Changed + +- URLs with [special schemes](https://url.spec.whatwg.org/#special-scheme) now percent encode `'` characters in the query string. +- The application/x-www-form-urlencoded parser now only handles UTF-8 encoded text. + +## [1.0.2] - 2018-02-28 + +### Changed + +- Trying to set `URL::searchParams` directly will now throw a `\Rowbot\URL\Exception\TypeError` +- Passing invalid input will throw an `\InvalidArgumentException` +- Malformed byte sequences will now get fixed up with `\u{FFFD}` replacement characters. +- `URLSearchParams` now implements `\Iterator` instead of `\IteratorAggregate` to match test expectations. + +### Fixed + +- The last few failing tests are now passing with the exception of 3 errors as a result of PHP bug [72506](https://bugs.php.net/bug.php?id=72506) + +## [1.0.1] - 2018-02-22 + +### Added + +- MIT License + +## [1.0.0] - 2018-02-22 + +- Initial Release! diff --git a/transfer-protocol/vendor/rowbot/url/LICENSE b/transfer-protocol/vendor/rowbot/url/LICENSE new file mode 100644 index 0000000..34196ce --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Trevor Rowbotham + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/transfer-protocol/vendor/rowbot/url/README.md b/transfer-protocol/vendor/rowbot/url/README.md new file mode 100644 index 0000000..5afa1d5 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/README.md @@ -0,0 +1,254 @@ +# URL-Parser + +[![GitHub](https://img.shields.io/github/license/TRowbotham/URL-Parser.svg?style=flat-square)](https://github.com/TRowbotham/URL-Parser/blob/master/LICENSE) +[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/TRowbotham/URL-Parser/tests.yml?branch=master&style=flat-square)](https://github.com/TRowbotham/URL-Parser/actions) +[![Codecov](https://img.shields.io/codecov/c/github/TRowbotham/URL-Parser/master?logo=Codecov&style=flat-square&token=WDWFg8wmjW)](https://codecov.io/gh/TRowbotham/URL-Parser) +[![Packagist](https://img.shields.io/packagist/v/rowbot/url.svg?style=flat-square)](https://packagist.org/packages/rowbot/url) +[![Packagist](https://img.shields.io/packagist/dt/rowbot/url.svg?style=flat-square)](https://packagist.org/packages/rowbot/url) + +A [WHATWG URL](https://url.spec.whatwg.org/) spec compliant URL parser for working with URLs and their query strings. + +This API offers 2 objects that you can use to help you work with URLs; [URL](#url) and [URLSearchParams](#urlsearchparams). +## Demo + +Checkout an interactive demo [here](https://url-demo.trowbotham.com/). + +## Requirements + +* PHP >= 8.1 +* `ext-mbstring` +* `brick/math` +* `rowbot/idna` + +## Installation + +```bash +composer require rowbot/url +``` + +## URL + +The URL object is the primary object for working with a URL. + +### The URL constructor + +`URL(string|\Stringable $url[, null|string|\Stringable $base = null, array $options = []])` + +The `$options` argument accepts an array with a key `logger` whose value is an object implementing +`\Psr\Log\LoggerInterface`. See [Logging](#logging) for more information. + +#### URL constructor throws + +* `\Rowbot\URL\Exception\TypeError` + * When the URL parser determines that the given input is not a valid URL. + +```php +use Rowbot\URL\URL; + +// Construct a new URL object. +$url = new URL('https://example.com/'); + +// Construct a new URL object using a relative URL, by also providing the constructor with the base URL. +$url = new URL('path/to/file.php?query=string', 'http://example.com'); +echo $url->href; // Outputs: "http://example.com/path/to/file.php?query=string" + +// You can also pass an existing URL object to either the $url or $base arguments. +$url = new URL('https://example.org:123'); +$url1 = new URL('foo/bar/', $url); +echo $url1->href; // Outputs: "https://example.org:123/foo/bar/" + +// Catch the error when URL parsing fails. +try { + $url = new URL('http://2001::1]'); +} catch (\Rowbot\URL\Exception\TypeError $e) { + echo 'Invalid URL'; +} +``` + +### URL Members + +Note: As a convience, both the `__get()` and `__set()` methods will throw an `\InvalidArgumentException` if you try to get or set an invalid property. + +#### `string URL::href` + +The `href` getter returns the serialization of the URL. The `href` setter will parse the entire string +updating all the components of the URL with the new values. Providing an invalid URL will cause the +setter to throw a `\Rowbot\URL\TypeError`. + +#### `readonly string URL::origin` + +The `origin` member is readonly. Its output is in the form of `scheme://host:port`. If a URL does not +have a port, then that will be excluded from the output. + +#### `string URL::protocol` + +The `protocol` getter, also known as a scheme, returns the protocol of the URL, such as http, ftp, or ssh. +The `protocol` setter is used to change the URLs protocol. + +#### `string URL::username` + +The `username` getter returns the username portion of the URL, or an empty string if the URL does not contain a username. The `username` setter changes the URLs username. + +#### `string URL::password` + +The `password` getter returns the password portion of the URL, or an empty string if the URL does not contain a password. The `password` setter changes the URLs password. + +#### `string URL::host` + +The `host` getter returns the combination of `hostname` and `port`. The output would look like `hostname:port`. If the URL does not have a port, then the port is not present in the output. The `host` setter allows you to change both the `hostname` and `port` at the same time. + +#### `string URL::hostname` + +The `hostname` getter returns the hostname of the URL. For example, the hostname of `https://example.com:31` would be `example.com`. The `hostname` setter will change the hostname portion of the URL. + +#### `string URL::port` + +The `port` getter returns an integer as a string representing the URLs port. If the URL does not have a port, the empty string will be returned instead. The `port` setter updates the URLs port. + +#### `string URL::pathname` + +The `pathname` getter returns the URLs path. The `pathname` setter updates the URLs path. + +#### `string URL::search` + +The `search` getter returns the URLs query string. The `search` setter updates the URLs URLSearchParams list. + +#### `readonly URLSearchParams URL::searchParams` + +Returns the URLSearchParams object associated with this URL allowing you to modify the query parameters without having to clobber the entire query string. This will always return the same object. + +#### `string URL::hash` + +The `hash` getter, also known as a URLs fragment, returns the portion of the URL that follows the "#" character. The `hash` setter updates the portion of the URL that follows the "#". + +#### `bool URL::canParse(string|\Stringable $url[, null|string|\Stringable $base = null])` + +A static method that allows the user to quickly check if a URL is parsable, without needing to construct a new URL object and wrapping it with a try/catch statement. + +#### `string URL::toJSON()` + +Returns a JSON encoded string of the URL. Note that this method escapes forward slashes, which is not the default for PHPs `json_encode()`, but matches the default behavior of JavaScripts `JSON.stringify()`. If you wish to control the serialization, then pass the URL obect to the `json_encode()` function. + +#### `string URL::jsonSerialize()` + +The URL object implements the `JsonSerializable` interface allowing you to pass the object as a whole to the json_encode() function. + +#### `string URL::toString()` + +Returns the serialization of the URL. + +#### `string URL::__toString()` + +See [URL::toString()](#string-urltostring) + +## URLSearchParams + +The URLSearchParams object allows you to work with query strings when you don't need a full URL. The URLSearchParams object implements the `Iterator` interface so that you may iterate over the list of search parameters. The iterator will return an array containing exactly 2 items. The first item is the parameter name and the second item is the parameter value. + +### The URLSearchParams constructor + +`URLSearchParams([iterable|(\Traversable&\Countable)>|object|string|\Stringable $init])` + +#### URLSearchParams constructor throws + +* `\Rowbot\URL\Exception\TypeError` + * When an iterable is passed and one if its values is not iterable. + * When an iterable is passed and one of its values is not countable, such as an object that implements `\Iterator`, but not `\Countable`. + * When an iterable is passed and one of its sequences does not contain exactly 2 items, such as an array that contains only 1 string. + +```php +use Rowbot\URL\URLSearchParams; + +// Construct an empty list of search params. +$params = new URLSearchParams(); + +// Construct a new list from a query string. Remember that a leading "?" will be stripped. +$params = new URLSearchParams('?foo=bar'); + +// Construct a new list using an array of arrays containing strings. Alternatively, you could pass an +// object that implements the Traversable interface and whose iterator returns an array of arrays, +// with each array containing exactly 2 items. +$params = new URLSearchParams([ + ['foo', 'bar'], + ['foo', 'bar'] // Duplicates are allowed! + ['one', 'two'] +]); + +// Iterate over a URLSearchParams object. +foreach ($params as $index => $param) { + if ($index > 0) { + echo '&'; + } + + echo $param[0] . '=' . $param[1]; +} + +// Above loop prints "foo=bar&foo=bar&one=two". + +// Construct a new list using an object +$obj = new \stdClass(); +$obj->foo = 'bar'; +$params = new URLSearchParams($obj); + +// Copy an existing URLSearchParams object into a new one. +$params1 = new URLSearchParams($params); +``` + +### URLSearchParams Members + +#### `void URLSearchParams::append(string $name, string $value)` + +Appends a new name-value pair to the list. + +#### `void URLSearchParams::delete(string $name[, string $value])` + +Deletes all name-value pairs whose name is `$name` from the list. If the optional `$value` is provided, +then only pairs with the same name and value are removed. + +#### `string|null URLSearchParams::get(string $name)` + +Returns the value of the first name-value pair whose name is `$name` in the list or null if there are no name-value pairs whose name is `$name` in the list. + +#### `string[] URLSearchParams::getAll(string $name)` + +Returns a list of values of all name-value pairs whose name is `$name`, in list order, or the empty list if there are no name-value pairs whose name is `$name` in the list. + +#### `bool URLSearchParams::has(string $name[, string $value])` + +Returns true if there is a name-value pair in the list, and false otherwise. + +#### `void URLSearchParams::set(string $name, string $value)` + +If the list contains name-value pairs whose name is `$name`, the first name-value pair in the list whose name is `$name` will have its value changed to `$value` and all others following it in the list will be removed. If the list does not contain a name-value pair whose name is `$name` then the new name-value pair will be appended to the list. + +#### `void URLSearchParams::sort()` + +Sorts the list of search params by comparing code units. The relative order of name-value pairs with the same name are preserved. + +#### `string URLSearchParams::toString()` + +Returns the serialization of the list of name-value pairs. + +### `int URLSearchParams::$size` + +Returns the number of query parameters in the list. + +#### `string URLSearchParams::__toString()` + +See [URLSearchParams::toString()](#string-urlsearchparamstostring) + +## Logging + +The given logger logs validation errors. Entries with a level of `warning` are fatal errors that cause the parser to +fail. Entries with a level of `notice` are not fatal. All validation errors have an `input` key and either a `column` +or `column_range` offset key. Column offsets start at 1. + +### Logging context + +| Key | Type | Description | +|-----|------|-------------| +| `input` | `string` | The input string that the parser is operating on at the time of error. | +| `column` | `positive-int` | The column offset of the error. | +| `column_range` | `array{0: positive-int, 1: positive-int}` | Index 0 is the starting column offset, and index 1 is the end column offset. The range is inclusive. | +| `idn_errors` | `list` | A list of strings that represent IDN error constant names. | +| `unicode_domain` | `string` | The domain name as a Unicode string. | diff --git a/transfer-protocol/vendor/rowbot/url/composer.json b/transfer-protocol/vendor/rowbot/url/composer.json new file mode 100644 index 0000000..dc85465 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/composer.json @@ -0,0 +1,52 @@ +{ + "name": "rowbot/url", + "description": "A WHATWG URL spec compliant URL parser for working with URLs and their query strings.", + "keywords": ["url", "url-parser", "uri", "querystring", "query-string", "url-parsing", "whatwg"], + "license": "MIT", + "authors": [ + { + "name": "Trevor Rowbotham", + "homepage": "https://trowbotham.com", + "role": "Developer" + } + ], + "require": { + "php": ">=8.1", + "ext-mbstring": "*", + "brick/math": "^0.8.13 || ^0.9", + "psr/log": "^3.0", + "rowbot/idna": "^0.1.5" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.0", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^10.0 || ^11.0", + "slevomat/coding-standard": "^8.0", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/cache": "^5.0 || ^6.0" + }, + "autoload": { + "psr-4": { + "Rowbot\\URL\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Rowbot\\URL\\Tests\\": "tests/" + } + }, + "scripts": { + "phpunit": "phpunit --coverage-text", + "test": [ + "@phpunit" + ] + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/transfer-protocol/vendor/rowbot/url/phpstan.neon b/transfer-protocol/vendor/rowbot/url/phpstan.neon new file mode 100644 index 0000000..d25b910 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/phpstan.neon @@ -0,0 +1,23 @@ +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + +parameters: + level: max + treatPhpDocTypesAsCertain: false + + paths: + - src + + ignoreErrors: + - + message: '#Call to function is_object\(\) with object will always evaluate to true\.#' + path: src/URLSearchParams.php + count: 1 + + - + message: '#Cannot use array destructuring on Countable&iterable\.#' + path: src/URLSearchParams.php + count: 1 + + # Note to self: You can't escape single quotes in neon. Another possible alternative would be to replace single quotes with \x27. diff --git a/transfer-protocol/vendor/rowbot/url/phpunit.xml b/transfer-protocol/vendor/rowbot/url/phpunit.xml new file mode 100644 index 0000000..d17d5f3 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/phpunit.xml @@ -0,0 +1,19 @@ + + + + + ./src + + + + + ./tests + + + diff --git a/transfer-protocol/vendor/rowbot/url/src/APIParserErrorType.php b/transfer-protocol/vendor/rowbot/url/src/APIParserErrorType.php new file mode 100644 index 0000000..91e7f11 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/APIParserErrorType.php @@ -0,0 +1,14 @@ +url = $urlRecord; + $this->error = $error; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/BasicURLParser.php b/transfer-protocol/vendor/rowbot/url/src/BasicURLParser.php new file mode 100644 index 0000000..60f3dbd --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/BasicURLParser.php @@ -0,0 +1,135 @@ +logger = $logger; + } + + /** + * The parser can parse both absolute and relative URLs. If a relative URL is given, a base URL must also be given + * so that an absolute URL can be resolved. It can also parse individual parts of a URL when the default starting + * state is overridden, however, a previously parsed URL record object must be provided in this case. + * + * @see https://url.spec.whatwg.org/#concept-basic-url-parser + * + * @param \Rowbot\URL\String\USVStringInterface $input A UTF-8 encoded string consisting of only scalar + * values, excluding surrogates. + * @param \Rowbot\URL\URLRecord|null $base (optional) This represents the base URL, which in + * most cases, is the document's URL, it may also be + * a node's base URI or whatever base URL you wish to + * resolve relative URLs against. Default is null. + * @param string|null $encodingOverride (optional) Overrides the default ouput encoding, + * which is UTF-8. This option exists solely for the + * use of the HTML specification and should never be + * changed. + * @param \Rowbot\URL\URLRecord|null $url (optional) This represents an existing URL record + * object that should be modified based on the input + * URL and optional base URL. Default is null. + * @param \Rowbot\URL\ParserState|null $stateOverride (optional) An object implementing the + * \Rowbot\URL\ParserState interface that overrides + * the default start state, which is the Scheme Start + * State. Default is null. + */ + public function parse( + USVStringInterface $input, + ?URLRecord $base = null, + ?string $encodingOverride = null, + ?URLRecord $url = null, + ?ParserState $stateOverride = null + ): URLRecord|false { + $count = 0; + + if ($url === null) { + $url = new URLRecord(); + $originalInput = $input; + $input = $input->replaceRegex('/^[\x00-\x20]+|[\x00-\x20]+$/u', '', -1, $count); + + if ($count !== 0) { + // Validation error. + $this->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $originalInput, + 'column_range' => (static function () use ($originalInput): array { + $originalInput->matches('/^[\x00-\x20]+|[\x00-\x20]+$/u', $matches, PREG_OFFSET_CAPTURE); + + if ($matches[0][1] === 0) { + return [1, strlen($matches[0][0])]; + } + + return [$originalInput->length() - strlen($matches[0][0]) + 1, $originalInput->length()]; + })(), + ]); + } + } + + $originalInput = $input; + $input = $input->replaceRegex('/[\x09\x0A\x0D]+/u', '', -1, $count); + + if ($count !== 0) { + // Validation error. + $this->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $originalInput, + 'column_range' => (static function () use ($originalInput): array { + $originalInput->matches('/[\x09\x0A\x0D]+/u', $matches, PREG_OFFSET_CAPTURE); + $start = mb_strlen(substr((string) $originalInput, 0, $matches[0][1]), 'utf-8'); + + return [$start + 1, $start + strlen($matches[0][0])]; + })(), + ]); + } + + $iter = $input->getIterator(); + $iter->rewind(); + // length + imaginary eof character + $length = $input->length() + 1; + $buffer = new StringBuffer(); + $context = new ParserContext( + $input, + $iter, + $buffer, + $url, + $base, + $stateOverride, + $encodingOverride, + $this->logger + ); + + do { + $handler = ParserState::createHandlerFor($context->state); + $status = $handler->handle($context, $iter->current()); + + if ($status === StatusCode::CONTINUE) { + $status = StatusCode::OK; + + continue; + } + + $iter->next(); + } while ($status === StatusCode::OK && $iter->key() < $length); + + return match ($status) { + StatusCode::FAILURE => false, + default => $url, + }; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/AbstractPath.php b/transfer-protocol/vendor/rowbot/url/src/Component/AbstractPath.php new file mode 100644 index 0000000..648f0f2 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/AbstractPath.php @@ -0,0 +1,69 @@ + + */ + protected array $list; + + /** + * @param list<\Rowbot\URL\Component\PathSegment> $paths + */ + public function __construct(array $paths = []) + { + $this->list = $paths; + } + + public function count(): int + { + return count($this->list); + } + + public function first(): PathSegment + { + return $this->list[0] ?? throw new UndefinedIndexException(); + } + + public function isEmpty(): bool + { + return $this->list === []; + } + + public function potentiallyStripTrailingSpaces(URLRecord $url): void + { + if (!$this->isOpaque()) { + return; + } + + if ($url->fragment !== null) { + return; + } + + if ($url->query !== null) { + return; + } + + $this->list[0]->stripTrailingSpaces(); + } + + public function __clone() + { + $list = []; + + foreach ($this->list as $path) { + $list[] = clone $path; + } + + $this->list = $list; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/AbstractHost.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/AbstractHost.php new file mode 100644 index 0000000..c9e38df --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/AbstractHost.php @@ -0,0 +1,23 @@ +?@[\\\\\]^|'; + private const FORBIDDEN_DOMAIN_CODEPOINTS = self::FORBIDDEN_HOST_CODEPOINTS . '\x01-\x1F%\x7F'; + + private const UNICODE_IDNA_OPTIONS = [ + 'CheckHyphens' => false, + 'CheckBidi' => true, + 'CheckJoiners' => true, + 'UseSTD3ASCIIRules' => false, + 'Transitional_Processing' => false, + ]; + + /** + * Parses a host string. The string could represent a domain, IPv4 or IPv6 address, or an opaque host. + * + * @param bool $isOpaque (optional) Whether or not the URL has a special scheme. + * + * @return \Rowbot\URL\Component\Host\HostInterface|false The returned Host can never be a null host. + */ + public function parse( + ParserContext $context, + USVStringInterface $input, + bool $isOpaque = false + ): HostInterface|false { + if ($input->startsWith('[')) { + if (!$input->endsWith(']')) { + // Validation error. + $context->logger?->warning('IPv6-unclosed', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 2, + ]); + + return false; + } + + return IPv6AddressParser::parse($context, $input->substr(1, -1)); + } + + if ($isOpaque) { + return $this->parseOpaqueHost($context, $input); + } + + assert(!$input->isEmpty()); + $domain = rawurldecode((string) $input); + $asciiDomain = $this->domainToAscii($context, $domain, false); + + if ($asciiDomain === false) { + return false; + } + + if ($asciiDomain->matches('/[' . self::FORBIDDEN_DOMAIN_CODEPOINTS . ']/u', $matches, PREG_OFFSET_CAPTURE)) { + // Validation error. + $context->logger?->warning('domain-invalid-code-point', [ + 'input' => (string) $asciiDomain, + 'column' => mb_strlen(mb_strcut((string) $asciiDomain, 0, $matches[0][1], 'utf-8'), 'utf-8') + 1, + 'unicode_domain' => Idna::toUnicode((string) $asciiDomain, self::UNICODE_IDNA_OPTIONS)->getDomain(), + ]); + + return false; + } + + if (IPv4AddressParser::endsInIPv4Number($asciiDomain)) { + return IPv4AddressParser::parse($context, $asciiDomain); + } + + return $asciiDomain; + } + + /** + * @see https://url.spec.whatwg.org/#concept-domain-to-ascii + */ + private function domainToAscii(ParserContext $context, string $domain, bool $beStrict): StringHost|false + { + // 1. Let result be the result of running Unicode ToASCII with domain_name set to domain, UseSTD3ASCIIRules set + // to beStrict, CheckHyphens set to false, CheckBidi set to true, CheckJoiners set to true, + // Transitional_Processing set to false, and VerifyDnsLength set to beStrict. + $result = Idna::toAscii($domain, [ + 'CheckHyphens' => false, + 'CheckBidi' => true, + 'CheckJoiners' => true, + 'UseSTD3ASCIIRules' => $beStrict, + 'Transitional_Processing' => false, + 'VerifyDnsLength' => $beStrict, + ]); + $convertedDomain = $result->getDomain(); + + // 2. If result is a failure value, validation error, return failure. + // 3. If result is the empty string, validation error, return failure. + if ($convertedDomain === '' || $result->hasErrors()) { + // Validation error. + $context->logger?->warning('domain-to-ASCII', [ + 'input' => $domain, + 'column_range' => [1, mb_strlen($domain, 'utf-8')], + 'idn_errors' => $this->enumerateIdnaErrors($result->getErrors()), + 'unicode_domain' => Idna::toUnicode($domain, self::UNICODE_IDNA_OPTIONS)->getDomain(), + ]); + + return false; + } + + // 4. Return result. + return new StringHost($convertedDomain); + } + + /** + * Parses an opaque host. + * + * @see https://url.spec.whatwg.org/#concept-opaque-host-parser + */ + private function parseOpaqueHost(ParserContext $context, USVStringInterface $input): HostInterface|false + { + if ($input->matches('/[' . self::FORBIDDEN_HOST_CODEPOINTS . ']/u', $matches, PREG_OFFSET_CAPTURE)) { + // Validation error. + $context->logger?->warning('host-invalid-code-point', [ + 'input' => (string) $input, + 'column' => mb_strlen(mb_strcut((string) $input, 0, $matches[0][1], 'utf-8'), 'utf-8') + 1, + ]); + + return false; + } + + foreach ($input as $i => $codePoint) { + if ($codePoint !== '%' && !CodePoint::isUrlCodePoint($codePoint)) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $input, + 'column' => $i, + ]); + } elseif ($codePoint === '%' && !$input->substr($i + 1)->startsWithTwoAsciiHexDigits()) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $input, + 'column' => $i, + ]); + } + } + + $percentEncoder = new PercentEncoder(); + $output = $percentEncoder->percentEncodeAfterEncoding('utf-8', (string) $input, EncodeSet::C0_CONTROL); + + return new StringHost($output); + } + + /** + * @return list + */ + private function enumerateIdnaErrors(int $bitmask): array + { + $reflection = new ReflectionClass(Idna::class); + $errorConstants = array_filter( + $reflection->getConstants(ReflectionClassConstant::IS_PUBLIC), + static fn (string $name): bool => str_starts_with($name, 'ERROR_'), + ARRAY_FILTER_USE_KEY + ); + $errors = []; + + foreach ($errorConstants as $name => $value) { + if (($value & $bitmask) !== 0) { + $errors[] = $name; + } + } + + return $errors; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4Address.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4Address.php new file mode 100644 index 0000000..c17fd15 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4Address.php @@ -0,0 +1,37 @@ +address = $address; + } + + public function equals(HostInterface $other): bool + { + return $other instanceof self && $this->address === $other->address; + } + + public function getSerializer(): HostSerializerInterface + { + return new IPv4AddressSerializer($this->address); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4AddressParser.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4AddressParser.php new file mode 100644 index 0000000..d010b8c --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv4AddressParser.php @@ -0,0 +1,270 @@ +split('.'); + $count = $parts->count(); + + // 2. If the last item in parts is the empty string, then: + if ($parts->last()->isEmpty()) { + // 2.1. Validation error. + $context->logger?->notice('IPv4-part-empty', [ + 'input' => (string) $input, + 'column' => $input->length() + 1, + ]); + + // 2.2. If parts’s size is greater than 1, then remove the last item from parts. + if ($count > 1) { + $parts->pop(); + --$count; + } + } + + // 3. If parts’s size is greater than 4, validation error, return failure. + if ($count > 4) { + $context->logger?->warning('IPv4-too-many-parts', [ + 'input' => (string) $input, + 'column' => array_reduce( + array_slice([...$parts], 0, 4), + static fn (int $carry, USVStringInterface $part): int => $carry + $part->length(), + 4 + ), + ]); + + return false; + } + + // 4. Let numbers be an empty list. + $numbers = []; + + // 5. For each part of parts: + foreach ($parts as $i => $part) { + // 5.1. Let result be the result of parsing part. + $result = self::parseIPv4Number($part); + + // 5.2. If result is failure, validation error, return failure. + if ($result === false) { + $context->logger?->warning('IPv4-non-numeric-part', [ + 'input' => (string) $input, + 'column_range' => self::getColumnRange($i, $parts), + ]); + + return false; + } + + // 5.3. If result[1] is true, then set validationError to true. + if ($result[1] === true) { + // Validation error. + $context->logger?->notice('IPv4-non-decimal-part', [ + 'input' => (string) $input, + 'column_range' => self::getColumnRange($i, $parts), + ]); + } + + // 5.4. Append result[0] to numbers. + $numbers[] = $result[0]; + } + + $size = count($numbers); + $sizeMinusOne = $size - 1; + $failure = false; + $errorQueue = []; + + // 6. If any item in numbers is greater than 255, validation error. + foreach ($numbers as $i => $number) { + if ($number->isGreaterThan(255)) { + // 7. If any but the last item in numbers is greater than 255, then return failure. + if ($i < $sizeMinusOne) { + $errorQueue[$i] = LogLevel::WARNING; + $failure = true; + + break; + } + + $errorQueue[$i] = LogLevel::NOTICE; + + break; + } + } + + $limit = NumberFactory::createNumber(256, 10)->pow(5 - $size); + + // 8. If the last item in numbers is greater than or equal to 256 ** (5 − numbers’s size), validation error, + // return failure. + if ($numbers[$sizeMinusOne]->isGreaterThanOrEqualTo($limit)) { + $errorQueue[$sizeMinusOne] = LogLevel::WARNING; + $failure = true; + } + + foreach ($errorQueue as $partIndex => $level) { + $context->logger?->log($level, 'IPv4-out-of-range-part', [ + 'input' => (string) $input, + 'column_range' => self::getColumnRange($partIndex, $parts), + ]); + } + + if ($failure) { + return false; + } + + /** + * 9. Let ipv4 be the last item in numbers. + * 10. Remove the last item from numbers. + * + * @var \Rowbot\URL\Component\Host\Math\NumberInterface $ipv4 + */ + $ipv4 = array_pop($numbers); + + // 11. Let counter be 0. + $counter = 0; + + // 12. For each n of numbers: + foreach ($numbers as $number) { + // 12.1. Increment ipv4 by n × 256 ** (3 − counter). + $ipv4 = $ipv4->plus($number->multipliedBy(256 ** (3 - $counter))); + + // 12.2. Increment counter by 1. + ++$counter; + } + + // 13. Return ipv4. + return new IPv4Address((string) $ipv4); + } + + public static function endsInIPv4Number(USVStringInterface $input): bool + { + // 1. Let parts be the result of strictly splitting input on U+002E (.). + $parts = $input->split('.'); + + // 2. If the last item in parts is the empty string, then: + if ($parts->last()->isEmpty()) { + // 2.1. If parts’s size is 1, then return false. + if ($parts->count() === 1) { + return false; + } + + // 3.1. Remove the last item from parts. + $parts->pop(); + } + + // 3. Let last be the last item in parts. + $last = $parts->last(); + + // 4. If parsing last as an IPv4 number does not return failure, then return true. + if (self::parseIPv4Number($last) !== false) { + return true; + } + + // 5. If last is non-empty and contains only ASCII digits, then return true. + // 6. Return false. + return !$last->isEmpty() && strspn((string) $last, CodePoint::ASCII_DIGIT_MASK) === $last->length(); + } + + /** + * @see https://url.spec.whatwg.org/#ipv4-number-parser + * + * @return array{0: \Rowbot\URL\Component\Host\Math\NumberInterface, 1: bool}|false + */ + private static function parseIPv4Number(USVStringInterface $input): array|false + { + // 1. If input is the empty string, then return failure. + if ($input->isEmpty()) { + return false; + } + + // 2. Let validationError be false. + $validationError = false; + + // 3. Let R be 10. + $radix = 10; + + if ($input->length() > 1) { + // 4. If input contains at least two code points and the first two code points are either "0x" or "0X", + // then: + if ($input->startsWith('0x') || $input->startsWith('0X')) { + // 4.1. Set validationError to true. + $validationError = true; + + // 4.2. Remove the first two code points from input. + $input = $input->substr(2); + + // 4.3. Set R to 16. + $radix = 16; + + // 5. Otherwise, if input contains at least two code points and the first code point is U+0030 (0), then: + } elseif ($input->startsWith('0')) { + // 5.1. Set validationError to true. + $validationError = true; + + // 5.2. Remove the first code point from input. + $input = $input->substr(1); + + // 5.3. Set R to 8. + $radix = 8; + } + } + + // 6. If input is the empty string, then return 0. + if ($input->isEmpty()) { + return [NumberFactory::createNumber(0, 10), $validationError]; + } + + $s = (string) $input; + $length = strlen($s); + + // 7. If input contains a code point that is not a radix-R digit, then return failure. + if ( + ($radix === 10 && strspn($s, CodePoint::ASCII_DIGIT_MASK) !== $length) + || ($radix === 16 && strspn($s, CodePoint::HEX_DIGIT_MASK) !== $length) + || ($radix === 8 && strspn($s, CodePoint::OCTAL_DIGIT_MASK) !== $length) + ) { + return false; + } + + // 8. Let output be the mathematical integer value that is represented by input in radix-R notation, using ASCII + // hex digits for digits with values 0 through 15. + // 9. Return (output, validationError). + return [NumberFactory::createNumber($s, $radix), $validationError]; + } + + /** + * @return array{0: int, 1: int} + */ + private static function getColumnRange(int $i, StringListInterface $parts): array + { + $partsArray = [...$parts]; + $offset = $i; + + for ($j = 0; $j < $i; ++$j) { + $offset += $partsArray[$j]->length(); + } + + $targetPartLength = $partsArray[$i]->length(); + + return [$offset + 1, $offset + $partsArray[$i]->length() + ($targetPartLength > 0 ? 0 : 1)]; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6Address.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6Address.php new file mode 100644 index 0000000..253b741 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6Address.php @@ -0,0 +1,37 @@ + + */ + private array $address; + + /** + * @param non-empty-list $address + */ + public function __construct(array $address) + { + $this->address = $address; + } + + public function equals(HostInterface $other): bool + { + return $other instanceof self && $this->address === $other->address; + } + + public function getSerializer(): HostSerializerInterface + { + return new IPv6AddressSerializer($this->address); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6AddressParser.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6AddressParser.php new file mode 100644 index 0000000..5364f6d --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/IPv6AddressParser.php @@ -0,0 +1,337 @@ +getIterator(); + $iter->rewind(); + + // 5. If c is U+003A (:), then: + if ($iter->current() === ':') { + // 5.1. If remaining does not start with U+003A (:), validation error, return failure. + if ($iter->peek() !== ':') { + $context->logger?->warning('IPv6-invalid-compression', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 5.2. Increase pointer by 2. + $iter->seek(2); + + // 5.3. Increase pieceIndex by 1 and then set compress to pieceIndex. + $compress = ++$pieceIndex; + } + + // 6. While c is not the EOF code point: + while ($iter->valid()) { + // 6.1. If pieceIndex is 8, validation error, return failure. + if ($pieceIndex === 8) { + $context->logger?->warning('IPv6-too-many-pieces', [ + 'input' => (string) $input, + 'column' => $iter->key(), + ]); + + return false; + } + + // 6.2. If c is U+003A (:), then: + if ($iter->current() === ':') { + // 6.2.1. If compress is non-null, validation error, return failure. + if ($compress !== null) { + $context->logger?->warning('IPv6-multiple-compression', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 6.2.2. Increase pointer and pieceIndex by 1, set compress to pieceIndex, and then continue. + $iter->next(); + $compress = ++$pieceIndex; + + continue; + } + + // 6.3. Let value and length be 0. + $value = 0; + $length = 0; + $current = $iter->current(); + + // 6.4. While length is less than 4 and c is an ASCII hex digit, set value to value × 0x10 + c interpreted + // as hexadecimal number, and increase pointer and length by 1. + while ($length < 4 && strpbrk($current, CodePoint::HEX_DIGIT_MASK) === $current) { + $value = ($value * 0x10) + intval($current, 16); + $iter->next(); + ++$length; + $current = $iter->current(); + } + + // 6.5. If c is U+002E (.), then: + if ($iter->current() === '.') { + // 6.5.1. If length is 0, validation error, return failure. + if ($length === 0) { + $context->logger?->warning('IPv4-in-IPv6-invalid-code-point', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 6.5.2. Decrease pointer by length. + $iter->seek(-$length); + + // 6.5.3. If pieceIndex is greater than 6, validation error, return failure. + if ($pieceIndex > 6) { + $context->logger?->warning('IPv4-in-IPv6-too-many-pieces', [ + 'input' => (string) $input, + 'column' => $iter->key(), + ]); + + return false; + } + + $result = self::parseIPv4Address($context, $input, $iter, $address, $pieceIndex); + + if ($result === false) { + return false; + } + + [$address, $pieceIndex] = $result; + + // 6.5.7. Break. + break; + } + + // 6.6. Otherwise, if c is U+003A (:): + if ($iter->current() === ':') { + // 6.6.1. Increase pointer by 1. + $iter->next(); + + // 6.2.2. If c is the EOF code point, validation error, return failure. + if (!$iter->valid()) { + $context->logger?->warning('IPv6-invalid-code-point', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 6.7. Otherwise, if c is not the EOF code point, validation error, return failure. + } elseif ($iter->valid()) { + $context->logger?->warning('IPv6-invalid-code-point', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 6.8. Set address[pieceIndex] to value. + // 6.9. Increase pieceIndex by 1. + $address[$pieceIndex++] = $value; + } + + // 7. If compress is non-null, then: + if ($compress !== null) { + // 7.1. Let swaps be pieceIndex − compress. + $swaps = $pieceIndex - $compress; + + // 7.2. Set pieceIndex to 7. + $pieceIndex = 7; + + // 7.3. While pieceIndex is not 0 and swaps is greater than 0, swap address[pieceIndex] with + // address[compress + swaps − 1], and then decrease both pieceIndex and swaps by 1. + while ($pieceIndex !== 0 && $swaps > 0) { + $temp = $address[$pieceIndex]; + $address[$pieceIndex] = $address[$compress + $swaps - 1]; + $address[$compress + $swaps - 1] = $temp; + --$pieceIndex; + --$swaps; + } + + // Otherwise, if compress is null and pieceIndex is not 8, validation error, return failure. + } elseif ($pieceIndex !== 8) { + $context->logger?->warning('IPv6-too-few-pieces', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + assert(array_is_list($address)); + + // 9. Return address. + return new IPv6Address($address); + } + + /** + * @param non-empty-list $address + * + * @return array{0: non-empty-list, 1: int}|false + */ + private static function parseIPv4Address( + ParserContext $context, + USVStringInterface $input, + StringIteratorInterface $iter, + array $address, + int $pieceIndex + ): array|false { + // 6.5.4. Let numbersSeen be 0. + $numbersSeen = 0; + + // 6.5.5. While c is not the EOF code point: + do { + // 6.5.5.1. Let ipv4Piece be null. + $ipv4Piece = null; + + // 6.5.5.2. If numbersSeen is greater than 0, then: + if ($numbersSeen > 0) { + // 6.5.5.2.2 Otherwise, validation error, return failure. + if ($iter->current() !== '.' || $numbersSeen >= 4) { + // Validation error. + $context->logger?->warning('IPv4-in-IPv6-invalid-code-point', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 6.5.5.2.1 If c is a U+002E (.) and numbersSeen is less than 4, then increase pointer by 1. + $iter->next(); + } + + $current = $iter->current(); + + // 6.5.5.3. If c is not an ASCII digit, validation error, return failure. + if (strpbrk($current, CodePoint::ASCII_DIGIT_MASK) !== $current) { + // Validation error. + $context->logger?->warning('IPv4-in-IPv6-invalid-code-point', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + // 6.5.5.4. While c is an ASCII digit: + do { + // 6.5.5.4.1. Let number be c interpreted as decimal number. + $number = (int) $current; + + // 6.5.5.4.2. If ipv4Piece is null, then set ipv4Piece to number. + if ($ipv4Piece === null) { + $ipv4Piece = $number; + + // Otherwise, if ipv4Piece is 0, validation error, return failure. + } elseif ($ipv4Piece === 0) { + // Validation error. + $context->logger?->warning('IPv4-in-IPv6-invalid-code-point', [ + 'input' => (string) $input, + 'column' => $iter->key(), + ]); + + return false; + + // Otherwise, set ipv4Piece to ipv4Piece × 10 + number. + } else { + $ipv4Piece = ($ipv4Piece * 10) + $number; + } + + // 6.5.5.4.3. If ipv4Piece is greater than 255, validation error, return failure. + if ($ipv4Piece > 255) { + // Validation error. + $context->logger?->warning('IPv4-in-IPv6-out-of-range-part', [ + 'input' => (string) $input, + 'column_range' => (static function () use ($input, $iter, $numbersSeen): array { + $str = (string) $input; + $delimiter = $numbersSeen === 0 ? ':' : '.'; + $startIndex = strrpos($str, $delimiter, -($input->length() - $iter->key())); + $endIndex = strpos($str, '.', $iter->key()); + + if ($startIndex === false) { + $startIndex = $iter->key(); + } + + if ($endIndex === false) { + $endIndex = $input->length(); + } + + return [$startIndex + 2, $endIndex]; + })(), + ]); + + return false; + } + + // 6.5.5.4.4. Increase pointer by 1. + $iter->next(); + $current = $iter->current(); + } while (strpbrk($current, CodePoint::ASCII_DIGIT_MASK) === $current); + + // 6.5.5.5. Set address[pieceIndex] to address[pieceIndex] × 0x100 + ipv4Piece. + $piece = $address[$pieceIndex]; + $address[$pieceIndex] = ($piece * 0x100) + $ipv4Piece; + + // 6.5.5.6. Increase numbersSeen by 1. + ++$numbersSeen; + + // 6.5.5.7. If numbersSeen is 2 or 4, then increase pieceIndex by 1. + if ($numbersSeen === 2 || $numbersSeen === 4) { + ++$pieceIndex; + } + } while ($iter->valid()); + + // 6.5.6. If numbersSeen is not 4, validation error, return failure. + if ($numbersSeen !== 4) { + // Validation error. + $context->logger?->warning('IPv4-in-IPv6-too-few-parts', [ + 'input' => (string) $input, + 'column' => $iter->key() + 1, + ]); + + return false; + } + + assert(array_is_list($address)); + + return [$address, $pieceIndex]; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/BrickMathAdapter.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/BrickMathAdapter.php new file mode 100644 index 0000000..f71490c --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/BrickMathAdapter.php @@ -0,0 +1,93 @@ +number = BigInteger::fromBase($number, $base); + + return; + } + + $this->number = BigInteger::of($number); + } + + public function intdiv(int $number): NumberInterface + { + return new self($this->number->dividedBy($number, RoundingMode::FLOOR)); + } + + public function isEqualTo(NumberInterface $number): bool + { + if (!$number instanceof self) { + throw new MathException('Must be given an instance of itself.'); + } + + return $this->number->isEqualTo($number->number); + } + + public function isGreaterThan(int $number): bool + { + return $this->number->isGreaterThan($number); + } + + public function isGreaterThanOrEqualTo(NumberInterface $number): bool + { + if (!$number instanceof self) { + throw new MathException('Must be given an instance of itself.'); + } + + return $this->number->isGreaterThanOrEqualTo($number->number); + } + + public function mod(int $number): NumberInterface + { + return new self($this->number->mod($number)); + } + + public function multipliedBy(int $number): NumberInterface + { + return new self($this->number->multipliedBy($number)); + } + + public function plus(NumberInterface $number): NumberInterface + { + if (!$number instanceof self) { + throw new MathException('Must be given an instance of itself.'); + } + + return new self($this->number->plus($number->number)); + } + + public function pow(int $number): NumberInterface + { + return new self($this->number->power($number)); + } + + /** + * @return numeric-string + */ + public function __toString(): string + { + $str = (string) $this->number; + assert(is_numeric($str)); + + return $str; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/Exception/MathException.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/Exception/MathException.php new file mode 100644 index 0000000..66ec163 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/Exception/MathException.php @@ -0,0 +1,11 @@ +number = intval($number, $base); + } + + public function intdiv(int $number): NumberInterface + { + return new self((int) floor($this->number / $number)); + } + + public function isEqualTo(NumberInterface $number): bool + { + if (!$number instanceof self) { + throw new MathException('Must be given an instance of itself.'); + } + + return $this->number === $number->number; + } + + public function isGreaterThan(int $number): bool + { + return $this->number > $number; + } + + public function isGreaterThanOrEqualTo(NumberInterface $number): bool + { + if (!$number instanceof self) { + throw new MathException('Must be given an instance of itself.'); + } + + return $this->number >= $number->number; + } + + public function mod(int $number): NumberInterface + { + return new self($this->number % $number); + } + + public function multipliedBy(int $number): NumberInterface + { + return new self($this->number * $number); + } + + public function plus(NumberInterface $number): NumberInterface + { + if (!$number instanceof self) { + throw new MathException('Must be given an instance of itself.'); + } + + return new self($this->number + $number->number); + } + + public function pow(int $number): NumberInterface + { + return new self($this->number ** $number); + } + + /** + * @return numeric-string + */ + public function __toString(): string + { + return (string) $this->number; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/NumberFactory.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/NumberFactory.php new file mode 100644 index 0000000..8d876a9 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Math/NumberFactory.php @@ -0,0 +1,27 @@ +address = $address; + } + + public function toFormattedString(): string + { + return $this->toString(); + } + + public function toString(): string + { + // 1. Let output be the empty string. + $output = ''; + + // 2. Let n be the value of address. + $number = NumberFactory::createNumber($this->address, 10); + + // 3. For each i in the range 1 to 4, inclusive: + for ($i = 0; $i < 4; ++$i) { + // 3.1. Prepend n % 256, serialized, to output. + $output = $number->mod(256) . $output; + + // 3.2. If i is not 4, then prepend U+002E (.) to output. + if ($i < 3) { + $output = '.' . $output; + } + + // 3.3. Set n to floor(n / 256). + $number = $number->intdiv(256); + } + + // 4. Return output. + return $output; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/IPv6AddressSerializer.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/IPv6AddressSerializer.php new file mode 100644 index 0000000..146beaf --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/IPv6AddressSerializer.php @@ -0,0 +1,121 @@ + + */ + private array $address; + + /** + * @param non-empty-list $address + */ + public function __construct(array $address) + { + $this->address = $address; + } + + public function toFormattedString(): string + { + return '[' . $this->toString() . ']'; + } + + public function toString(): string + { + // 1. Let output be the empty string. + $output = ''; + + // 2. Let compress be an index to the first IPv6 piece in the first longest sequences of address’s IPv6 pieces + // that are 0. + // 3. If there is no sequence of address’s IPv6 pieces that are 0 that is longer than 1, then set compress to + // null. + // 4. Let ignore0 be false. + [$compress, $longestSequence] = $this->getCompressLocation(); + $pieceIndex = 0; + + // 5. For each pieceIndex in the range 0 to 7, inclusive: + do { + // 5.3. If compress is pieceIndex, then: + if ($compress === $pieceIndex) { + // 5.3.1. Let separator be "::" if pieceIndex is 0, and U+003A (:) otherwise. + // 5.3.2. Append separator to output. + $output .= $pieceIndex === 0 ? '::' : ':'; + + // 5.3.3. Set ignore0 to true and continue. + // + // Advance the pointer to $compress + $longestSequence + // to skip over all 16-bit pieces that are 0 that immediately + // follow the piece at $compress. + $pieceIndex = $compress + $longestSequence; + + continue; + } + + // 5.4. Append address[pieceIndex], represented as the shortest possible lowercase hexadecimal number, to + // output. + // + // Is it safe to assume this always returns lowercase letters? + $output .= dechex($this->address[$pieceIndex]); + + // 5.5. If pieceIndex is not 7, then append U+003A (:) to output. + if ($pieceIndex < self::MAX_SIZE - 1) { + $output .= ':'; + } + + ++$pieceIndex; + } while ($pieceIndex < self::MAX_SIZE); + + // 6. Return output. + return $output; + } + + /** + * Finds the longest sequence, with a length greater than 1, of 16-bit pieces that are 0 and + * sets $compress to the first 16-bit piece in that sequence, otherwise $compress will remain + * null. + * + * @return array{0: int|null, 1: int} The first item is the compress pointer, which indicates where in the address + * it can start compression, or null if the address isn't compressable. The + * second item is the length of the longest sequence of zeroes. + */ + private function getCompressLocation(): array + { + $longestSequence = 1; + $compress = null; + $i = 0; + + do { + if ($this->address[$i] !== 0) { + continue; + } + + $sequenceLength = 0; + + do { + ++$sequenceLength; + ++$i; + } while ($i < self::MAX_SIZE && $this->address[$i] === 0); + + // We are only interested in sequences with a length greater than one. We also only want + // to note the first of those sequences since there may be multiple sequences of zero + // that have the same length. + if ($sequenceLength > $longestSequence) { + $longestSequence = $sequenceLength; + $compress = $i - $sequenceLength; + } + } while (++$i < self::MAX_SIZE); + + return [$compress, $longestSequence]; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/StringHostSerializer.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/StringHostSerializer.php new file mode 100644 index 0000000..5223279 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/Serializer/StringHostSerializer.php @@ -0,0 +1,25 @@ +string = $string; + } + + public function toFormattedString(): string + { + return $this->string; + } + + public function toString(): string + { + return $this->string; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Host/StringHost.php b/transfer-protocol/vendor/rowbot/url/src/Component/Host/StringHost.php new file mode 100644 index 0000000..a4833ff --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Host/StringHost.php @@ -0,0 +1,37 @@ +string === $other->string; + } + + public function getSerializer(): HostSerializerInterface + { + return new StringHostSerializer($this->string); + } + + public function isLocalHost(): bool + { + return $this->string === 'localhost'; + } + + public function isNull(): bool + { + return false; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/OpaqueOrigin.php b/transfer-protocol/vendor/rowbot/url/src/Component/OpaqueOrigin.php new file mode 100644 index 0000000..3c7c25b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/OpaqueOrigin.php @@ -0,0 +1,41 @@ +list); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/PathInterface.php b/transfer-protocol/vendor/rowbot/url/src/Component/PathInterface.php new file mode 100644 index 0000000..ad9156d --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/PathInterface.php @@ -0,0 +1,30 @@ +list[] = $path; + } + + public function shorten(Scheme $scheme): void + { + // 3. If url’s scheme is "file", path’s size is 1, and path[0] is a normalized Windows drive letter, then + // return. + if ($scheme->isFile() && count($this->list) === 1 && $this->list[0]->isNormalizedWindowsDriveLetter()) { + return; + } + + // 4. Remove path’s last item, if any. + array_pop($this->list); + } + + /** + * @see https://url.spec.whatwg.org/#url-path-serializer + */ + public function __toString(): string + { + if (!isset($this->list[0])) { + return ''; + } + + return '/' . implode('/', $this->list); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/PathSegment.php b/transfer-protocol/vendor/rowbot/url/src/Component/PathSegment.php new file mode 100644 index 0000000..eda1c1c --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/PathSegment.php @@ -0,0 +1,33 @@ +string) === 2 + && strpbrk($this->string[0], CodePoint::ASCII_ALPHA_MASK) === $this->string[0] + && $this->string[1] === ':'; + } + + public function stripTrailingSpaces(): void + { + $this->string = rtrim($this->string, "\x20"); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/QueryList.php b/transfer-protocol/vendor/rowbot/url/src/Component/QueryList.php new file mode 100644 index 0000000..2ae23e7 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/QueryList.php @@ -0,0 +1,339 @@ + + */ +class QueryList implements Countable, IteratorAggregate +{ + private const LEAD_OFFSET = 0xD800 - (0x10000 >> 10); + + /** + * @var array + */ + private array $cache; + + /** + * @var array + */ + private array $list; + + /** + * @param array $list + */ + public function __construct(array $list = []) + { + $this->list = $list; + $this->cache = []; + } + + /** + * Decodes a application/x-www-form-urlencoded string and returns the decoded pairs as a list. + * + * Note: A legacy server-oriented implementation might have to support encodings other than + * UTF-8 as well as have special logic for tuples of which the name is `_charset_`. Such logic + * is not described here as only UTF-8' is conforming. + * + * @see https://url.spec.whatwg.org/#concept-urlencoded-parser + */ + public static function fromString(string $input): self + { + // Let sequences be the result of splitting input on 0x26 (&). + $sequences = explode('&', $input); + + // Let output be an initially empty list of name-value tuples where both name and value + // hold a string. + $output = new self(); + + foreach ($sequences as $bytes) { + if ($bytes === '') { + continue; + } + + // If bytes contains a 0x3D (=), then let name be the bytes from the start of bytes up + // to but excluding its first 0x3D (=), and let value be the bytes, if any, after the + // first 0x3D (=) up to the end of bytes. If 0x3D (=) is the first byte, then name will + // be the empty byte sequence. If it is the last, then value will be the empty byte + // sequence. Otherwise, let name have the value of bytes and let value be the empty byte + // sequence. + $name = $bytes; + $value = ''; + + if (str_contains($bytes, '=')) { + [$name, $value] = explode('=', $bytes, 2); + } + + // Replace any 0x2B (+) in name and value with 0x20 (SP). + [$name, $value] = str_replace('+', "\x20", [$name, $value]); + + // Let nameString and valueString be the result of running UTF-8 + // decode without BOM on the percent decoding of name and value, + // respectively. + $output->append( + Utf8String::transcode(rawurldecode($name), 'utf-8', 'utf-8'), + Utf8String::transcode(rawurldecode($value), 'utf-8', 'utf-8') + ); + } + + return $output; + } + + /** + * Appends a new name-value pair to the list. + */ + public function append(string $name, string $value): void + { + $this->list[] = ['name' => $name, 'value' => $value]; + $this->cache[$name] = true; + } + + public function count(): int + { + return count($this->list); + } + + /** + * Determines if a name-value pair with name $name exists in the collection. + */ + public function contains(string $name, ?string $value = null): bool + { + $hasTuple = isset($this->cache[$name]); + + if ($value === null || !$hasTuple) { + return $hasTuple; + } + + foreach ($this->list as $tuple) { + if ($name === $tuple['name'] && $value === $tuple['value']) { + return true; + } + } + + return false; + } + + /** + * Returns a filtered array based on the given callback. + * + * @return array> + */ + public function filter(callable $callback): array + { + return array_filter($this->list, $callback); + } + + /** + * Returns the first name-value pair in the list whose name is $name. + */ + public function first(string $name): ?string + { + foreach ($this->list as $pair) { + if ($pair['name'] === $name) { + return $pair['value']; + } + } + + return null; + } + + /** + * @return \ArrayIterator + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->list); + } + + /** + * @return array{name: string, value: string}|null + */ + public function getTupleAt(int $index): ?array + { + return $this->list[$index] ?? null; + } + + /** + * Removes all name-value pairs with name $name from the list. + */ + public function remove(string $name, ?string $value): void + { + $seen = 0; + $removed = 0; + + for ($i = count($this->list) - 1; $i >= 0; --$i) { + if ($this->list[$i]['name'] === $name) { + ++$seen; + + if ($value !== null && $this->list[$i]['value'] !== $value) { + continue; + } + + array_splice($this->list, $i, 1); + ++$removed; + } + } + + if ($seen === $removed) { + unset($this->cache[$name]); + } + } + + /** + * Sets the value of the first name-value pair with $name to $value and + * removes all other occurances that have name $name. + */ + public function set(string $name, string $value): void + { + $prevIndex = null; + + for ($i = count($this->list) - 1; $i >= 0; --$i) { + if ($this->list[$i]['name'] === $name) { + if ($prevIndex !== null) { + array_splice($this->list, $prevIndex, 1); + } + + $prevIndex = $i; + } + } + + if ($prevIndex === null) { + return; + } + + $this->list[$prevIndex]['value'] = $value; + } + + /** + * Sorts the collection by code units and preserves the relative positioning + * of name-value pairs. + */ + public function sort(): void + { + $temp = []; + + foreach ($this->list as $pair) { + $codeUnits = $this->convertToCodeUnits($pair['name']); + $temp[] = ['original' => $pair, 'codeUnits' => $codeUnits, 'length' => count($codeUnits)]; + } + + // Sorting priority overview: + // + // Each string is compared code unit by code unit against each other. + // + // 1) If the two strings have different lengths, and the strings are equal up to the end of + // the shortest string, then the shorter of the two strings will be moved up in the + // array. (e.g. The string "aa" will come before the string "aaa".) + // 2) If the value of the code units differ, the character with the lower code unit will be + // moved up in the array. (e.g. "🌈" will come before "ffi". Although "🌈" has a code + // point value of 127,752 that is greater than the "ffi" code point value of 64,259, "🌈" + // is split in to 2 code units and it's first code unit has a value of 55,356, which is + // less than the "ffi" single code unit value of 64,259.) + // 3) If the two strings are considered equal, then they are sorted by the relative + // position in which they appeared in the array. (e.g. The string "b=c&a=c&b=a&a=a" + // becomes "a=c&a=a&b=c&b=a".) + usort($temp, static function (array $a, array $b): int { + $aCodeUnits = $a['codeUnits']; + $bCodeUnits = $b['codeUnits']; + $lengthComparison = $a['length'] <=> $b['length']; + + if ($lengthComparison === 0) { + return $aCodeUnits <=> $bCodeUnits; + } + + $shortestLength = $lengthComparison < 0 ? $a['length'] : $b['length']; + + for ($i = 0; $i < $shortestLength; ++$i) { + $comparison = $aCodeUnits[$i] <=> $bCodeUnits[$i]; + + if ($comparison !== 0) { + return $comparison; + } + } + + return $lengthComparison; + }); + + $this->list = array_column($temp, 'original'); + } + + /** + * Encodes the list of tuples as a valid application/x-www-form-urlencoded string. + * + * @see https://url.spec.whatwg.org/#concept-urlencoded-serializer + */ + public function toUrlencodedString(?string $encodingOverride = null): string + { + $encoding = EncodingHelper::getOutputEncoding($encodingOverride) ?? 'utf-8'; + $output = ''; + $percentEncoder = new PercentEncoder(); + + foreach ($this->list as $key => $tuple) { + $name = $percentEncoder->percentEncodeAfterEncoding( + $encoding, + $tuple['name'], + EncodeSet::X_WWW_URLENCODED, + true + ); + $value = $percentEncoder->percentEncodeAfterEncoding( + $encoding, + $tuple['value'], + EncodeSet::X_WWW_URLENCODED, + true + ); + + if ($key > 0) { + $output .= '&'; + } + + $output .= $name . '=' . $value; + } + + return $output; + } + + /** + * @see https://www.unicode.org/faq/utf_bom.html?source=post_page---------------------------#utf16-4 + * + * @return list> + */ + private function convertToCodeUnits(string $input): array + { + $codeUnits = []; + + foreach (mb_str_split($input, 1, 'utf-8') as $strCodePoint) { + $codePoint = mb_ord($strCodePoint, 'utf-8'); + + // Code points less than 0x10000 are part of the Basic Multilingual Plane and are + // represented by a single code unit that is equal to its code point. Use 0 as the low + // surrogate as the <=> operator compares array size first and values second. + $codeUnits[] = $codePoint < 0x10000 + ? [$codePoint, 0] + : [self::LEAD_OFFSET + ($codePoint >> 10), 0xDC00 + ($codePoint & 0x3FF)]; + } + + return $codeUnits; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/Scheme.php b/transfer-protocol/vendor/rowbot/url/src/Component/Scheme.php new file mode 100644 index 0000000..7f9d857 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/Scheme.php @@ -0,0 +1,75 @@ + 21, + 'file' => null, + 'http' => 80, + 'https' => 443, + 'ws' => 80, + 'wss' => 443, + ]; + + private string $scheme; + + public function __construct(string $scheme = '') + { + $this->scheme = $scheme; + } + + public function isBlob(): bool + { + return $this->scheme === 'blob'; + } + + public function isFile(): bool + { + return $this->scheme === 'file'; + } + + public function isWebsocket(): bool + { + return $this->scheme === 'wss' || $this->scheme === 'ws'; + } + + /** + * Returns whether or not the string is a special scheme. + * + * @see https://url.spec.whatwg.org/#is-special + */ + public function isSpecial(): bool + { + return array_key_exists($this->scheme, self::SPECIAL_SCHEMES); + } + + public function isDefaultPort(?int $port): bool + { + if (!isset(self::SPECIAL_SCHEMES[$this->scheme])) { + return false; + } + + return self::SPECIAL_SCHEMES[$this->scheme] === $port; + } + + public function equals(self $other): bool + { + return $this->scheme === $other->scheme; + } + + public function __toString(): string + { + return $this->scheme; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Component/TupleOrigin.php b/transfer-protocol/vendor/rowbot/url/src/Component/TupleOrigin.php new file mode 100644 index 0000000..60028a0 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Component/TupleOrigin.php @@ -0,0 +1,88 @@ +domain = $domain; + $this->host = $host; + $this->port = $port; + $this->scheme = $scheme; + } + + public function getEffectiveDomain(): ?string + { + if ($this->domain !== null) { + return $this->domain; + } + + return $this->host->getSerializer()->toFormattedString(); + } + + public function isOpaque(): bool + { + return false; + } + + public function isSameOrigin(Origin $other): bool + { + return $other instanceof self + && $this->scheme === $other->scheme + && $this->host->equals($other->host) + && $this->port === $other->port; + } + + public function isSameOriginDomain(Origin $other): bool + { + // If A and B are both tuple origins... + if ($other instanceof self) { + // If A and B's schemes are identical, and their domains are + // identical and non-null, then return true. Otherwise, if A and B + // are same origin and their domains are identical and null, then + // return true. + if ($this->scheme === $other->scheme && $this->domain !== null && $this->domain === $other->domain) { + return true; + } + + if ($this->isSameOrigin($other) && $this->domain === null && $other->domain === null) { + return true; + } + } + + return false; + } + + /** + * @see https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin + */ + public function __toString(): string + { + $result = $this->scheme; + $result .= '://'; + $result .= $this->host->getSerializer()->toFormattedString(); + + if ($this->port !== null) { + $result .= ':' . $this->port; + } + + return $result; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Exception/TypeError.php b/transfer-protocol/vendor/rowbot/url/src/Exception/TypeError.php new file mode 100644 index 0000000..9e807d9 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Exception/TypeError.php @@ -0,0 +1,9 @@ +input = $input; + $this->iter = $iter; + $this->buffer = $buffer; + $this->url = $url; + $this->base = $base; + $this->encoding = EncodingHelper::getOutputEncoding($encodingOverride) ?? 'utf-8'; + $this->state = $stateOverride ?? ParserState::SCHEME_START; + $this->stateOverride = $stateOverride; + $this->logger = $logger; + } + + /** + * Returns the output encoding of the URL string. + */ + public function getOutputEncoding(): string + { + return $this->encoding; + } + + /** + * Returns whether the parser's starting state was overriden. This occurs when using one of the + * URL object's setters. + */ + public function isStateOverridden(): bool + { + return $this->stateOverride !== null; + } + + /** + * Returns whether the parser's starting state was the Hostname state. + */ + public function isOverrideStateHostname(): bool + { + return $this->stateOverride === ParserState::HOSTNAME; + } + + /** + * Changes the encoding of the resulting URL string. This only affects the query string portion + * and it is only for use in the HTML specification. This should never be changed from the + * default UTF-8 encoding. + */ + public function setOutputEncoding(string $encoding): void + { + $this->encoding = EncodingHelper::getOutputEncoding($encoding) ?? 'utf-8'; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/ParserState.php b/transfer-protocol/vendor/rowbot/url/src/ParserState.php new file mode 100644 index 0000000..7f1ec28 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/ParserState.php @@ -0,0 +1,80 @@ + new SchemeStartState(), + self::SCHEME => new SchemeState(), + self::NO_SCHEME => new NoSchemeState(), + self::SPECIAL_RELATIVE_OR_AUTHORITY => new SpecialRelativeOrAuthorityState(), + self::PATH_OR_AUTHORITY => new PathOrAuthorityState(), + self::RELATIVE => new RelativeState(), + self::RELATIVE_SLASH => new RelativeSlashState(), + self::SPECIAL_AUTHORITY_SLASHES => new SpecialAuthoritySlashesState(), + self::SPECIAL_AUTHORITY_IGNORE_SLASHES => new SpecialAuthorityIgnoreSlashesState(), + self::AUTHORITY => new AuthorityState(), + self::HOST => new HostState(), + self::HOSTNAME => new HostnameState(), + self::PORT => new PortState(), + self::FILE => new FileState(), + self::FILE_SLASH => new FileSlashState(), + self::FILE_HOST => new FileHostState(), + self::PATH_START => new PathStartState(), + self::PATH => new PathState(), + self::OPAQUE_PATH => new OpaquePathState(), + self::QUERY => new QueryState(), + self::FRAGMENT => new FragmentState(), + }; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/AbstractHostState.php b/transfer-protocol/vendor/rowbot/url/src/State/AbstractHostState.php new file mode 100644 index 0000000..a359c56 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/AbstractHostState.php @@ -0,0 +1,145 @@ +isBracketOpen = false; + } + + public function handle(ParserContext $context, string $codePoint): StatusCode + { + // 1. If state override is given and url’s scheme is "file", then decrease pointer by 1 and set state to file + // host state. + if ($context->isStateOverridden() && $context->url->scheme->isFile()) { + $context->iter->prev(); + $context->state = ParserState::FILE_HOST; + + return StatusCode::OK; + } + + do { + // 2. Otherwise, if c is U+003A (:) and insideBrackets is false, then: + if ($codePoint === ':' && !$this->isBracketOpen) { + // 2.1. If buffer is the empty string, validation error, return failure. + if ($context->buffer->isEmpty()) { + // Validation error. Return failure. + $context->logger?->warning('host-missing', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + return StatusCode::FAILURE; + } + + // 2.2. If state override is given and state override is hostname state, then return. + if ($context->isOverrideStateHostname()) { + return StatusCode::BREAK; + } + + // 2.3. Let host be the result of host parsing buffer with url is not special. + $parser = new HostParser(); + $host = $parser->parse($context, $context->buffer->toUtf8String(), !$context->url->scheme->isSpecial()); + + // 2.4. If host is failure, then return failure. + if ($host === false) { + return StatusCode::FAILURE; + } + + // 5. Set url’s host to host, buffer to the empty string, and state to port state. + $context->url->host = $host; + $context->buffer->clear(); + $context->state = ParserState::PORT; + + return StatusCode::OK; + } + + // 3. Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + if ( + ( + $codePoint === CodePoint::EOF + || $codePoint === '/' + || $codePoint === '?' + || $codePoint === '#' + ) + || ($context->url->scheme->isSpecial() && $codePoint === '\\') + ) { + // then decrease pointer by 1, and then: + $context->iter->prev(); + + // 3.1. If url is special and buffer is the empty string, validation error, return failure. + if ($context->url->scheme->isSpecial() && $context->buffer->isEmpty()) { + // Validation error. Return failure. + $context->logger?->warning('host-missing', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 2, // Add 2 since we called ->prev() above + ]); + + return StatusCode::FAILURE; + } + + // 3.2. Otherwise, if state override is given, buffer is the empty string, and either url includes + // credentials or url’s port is non-null, return. + if ( + $context->isStateOverridden() + && $context->buffer->isEmpty() + && ($context->url->includesCredentials() || $context->url->port !== null) + ) { + return StatusCode::BREAK; + } + + // 3.3. Let host be the result of host parsing buffer with url is not special. + $parser = new HostParser(); + $host = $parser->parse($context, $context->buffer->toUtf8String(), !$context->url->scheme->isSpecial()); + + // 3.4. If host is failure, then return failure. + if ($host === false) { + return StatusCode::FAILURE; + } + + // 3.5. Set url’s host to host, buffer to the empty string, and state to path start state. + $context->url->host = $host; + $context->buffer->clear(); + $context->state = ParserState::PATH_START; + + // 3.6. If state override is given, then return. + if ($context->isStateOverridden()) { + return StatusCode::BREAK; + } + + return StatusCode::OK; + } + + // 4. Otherwise: + // 4.1. If c is U+005B ([), then set insideBrackets to true. + if ($codePoint === '[') { + $this->isBracketOpen = true; + + // 4.2. If c is U+005D (]), then set insideBrackets to false. + } elseif ($codePoint === ']') { + $this->isBracketOpen = false; + } + + // 4.3. Append c to buffer. + $context->buffer->append($codePoint); + $context->iter->next(); + $codePoint = $context->iter->current(); + } while (true); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/AuthorityState.php b/transfer-protocol/vendor/rowbot/url/src/State/AuthorityState.php new file mode 100644 index 0000000..89b23dd --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/AuthorityState.php @@ -0,0 +1,129 @@ +atTokenSeen = false; + $this->passwordTokenSeen = false; + } + + public function handle(ParserContext $context, string $codePoint): StatusCode + { + do { + // 1. If c is U+0040 (@), then: + if ($codePoint === '@') { + // 1.1. Validation error. + $context->logger?->notice('invalid-credentials', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + // 1.2. If atSignSeen is true, then prepend "%40" to buffer. + if ($this->atTokenSeen) { + $context->buffer->prepend('%40'); + } + + // 1.3. Set atSignSeen to true. + $this->atTokenSeen = true; + $username = ''; + $password = ''; + + // 1.4. For each codePoint in buffer: + foreach ($context->buffer as $bufferCodePoint) { + // 1.4.1. If codePoint is U+003A (:) and passwordTokenSeen is false, then set passwordTokenSeen to true + // and continue. + if ($bufferCodePoint === ':' && !$this->passwordTokenSeen) { + $this->passwordTokenSeen = true; + + continue; + } + + // 1.4.3. If passwordTokenSeen is true, then append encodedCodePoints to url’s password. + // 1.4.4. Otherwise, append encodedCodePoints to url’s username. + if ($this->passwordTokenSeen) { + $password .= $bufferCodePoint; + } else { + $username .= $bufferCodePoint; + } + } + + // 1.4.2. Let encodedCodePoints be the result of running UTF-8 percent-encode codePoint using the + // userinfo percent-encode set. + $percentEncoder = new PercentEncoder(); + $context->url->username .= $percentEncoder->percentEncodeAfterEncoding( + 'utf-8', + $username, + EncodeSet::USERINFO + ); + $context->url->password .= $percentEncoder->percentEncodeAfterEncoding( + 'utf-8', + $password, + EncodeSet::USERINFO + ); + + // 1.5. Set buffer to the empty string. + $context->buffer->clear(); + + $context->iter->next(); + $codePoint = $context->iter->current(); + + continue; + } + + // 2. Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + if ( + ( + $codePoint === CodePoint::EOF + || $codePoint === '/' + || $codePoint === '?' + || $codePoint === '#' + ) + || ($context->url->scheme->isSpecial() && $codePoint === '\\') + ) { + // 2.1. If atSignSeen is true and buffer is the empty string, validation error, return failure. + if ($this->atTokenSeen && $context->buffer->isEmpty()) { + // Validation error. + $context->logger?->warning('host-missing', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + return StatusCode::FAILURE; + } + + // 2.2. Decrease pointer by the number of code points in buffer plus one, set buffer to the empty string, + // and set state to host state. + $context->iter->seek(-($context->buffer->length() + 1)); + $context->buffer->clear(); + $context->state = ParserState::HOST; + + return StatusCode::OK; + } + + // 3. Otherwise, append c to buffer. + $context->buffer->append($codePoint); + $context->iter->next(); + $codePoint = $context->iter->current(); + } while (true); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/FileHostState.php b/transfer-protocol/vendor/rowbot/url/src/State/FileHostState.php new file mode 100644 index 0000000..a472747 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/FileHostState.php @@ -0,0 +1,100 @@ +iter->prev(); + + // 1.1. If state override is not given and buffer is a Windows drive letter, validation error, set state to + // path state. + if (!$context->isStateOverridden() && $context->buffer->isWindowsDriveLetter()) { + // Validation error + $context->logger?->notice('file-invalid-Windows-drive-letter-host', [ + 'input' => (string) $context->input, + 'column_range' => [$context->iter->key(), $context->iter->key() + $context->buffer->length()], + ]); + $context->state = ParserState::PATH; + + return StatusCode::OK; + } + + // This is a (platform-independent) Windows drive letter quirk. $context->buffer is not reset + // here and instead used in the path state. + // + // 1.2. Otherwise, if buffer is the empty string, then: + if ($context->buffer->isEmpty()) { + // 1.2.1. Set url’s host to the empty string. + $context->url->host = new StringHost(); + + // 1.2.2. If state override is given, then return. + if ($context->isStateOverridden()) { + return StatusCode::BREAK; + } + + // 1.2.3. Set state to path start state. + $context->state = ParserState::PATH_START; + + return StatusCode::OK; + } + + // 1.3. Otherwise, run these steps: + // 1.3.1. Let host be the result of host parsing buffer with url is not special. + $parser = new HostParser(); + $host = $parser->parse($context, $context->buffer->toUtf8String(), !$context->url->scheme->isSpecial()); + + // 1.3.2. If host is failure, then return failure. + if ($host === false) { + return StatusCode::FAILURE; + } + + // 1.3.3. If host is "localhost", then set host to the empty string. + if ($host->isLocalHost()) { + $host = new StringHost(); + } + + // 1.3.4. Set url’s host to host. + $context->url->host = $host; + + // 1.3.5. If state override is given, then return. + if ($context->isStateOverridden()) { + return StatusCode::BREAK; + } + + // 1.3.6. Set buffer to the empty string and state to path start state. + $context->buffer->clear(); + $context->state = ParserState::PATH_START; + + return StatusCode::OK; + } + + // 2. Otherwise, append c to buffer. + $context->buffer->append($codePoint); + $context->iter->next(); + $codePoint = $context->iter->current(); + } while (true); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/FileSlashState.php b/transfer-protocol/vendor/rowbot/url/src/State/FileSlashState.php new file mode 100644 index 0000000..d3b1b06 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/FileSlashState.php @@ -0,0 +1,59 @@ +logger?->notice('invalid-reverse-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 1.2. Set state to file host state. + $context->state = ParserState::FILE_HOST; + + return StatusCode::OK; + } + + // 2. Otherwise: + // 2.1. If base is non-null and base’s scheme is "file", then: + if ($context->base !== null && $context->base->scheme->isFile()) { + // 2.1.1. Set url’s host to base’s host. + $context->url->host = clone $context->base->host; + $path = $context->base->path->first(); + + // 2.1.2. If the substring from pointer in input does not start with a Windows drive letter and base’s + // path[0] is a normalized Windows drive letter, then append base’s path[0] to url’s path. + if ( + !$context->input->substr($context->iter->key())->startsWithWindowsDriveLetter() + && $path->isNormalizedWindowsDriveLetter() + ) { + // This is a (platform-independent) Windows drive letter quirk. Both url’s and + // base’s host are null under these conditions and therefore not copied. + $context->url->path->push($path); + } + } + + // 2.2. Set state to path state, and decrease pointer by 1. + $context->state = ParserState::PATH; + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/FileState.php b/transfer-protocol/vendor/rowbot/url/src/State/FileState.php new file mode 100644 index 0000000..6dadeb7 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/FileState.php @@ -0,0 +1,108 @@ +url->scheme = new Scheme('file'); + + // 2. Set url’s host to the empty string. + $context->url->host = new StringHost(); + + // 3. If c is U+002F (/) or U+005C (\), then: + if ($codePoint === '/' || $codePoint === '\\') { + // 3.1. If c is U+005C (\), validation error. + if ($codePoint === '\\') { + // Validation error + $context->logger?->notice('invalid-reverse-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 3.2. Set state to file slash state. + $context->state = ParserState::FILE_SLASH; + + return StatusCode::OK; + } + + // 4. Otherwise, if base is non-null and base’s scheme is "file": + if ($context->base !== null && $context->base->scheme->isFile()) { + // 4.1. Set url’s host to base’s host, url’s path to a clone of base’s path, and url’s query to base’s + // query. + $context->url->host = clone $context->base->host; + $context->url->path = clone $context->base->path; + $context->url->query = $context->base->query; + + // 4.2. If c is U+003F (?), then set url’s query to the empty string and state to query state. + if ($codePoint === '?') { + $context->url->query = ''; + $context->state = ParserState::QUERY; + + return StatusCode::OK; + } + + // 4.3. Otherwise, if c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. + if ($codePoint === '#') { + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + + return StatusCode::OK; + } + + // 4.4. Otherwise, if c is not the EOF code point: + if ($codePoint === CodePoint::EOF) { + return StatusCode::OK; + } + + // 4.4.1. Set url’s query to null. + $context->url->query = null; + + // This is a (platform-independent) Windows drive letter quirk. + // + // 4.4.2. If the substring from pointer in input does not start with a Windows drive letter, then shorten + // url’s path. + if (!$context->input->substr($context->iter->key())->startsWithWindowsDriveLetter()) { + $context->url->path->shorten($context->url->scheme); + + // 4.4.3. Otherwise: + } else { + // 4.4.3.1 Validation error. + $context->logger?->notice('file-invalid-Windows-drive-letter', [ + 'input' => (string) $context->input, + 'column_range' => [$context->iter->key() + 1, $context->iter->key() + 3], + ]); + + // 4.4.3.2. Set url’s path to an empty list. + $context->url->path = new PathList(); + } + + // 4.4.4 Set state to path state and decrease pointer by 1. + $context->state = ParserState::PATH; + $context->iter->prev(); + + return StatusCode::OK; + } + + // 5. Otherwise, set state to path state, and decrease pointer by 1. + $context->state = ParserState::PATH; + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/FragmentState.php b/transfer-protocol/vendor/rowbot/url/src/State/FragmentState.php new file mode 100644 index 0000000..8f0b0ad --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/FragmentState.php @@ -0,0 +1,54 @@ +logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + // 1.2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, validation error. + } elseif ( + $codePoint === '%' + && !$context->input->substr($context->iter->key() + 1)->startsWithTwoAsciiHexDigits() + ) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + $buffer .= $codePoint; + $context->iter->next(); + $codePoint = $context->iter->current(); + } + + // 1.3. UTF-8 percent-encode c using the fragment percent-encode set and append the result to url’s fragment. + $percentEncoder = new PercentEncoder(); + $context->url->fragment .= $percentEncoder->percentEncodeAfterEncoding('utf-8', $buffer, EncodeSet::FRAGMENT); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/HostState.php b/transfer-protocol/vendor/rowbot/url/src/State/HostState.php new file mode 100644 index 0000000..3a95127 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/HostState.php @@ -0,0 +1,9 @@ +base === null || ($context->base->path->isOpaque() && $codePoint !== '#')) { + // Validation error. Return failure. + $context->logger?->warning('missing-scheme-non-relative-URL', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + return StatusCode::FAILURE; + } + + // 2. Otherwise, if base has an opaque path and c is U+0023 (#), set url’s scheme to base’s scheme, url’s path + // to base’s path, url’s query to base’s query, url’s fragment to the empty string, and set state to fragment + // state. + if ($context->base->path->isOpaque() && $codePoint === '#') { + $context->url->scheme = clone $context->base->scheme; + $context->url->path = clone $context->base->path; + $context->url->query = $context->base->query; + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + + return StatusCode::OK; + } + + // 3. Otherwise, if base’s scheme is not "file", set state to relative state and decrease pointer by 1. + if (!$context->base->scheme->isFile()) { + $context->state = ParserState::RELATIVE; + $context->iter->prev(); + + return StatusCode::OK; + } + + // 4. Otherwise, set state to file state and decrease pointer by 1. + $context->state = ParserState::FILE; + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/OpaquePathState.php b/transfer-protocol/vendor/rowbot/url/src/State/OpaquePathState.php new file mode 100644 index 0000000..a8aeb61 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/OpaquePathState.php @@ -0,0 +1,77 @@ +url->query = ''; + $context->state = ParserState::QUERY; + + break; + } + + // 2. Otherwise, if c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. + if ($codePoint === '#') { + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + + break; + } + + // 3. Otherwise: + // 3.1. If c is not the EOF code point, not a URL code point, and not U+0025 (%), validation error. + if ($codePoint !== CodePoint::EOF && $codePoint !== '%' && !CodePoint::isUrlCodePoint($codePoint)) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + // 3.2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, validation error. + } elseif ( + $codePoint === '%' + && !$context->input->substr($context->iter->key() + 1)->startsWithTwoAsciiHexDigits() + ) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 3.3. If c is not the EOF code point, UTF-8 percent-encode c using the C0 control percent-encode set and + // append the result to url’s path. + if ($codePoint !== CodePoint::EOF) { + $percentEncoder ??= new PercentEncoder(); + $context->url->path->first()->append($percentEncoder->percentEncodeAfterEncoding( + 'utf-8', + $codePoint, + EncodeSet::C0_CONTROL + )); + } + + $context->iter->next(); + $codePoint = $context->iter->current(); + } while ($codePoint !== CodePoint::EOF); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/PathOrAuthorityState.php b/transfer-protocol/vendor/rowbot/url/src/State/PathOrAuthorityState.php new file mode 100644 index 0000000..4bc0aa7 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/PathOrAuthorityState.php @@ -0,0 +1,30 @@ +state = ParserState::AUTHORITY; + + return StatusCode::OK; + } + + // 2. Otherwise, set state to path state, and decrease pointer by 1. + $context->state = ParserState::PATH; + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/PathStartState.php b/transfer-protocol/vendor/rowbot/url/src/State/PathStartState.php new file mode 100644 index 0000000..87f4eb7 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/PathStartState.php @@ -0,0 +1,79 @@ +url->scheme->isSpecial()) { + // 1.1. If c is U+005C (\), validation error. + if ($codePoint === '\\') { + // Validation error. + $context->logger?->notice('invalid-reverse-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 1.2. Set state to path state. + $context->state = ParserState::PATH; + + // 1.3. If c is neither U+002F (/) nor U+005C (\), then decrease pointer by 1. + if ($codePoint !== '/' && $codePoint !== '\\') { + $context->iter->prev(); + } + + return StatusCode::OK; + } + + // 2. Otherwise, if state override is not given and c is U+003F (?), set url’s query to the empty string and + // state to query state. + if (!$context->isStateOverridden() && $codePoint === '?') { + $context->url->query = ''; + $context->state = ParserState::QUERY; + + return StatusCode::OK; + } + + // 3. Otherwise, if state override is not given and c is U+0023 (#), set url’s fragment to the empty string and + // state to fragment state. + if (!$context->isStateOverridden() && $codePoint === '#') { + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + + return StatusCode::OK; + } + + // 4. Otherwise, if c is not the EOF code point: + if ($codePoint !== CodePoint::EOF) { + // 4.1. Set state to path state. + $context->state = ParserState::PATH; + + // 4.2. If c is not U+002F (/), then decrease pointer by 1. + if ($codePoint !== '/') { + $context->iter->prev(); + } + + return StatusCode::OK; + } + + // 5. Otherwise, if state override is given and url’s host is null, append the empty string to url’s path. + if ($context->isStateOverridden() && $context->url->host->isNull()) { + $context->url->path->push(new PathSegment()); + } + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/PathState.php b/transfer-protocol/vendor/rowbot/url/src/State/PathState.php new file mode 100644 index 0000000..98f074f --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/PathState.php @@ -0,0 +1,153 @@ + '', + '.%2e' => '', + '.%2E' => '', + '%2e.' => '', + '%2E.' => '', + '%2e%2e' => '', + '%2E%2E' => '', + '%2e%2E' => '', + '%2E%2e' => '', + ]; + + /** + * @see https://url.spec.whatwg.org/#single-dot-path-segment + */ + private const SINGLE_DOT_SEGMENT = [ + '.' => '', + '%2e' => '', + '%2E' => '', + ]; + + public function handle(ParserContext $context, string $codePoint): StatusCode + { + $percentEncoder = null; + + do { + // 1. If one of the following is true: + // - c is the EOF code point or U+002F (/) + // - url is special and c is U+005C (\) + // - state override is not given and c is U+003F (?) or U+0023 (#) + if ( + $codePoint === CodePoint::EOF + || $codePoint === '/' + || ($context->url->scheme->isSpecial() && $codePoint === '\\') + || (!$context->isStateOverridden() && ($codePoint === '?' || $codePoint === '#')) + ) { + $urlIsSpecial = $context->url->scheme->isSpecial(); + + // 1.1. If url is special and c is U+005C (\), validation error. + if ($urlIsSpecial && $codePoint === '\\') { + // Validation error. + $context->logger?->notice('invalid-reverse-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + $stringBuffer = (string) $context->buffer; + + // 1.2. If buffer is a double-dot path segment, then: + if (isset(self::DOUBLE_DOT_SEGMENT[$stringBuffer])) { + // 1.2.1. Shorten url’s path. + $context->url->path->shorten($context->url->scheme); + + // 1.2.2. If neither c is U+002F (/), nor url is special and c is U+005C (\), append the empty string + // to url’s path. + if ($codePoint !== '/' && !($urlIsSpecial && $codePoint === '\\')) { + $context->url->path->push(new PathSegment()); + } + + // 1.3. Otherwise, if buffer is a single-dot path segment and if neither c is U+002F (/), nor url is special + // and c is U+005C (\), append the empty string to url’s path. + } elseif ( + isset(self::SINGLE_DOT_SEGMENT[$stringBuffer]) + && $codePoint !== '/' + && !($urlIsSpecial && $codePoint === '\\') + ) { + $context->url->path->push(new PathSegment()); + + // 1.4. Otherwise, if buffer is not a single-dot path segment, then: + } elseif (!isset(self::SINGLE_DOT_SEGMENT[$stringBuffer])) { + // 1.4.1. If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then + // replace the second code point in buffer with U+003A (:). + if ( + $context->url->scheme->isFile() + && $context->url->path->isEmpty() + && $context->buffer->isWindowsDriveLetter() + ) { + // This is a (platform-independent) Windows drive letter quirk. + $context->buffer->setCodePointAt(1, ':'); + } + + // 1.4.2. Append buffer to url’s path. + $context->url->path->push($context->buffer->toPath()); + } + + // 1.5. Set buffer to the empty string. + $context->buffer->clear(); + + // 1.6. If c is U+003F (?), then set url’s query to the empty string and state to query state. + if ($codePoint === '?') { + $context->url->query = ''; + $context->state = ParserState::QUERY; + + // If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. + } elseif ($codePoint === '#') { + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + } + + return StatusCode::OK; + } + + // 2. Otherwise, run these steps: + // 2.1. If c is not a URL code point and not U+0025 (%), validation error. + if ($codePoint !== '%' && !CodePoint::isUrlCodePoint($codePoint)) { + // Validation error + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + // 2.2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, validation error. + } elseif ( + $codePoint === '%' + && !$context->input->substr($context->iter->key() + 1)->startsWithTwoAsciiHexDigits() + ) { + // Validation error + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 2.3. UTF-8 percent-encode c using the path percent-encode set and append the result to buffer. + $percentEncoder ??= new PercentEncoder(); + $context->buffer->append($percentEncoder->percentEncodeAfterEncoding('utf-8', $codePoint, EncodeSet::PATH)); + $context->iter->next(); + $codePoint = $context->iter->current(); + } while (true); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/PortState.php b/transfer-protocol/vendor/rowbot/url/src/State/PortState.php new file mode 100644 index 0000000..34fc453 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/PortState.php @@ -0,0 +1,92 @@ +buffer->append($codePoint); + $context->iter->next(); + $codePoint = $context->iter->current(); + } + + // 2. Otherwise, if one of the following is true: + // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) + // - url is special and c is U+005C (\) + // - state override is given + if ( + ( + $codePoint === CodePoint::EOF + || $codePoint === '/' + || $codePoint === '?' + || $codePoint === '#' + ) + || ($context->url->scheme->isSpecial() && $codePoint === '\\') + || $context->isStateOverridden() + ) { + // 2.1. If buffer is not the empty string, then: + if (!$context->buffer->isEmpty()) { + // 2.1.1. Let port be the mathematical integer value that is represented by buffer in radix-10 using + // ASCII digits for digits with values 0 through 9. + $port = $context->buffer->toInt(); + + // 2.1.2. If port is greater than 2 ^ 16 − 1, validation error, return failure. + if ($port > 2 ** 16 - 1) { + // Validation error. Return failure. + $context->logger?->warning('port-out-of-range', [ + 'input' => (string) $context->input, + 'column_range' => [ + $context->iter->key() - $context->buffer->length() + 1, + $context->iter->key(), + ], + ]); + + return StatusCode::FAILURE; + } + + // 2.1.3. Set url’s port to null, if port is url’s scheme’s default port, and to port otherwise. + if ($context->url->scheme->isSpecial() && $context->url->scheme->isDefaultPort($port)) { + $context->url->port = null; + } else { + $context->url->port = $port; + } + + // 2.1.4. Set buffer to the empty string. + $context->buffer->clear(); + } + + // 2.2. If state override is given, then return. + if ($context->isStateOverridden()) { + return StatusCode::BREAK; + } + + // 2.3. Set state to path start state and decrease pointer by 1. + $context->state = ParserState::PATH_START; + $context->iter->prev(); + + return StatusCode::OK; + } + + // 3. Otherwise, validation error, return failure. + $context->logger?->warning('port-invalid', [ + 'input' => (string) $context->input, + 'column_range' => [$context->iter->key() - $context->buffer->length() + 1, $context->iter->key() + 1], + ]); + + return StatusCode::FAILURE; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/QueryState.php b/transfer-protocol/vendor/rowbot/url/src/State/QueryState.php new file mode 100644 index 0000000..a53dc9e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/QueryState.php @@ -0,0 +1,93 @@ +getOutputEncoding() !== 'utf-8' + && (!$context->url->scheme->isSpecial() || $context->url->scheme->isWebsocket()) + ) { + $context->setOutputEncoding('utf-8'); + } + + do { + // 2. If one of the following is true: + // - state override is not given and c is U+0023 (#) + // - c is the EOF code point + // then: + if (!$context->isStateOverridden() && $codePoint === '#' || $codePoint === CodePoint::EOF) { + // 2.1. Let queryPercentEncodeSet be the special-query percent-encode set if url is special; otherwise the + // query percent-encode set. + $queryPercentEncodeSet = $context->url->scheme->isSpecial() + ? EncodeSet::SPECIAL_QUERY + : EncodeSet::QUERY; + + // 2.2. Percent-encode after encoding, with encoding, buffer, and queryPercentEncodeSet, and append the + // result to url’s query. + // + // NOTE: This operation cannot be invoked code-point-for-code-point due to the stateful ISO-2022-JP encoder. + $percentEncoder = new PercentEncoder(); + $context->url->query .= $percentEncoder->percentEncodeAfterEncoding( + $context->getOutputEncoding(), + (string) $context->buffer, + $queryPercentEncodeSet + ); + + // 2.3. Set buffer to the empty string. + $context->buffer->clear(); + + // 2.4. If c is U+0023 (#), then set url’s fragment to the empty string and state to fragment state. + if ($codePoint === '#') { + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + } + + return StatusCode::OK; + } + + // 3. Otherwise, if c is not the EOF code point: + // 3.1. If c is not a URL code point and not U+0025 (%), validation error. + if ($codePoint !== '%' && !CodePoint::isUrlCodePoint($codePoint)) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + // 3.2. If c is U+0025 (%) and remaining does not start with two ASCII hex digits, validation error. + } elseif ( + $codePoint === '%' + && !$context->input->substr($context->iter->key() + 1)->startsWithTwoAsciiHexDigits() + ) { + // Validation error. + $context->logger?->notice('invalid-URL-unit', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 3.3. Append c to buffer. + $context->buffer->append($codePoint); + $context->iter->next(); + $codePoint = $context->iter->current(); + } while (true); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/RelativeSlashState.php b/transfer-protocol/vendor/rowbot/url/src/State/RelativeSlashState.php new file mode 100644 index 0000000..9e686d0 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/RelativeSlashState.php @@ -0,0 +1,56 @@ +base !== null); + + // 1. If url is special and c is U+002F (/) or U+005C (\), then: + if ($context->url->scheme->isSpecial() && ($codePoint === '/' || $codePoint === '\\')) { + // 1.1. If c is U+005C (\), validation error. + if ($codePoint === '\\') { + // Validation error. + $context->logger?->notice('invalid-reverse-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + } + + // 1.2. Set state to special authority ignore slashes state. + $context->state = ParserState::SPECIAL_AUTHORITY_IGNORE_SLASHES; + + return StatusCode::OK; + } + + // 2. Otherwise, if c is U+002F (/), then set state to authority state. + if ($codePoint === '/') { + $context->state = ParserState::AUTHORITY; + + return StatusCode::OK; + } + + // 3. Otherwise, set url’s username to base’s username, url’s password to base’s password, url’s host to base’s + // host, url’s port to base’s port, state to path state, and then, decrease pointer by 1. + $context->url->username = $context->base->username; + $context->url->password = $context->base->password; + $context->url->host = clone $context->base->host; + $context->url->port = $context->base->port; + $context->state = ParserState::PATH; + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/RelativeState.php b/transfer-protocol/vendor/rowbot/url/src/State/RelativeState.php new file mode 100644 index 0000000..6ad710c --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/RelativeState.php @@ -0,0 +1,88 @@ +base !== null && !$context->base->scheme->isFile()); + + // 2. Set url’s scheme to base’s scheme. + $context->url->scheme = clone $context->base->scheme; + + // 3. If c is U+002F (/), then set state to relative slash state. + if ($codePoint === '/') { + $context->state = ParserState::RELATIVE_SLASH; + + return StatusCode::OK; + } + + // 4. Otherwise, if url is special and c is U+005C (\), validation error, set state to relative slash state. + if ($context->url->scheme->isSpecial() && $codePoint === '\\') { + // Validation error + $context->logger?->notice('invalid-reverse-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + $context->state = ParserState::RELATIVE_SLASH; + + return StatusCode::OK; + } + + // 5. Otherwise: + // 5.1. Set url’s username to base’s username, url’s password to base’s password, url’s host to base’s host, + // url’s port to base’s port, url’s path to a clone of base’s path, and url’s query to base’s query. + $context->url->username = $context->base->username; + $context->url->password = $context->base->password; + $context->url->host = clone $context->base->host; + $context->url->port = $context->base->port; + $context->url->path = clone $context->base->path; + $context->url->query = $context->base->query; + + // 5.2. If c is U+003F (?), then set url’s query to the empty string, and state to query state. + if ($codePoint === '?') { + $context->url->query = ''; + $context->state = ParserState::QUERY; + + return StatusCode::OK; + } + + // 5.3. Otherwise, if c is U+0023 (#), set url’s fragment to the empty string and state to fragment state. + if ($codePoint === '#') { + $context->url->fragment = ''; + $context->state = ParserState::FRAGMENT; + + return StatusCode::OK; + } + + // 5.4 Otherwise, if c is not the EOF code point: + if ($codePoint === CodePoint::EOF) { + return StatusCode::OK; + } + + // 5.4.1. Set url’s query to null. + $context->url->query = null; + + // 5.4.2. Shorten url’s path. + $context->url->path->shorten($context->url->scheme); + + // 5.4.3. Set state to path state and decrease pointer by 1. + $context->state = ParserState::PATH; + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/SchemeStartState.php b/transfer-protocol/vendor/rowbot/url/src/State/SchemeStartState.php new file mode 100644 index 0000000..241685b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/SchemeStartState.php @@ -0,0 +1,43 @@ +buffer->append(strtolower($codePoint)); + $context->state = ParserState::SCHEME; + + return StatusCode::OK; + } + + // 2. Otherwise, if state override is not given, set state to no scheme state and decrease pointer by 1. + if (!$context->isStateOverridden()) { + $context->state = ParserState::NO_SCHEME; + $context->iter->prev(); + + return StatusCode::OK; + } + + // 3. Otherwise, return failure. + // + // Note: This indication of failure is used exclusively by the Location object's protocol + // attribute. + return StatusCode::FAILURE; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/SchemeState.php b/transfer-protocol/vendor/rowbot/url/src/State/SchemeState.php new file mode 100644 index 0000000..5d0a535 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/SchemeState.php @@ -0,0 +1,150 @@ +buffer->append(strtolower($codePoint)); + $context->iter->next(); + $codePoint = $context->iter->current(); + } + + // 2. Otherwise, if c is U+003A (:), then: + if ($codePoint === ':') { + $stateIsOverridden = $context->isStateOverridden(); + $bufferIsSpecialScheme = false; + $candidateScheme = $context->buffer->toScheme(); + + // 2.1. If state override is given, then: + if ($stateIsOverridden) { + $bufferIsSpecialScheme = $candidateScheme->isSpecial(); + $urlIsSpecial = $context->url->scheme->isSpecial(); + + // 2.1.1. If url’s scheme is a special scheme and buffer is not a special scheme, then return. + // 2.1.2. If url’s scheme is not a special scheme and buffer is a special scheme, then return. + if ($urlIsSpecial xor $bufferIsSpecialScheme) { + return StatusCode::BREAK; + } + + // 2.1.3. If url includes credentials or has a non-null port, and buffer is "file", then return. + if ( + $context->url->includesCredentials() + || ($context->url->port !== null && $candidateScheme->isFile()) + ) { + return StatusCode::BREAK; + } + + // 2.1.4. If url’s scheme is "file" and its host is an empty host, then return. + if ($context->url->scheme->isFile() && $context->url->host->isEmpty()) { + return StatusCode::BREAK; + } + } + + // 2.2. Set url’s scheme to buffer. + $context->url->scheme = $candidateScheme; + + // 2.3. If state override is given, then: + if ($stateIsOverridden) { + // 2.3.1. If url’s port is url’s scheme’s default port, then set url’s port to null. + if ($bufferIsSpecialScheme && $context->url->scheme->isDefaultPort($context->url->port)) { + $context->url->port = null; + } + + // 2.3.2. Return. + return StatusCode::BREAK; + } + + // 2.4. Set buffer to the empty string. + $context->buffer->clear(); + $urlIsSpecial = $context->url->scheme->isSpecial(); + + // 2.5. If url’s scheme is "file", then: + if ($context->url->scheme->isFile()) { + // 2.5.1. If remaining does not start with "//", validation error. + if ($context->iter->peek(2) !== '//') { + // Validation error. + $context->logger?->notice('special-scheme-missing-following-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 2, + ]); + } + + // 2.5.2. Set state to file state. + $context->state = ParserState::FILE; + + // 2.6. Otherwise, if url is special, base is non-null, and base’s scheme is equal to url’s scheme, set + // state to special relative or authority state. + } elseif ( + $urlIsSpecial + && $context->base !== null + && $context->base->scheme->equals($context->url->scheme) + ) { + assert( + $context->base->scheme->isSpecial(), + 'base is special (and therefore does not have an opaque path)' + ); + $context->state = ParserState::SPECIAL_RELATIVE_OR_AUTHORITY; + + // 2.7. Otherwise, if url is special, set state to special authority slashes state. + } elseif ($urlIsSpecial) { + $context->state = ParserState::SPECIAL_AUTHORITY_SLASHES; + + // 2.8. Otherwise, if remaining starts with an U+002F (/), set state to path or authority state and + // increase pointer by 1. + } elseif ($context->iter->peek() === '/') { + $context->state = ParserState::PATH_OR_AUTHORITY; + $context->iter->next(); + + // 2.9. Otherwise, set url’s path to the empty string and set state to opaque path state. + } else { + $context->url->path = new OpaquePath(new PathSegment()); + $context->state = ParserState::OPAQUE_PATH; + } + + return StatusCode::OK; + } + + // 3. Otherwise, if state override is not given, set buffer to the empty string, state to no scheme state, and + // start over (from the first code point in input). + if (!$context->isStateOverridden()) { + $context->buffer->clear(); + $context->state = ParserState::NO_SCHEME; + + // Reset the pointer to point at the first code point. + $context->iter->rewind(); + + return StatusCode::CONTINUE; + } + + // 4. Otherwise, return failure. + // + // Note: This indication of failure is used exclusively by the Location object's protocol + // attribute. Furthermore, the non-failure termination earlier in this state is an + // intentional difference for defining that attribute. + return StatusCode::FAILURE; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthorityIgnoreSlashesState.php b/transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthorityIgnoreSlashesState.php new file mode 100644 index 0000000..60cdc1e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthorityIgnoreSlashesState.php @@ -0,0 +1,33 @@ +state = ParserState::AUTHORITY; + $context->iter->prev(); + + return StatusCode::OK; + } + + // 2. Otherwise, validation error. + $context->logger?->notice('special-scheme-missing-following-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthoritySlashesState.php b/transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthoritySlashesState.php new file mode 100644 index 0000000..ee18b19 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/SpecialAuthoritySlashesState.php @@ -0,0 +1,37 @@ +iter->peek() === '/') { + $context->state = ParserState::SPECIAL_AUTHORITY_IGNORE_SLASHES; + $context->iter->next(); + + return StatusCode::OK; + } + + // 2. Otherwise, validation error, set state to special authority ignore slashes state and decrease pointer + // by 1. + $context->state = ParserState::SPECIAL_AUTHORITY_IGNORE_SLASHES; + $context->logger?->notice('special-scheme-missing-following-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/SpecialRelativeOrAuthorityState.php b/transfer-protocol/vendor/rowbot/url/src/State/SpecialRelativeOrAuthorityState.php new file mode 100644 index 0000000..2f738bd --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/SpecialRelativeOrAuthorityState.php @@ -0,0 +1,36 @@ +iter->peek() === '/') { + $context->state = ParserState::SPECIAL_AUTHORITY_IGNORE_SLASHES; + $context->iter->next(); + + return StatusCode::OK; + } + + // 2. Otherwise, validation error, set state to relative state and decrease pointer by 1. + $context->state = ParserState::RELATIVE; + $context->logger?->notice('special-scheme-missing-following-solidus', [ + 'input' => (string) $context->input, + 'column' => $context->iter->key() + 1, + ]); + $context->iter->prev(); + + return StatusCode::OK; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/State/State.php b/transfer-protocol/vendor/rowbot/url/src/State/State.php new file mode 100644 index 0000000..9d36645 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/State/State.php @@ -0,0 +1,12 @@ + + */ +abstract class AbstractStringBuffer implements IteratorAggregate, Stringable +{ + protected string $string; + + public function __construct(string $string = '') + { + $this->string = $string; + } + + public function append(string $string): void + { + $this->string .= $string; + } + + public function clear(): void + { + $this->string = ''; + } + + public function getIterator(): StringIteratorInterface + { + return new Utf8StringIterator($this->string); + } + + public function isEmpty(): bool + { + return $this->string === ''; + } + + public function length(): int + { + return mb_strlen($this->string, 'utf-8'); + } + + public function prepend(string $string): void + { + $this->string = $string . $this->string; + } + + public function setCodePointAt(int $index, string $codePoint): void + { + $prefix = mb_substr($this->string, 0, $index, 'utf-8'); + $suffix = mb_substr($this->string, $index + 1, null, 'utf-8'); + $this->string = $prefix . $codePoint . $suffix; + } + + public function toUtf8String(): USVStringInterface + { + return new Utf8String($this->string); + } + + public function __toString(): string + { + return $this->string; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/AbstractStringList.php b/transfer-protocol/vendor/rowbot/url/src/String/AbstractStringList.php new file mode 100644 index 0000000..99584e8 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/AbstractStringList.php @@ -0,0 +1,103 @@ + + */ + protected array $list; + + /** + * @param array $list + */ + public function __construct(array $list = []) + { + $this->list = $list; + } + + public function count(): int + { + return count($this->list); + } + + /** + * @return T + */ + public function first() + { + if (!isset($this->list[0])) { + throw new UndefinedIndexException(); + } + + return $this->list[0]; + } + + public function isEmpty(): bool + { + return $this->list === []; + } + + /** + * @return T + */ + public function last() + { + $last = count($this->list) - 1; + + if ($last < 0) { + throw new UndefinedIndexException(); + } + + return $this->list[$last]; + } + + /** + * @return T|null + */ + public function pop() + { + return array_pop($this->list); + } + + /** + * @param T $string + */ + public function push($string): void + { + $this->list[] = $string; + } + + /** + * @return \Generator + */ + public function getIterator(): Generator + { + foreach ($this->list as $string) { + yield $string; + } + } + + public function __clone() + { + $temp = []; + + foreach ($this->list as $string) { + $temp[] = clone $string; + } + + $this->list = $temp; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/AbstractUSVString.php b/transfer-protocol/vendor/rowbot/url/src/String/AbstractUSVString.php new file mode 100644 index 0000000..1eec27f --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/AbstractUSVString.php @@ -0,0 +1,154 @@ +string = $string; + } + + public function append(string $string): USVStringInterface + { + $copy = clone $this; + $copy->string .= $string; + + return $copy; + } + + public function endsWith(string $string): bool + { + return str_ends_with($this->string, $string); + } + + public function getIterator(): StringIteratorInterface + { + return new Utf8StringIterator($this->string); + } + + public function isEmpty(): bool + { + return $this->string === ''; + } + + public function length(): int + { + return mb_strlen($this->string, 'utf-8'); + } + + public function matches(string $pattern, ?array &$matches = null, int $flags = 0, int $offset = 0): bool + { + $result = preg_match($pattern, $this->string, $matches, $flags, $offset); + + if ($result === false) { + throw new RegexException(sprintf( + 'preg_match encountered an error with message "%s".', + preg_last_error_msg(), + )); + } + + return $result === 1; + } + + public function replaceRegex( + string $pattern, + string $replacement, + int $limit = -1, + int &$count = 0 + ): USVStringInterface { + $result = preg_replace($pattern, $replacement, $this->string, $limit, $count); + + if ($result === null) { + throw new RegexException(sprintf( + 'preg_replace encountered an error with message "%s".', + preg_last_error_msg(), + )); + } + + $copy = clone $this; + $copy->string = $result; + + return $copy; + } + + public function split(string $delimiter, ?int $limit = null): StringListInterface + { + if ($delimiter === '') { + return new StringList(); + } + + /** @var non-empty-list $list */ + $list = explode($delimiter, $this->string, $limit ?? PHP_INT_MAX); + $temp = []; + + foreach ($list as $string) { + $copy = clone $this; + $copy->string = $string; + $temp[] = $copy; + } + + return new StringList($temp); + } + + public function startsWith(string $string): bool + { + return str_starts_with($this->string, $string); + } + + public function startsWithTwoAsciiHexDigits(): bool + { + if (!isset($this->string[1])) { + return false; + } + + return strspn($this->string, CodePoint::HEX_DIGIT_MASK, 0, 2) === 2; + } + + /** + * @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter + */ + public function startsWithWindowsDriveLetter(): bool + { + return preg_match('/^[A-Za-z][:|](?:$|[\/\\\?#])/u', $this->string) === 1; + } + + public function substr(int $start, ?int $length = null): USVStringInterface + { + $copy = clone $this; + $copy->string = mb_substr($this->string, $start, $length, 'utf-8'); + + return $copy; + } + + public function toInt(int $base = 10): int + { + return intval($this->string, $base); + } + + public function __toString(): string + { + return $this->string; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/CodePoint.php b/transfer-protocol/vendor/rowbot/url/src/String/CodePoint.php new file mode 100644 index 0000000..4a76092 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/CodePoint.php @@ -0,0 +1,86 @@ += '&' && $codePoint <= '/') + || ($codePoint >= "\xA0" && $codePoint <= "\u{10FFFD}") + ) + + // Not a surrogate + && ($codePoint < "\u{D800}" || $codePoint > "\u{DFFF}") + + // Not a non-character + && ($codePoint < "\u{FDD0}" || $codePoint > "\u{FDEF}") + && !in_array($codePoint, [ + "\u{FFFE}", + "\u{FFFF}", + "\u{1FFFE}", + "\u{1FFFF}", + "\u{2FFFE}", + "\u{2FFFF}", + "\u{3FFFE}", + "\u{3FFFF}", + "\u{4FFFE}", + "\u{4FFFF}", + "\u{5FFFE}", + "\u{5FFFF}", + "\u{6FFFE}", + "\u{6FFFF}", + "\u{7FFFE}", + "\u{7FFFF}", + "\u{8FFFE}", + "\u{8FFFF}", + "\u{9FFFE}", + "\u{9FFFF}", + "\u{AFFFE}", + "\u{AFFFF}", + "\u{BFFFE}", + "\u{BFFFF}", + "\u{CFFFE}", + "\u{CFFFF}", + "\u{DFFFE}", + "\u{DFFFF}", + "\u{EFFFE}", + "\u{EFFFF}", + "\u{FFFFE}", + "\u{FFFFF}", + "\u{10FFFE}", + "\u{10FFFF}", + ], true); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/EncodeSet.php b/transfer-protocol/vendor/rowbot/url/src/String/EncodeSet.php new file mode 100644 index 0000000..646293c --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/EncodeSet.php @@ -0,0 +1,17 @@ +randomBytes = null; + } + + /** + * While letting mbstring do the text encoding works in the majority of cases, it isn't perfect due to differences + * in the encoders for mbstring and those defined by the WHATWG encoding standard. This is the best we can do + * without actually implementing custom encoders from the WHATWG standard. Mbstring's lack of granular error + * handling also makes this more complex than it would otherwise need to be. + * + * @see https://url.spec.whatwg.org/#string-percent-encode-after-encoding + * + * @param string $encoding Output encoding + * @param string $input UTF-8 encoded string + */ + public function percentEncodeAfterEncoding( + string $encoding, + string $input, + EncodeSet $percentEncodeSet, + bool $spaceAsPlus = false + ): string { + // 1. Let encoder be the result of getting an encoder from encoding. + $encoder = EncodingHelper::getOutputEncoding($encoding) ?? 'utf-8'; + + // 3. Let output be the empty string. + $output = ''; + + // Avoid the costly encoding conversion and error handling in the common case of UTF-8 as it is only relevant + // for non-UTF-8 strings. + if (strcasecmp($encoder, 'utf-8') !== 0) { + // Generate a random string to be used as a placeholder, only changing it if the given input contains the + // same sequence of bytes. + while ($this->randomBytes === null || str_contains($input, $this->randomBytes)) { + $this->randomBytes = bin2hex(random_bytes(16)); + } + + // Replace any existing numeric entities, that are in the hexadecimal format, so that we can distinguish + // encoding errors below. These will be reinserted later. + $replacedEntities = 0; + $input = preg_replace( + '/&#x([[:xdigit:]]{2,6};?)/', + '__' . $this->randomBytes . '_${1}__', + $input, + -1, + $replacedEntities + ); + + if ($input === null) { + throw new RegexException(sprintf( + 'preg_replace encountered an error with message "%s".', + preg_last_error_msg() + )); + } + + // 5.1. Let encodeOutput be an empty I/O queue. + // 5.2. Set potentialError to the result of running encode or fail with inputQueue, encoder, and + // encodeOutput. + $substituteChar = mb_substitute_character(); + mb_substitute_character('entity'); + $encodeOutput = mb_convert_encoding($input, $encoder, 'utf-8'); + mb_substitute_character($substituteChar); + + $chunks = preg_split('/&#x([[:xdigit:]]{2,6});/', $encodeOutput, -1, PREG_SPLIT_DELIM_CAPTURE); + + if ($chunks === false) { + throw new RegexException(sprintf( + 'preg_split encountered an error with message "%s".', + preg_last_error_msg() + )); + } + + // Replace the inserted placeholders of original numeric entities with the original text, so they get + // percent encoded. + if ($replacedEntities > 0) { + $chunks = preg_replace("/__{$this->randomBytes}_([[:xdigit:]]+;?)__/", '&#x${1}', $chunks); + + if ($chunks === null) { + throw new RegexException(sprintf( + 'preg_replace encountered an error with message "%s".', + preg_last_error_msg() + )); + } + } + } + + $chunks ??= [$input]; + + foreach ($chunks as $key => $bytes) { + // 5.4. If potentialError is non-null, then append "%26%23", followed by the shortest sequence of ASCII + // digits representing potentialError in base ten, followed by "%3B", to output. + // + // NOTE: This can happen when encoding is not UTF-8. + // + // Because we are splitting using the PREG_SPLIT_DELIM_CAPTURE_FLAG, odd keys contain the hex number of the + // numeric entity inserted during encoding conversion should an invalid character be encountered. + if ($key % 2 === 1) { + $output .= '%26%23' . hexdec($bytes) . '%3B'; + + continue; + } + + // 5.3. For each byte of encodeOutput converted to a byte sequence: + for ($i = 0, $length = strlen($bytes); $i < $length; ++$i) { + // 5.3.1. If spaceAsPlus is true and byte is 0x20 (SP), then append U+002B (+) to output and continue. + if ($spaceAsPlus && $bytes[$i] === "\x20") { + $output .= '+'; + + continue; + } + + // 5.3.2. Let isomorph be a code point whose value is byte’s value. + $isomorph = ord($bytes[$i]); + + // 5.3.4. If isomorph is not in percentEncodeSet, then append isomorph to output. + if (!$this->inEncodeSet($isomorph, $percentEncodeSet)) { + $output .= $bytes[$i]; + + continue; + } + + // 5.3.5. Otherwise, percent-encode byte and append the result to output. + $output .= rawurlencode($bytes[$i]); + } + } + + // 6. Return output. + return $output; + } + + /** + * @see https://url.spec.whatwg.org/#c0-control-percent-encode-set + * @see https://url.spec.whatwg.org/#fragment-percent-encode-set + * @see https://url.spec.whatwg.org/#query-percent-encode-set + * @see https://url.spec.whatwg.org/#special-query-percent-encode-set + * @see https://url.spec.whatwg.org/#path-percent-encode-set + * @see https://url.spec.whatwg.org/#userinfo-percent-encode-set + * @see https://url.spec.whatwg.org/#component-percent-encode-set + */ + private function inEncodeSet(int $codePoint, EncodeSet $percentEncodeSet): bool + { + switch ($percentEncodeSet) { + case EncodeSet::X_WWW_URLENCODED: + switch ($codePoint) { + case ord('!'): + case ord('\''): + case ord('('): + case ord(')'): + case ord('~'): + return true; + } + + // no break + + case EncodeSet::COMPONENT: + switch ($codePoint) { + case ord('$'): + case ord('%'): + case ord('&'): + case ord('+'): + case ord(','): + return true; + } + + // no break + + case EncodeSet::USERINFO: + switch ($codePoint) { + case ord('/'): + case ord(':'): + case ord(';'): + case ord('='): + case ord('@'): + case ord('['): + case ord('\\'): + case ord(']'): + case ord('^'): + case ord('|'): + return true; + } + + // no break + + case EncodeSet::PATH: + switch ($codePoint) { + case ord('?'): + case ord('`'): + case ord('{'): + case ord('}'): + return true; + + default: + $percentEncodeSet = EncodeSet::QUERY; + } + } + + switch ($percentEncodeSet) { + case EncodeSet::SPECIAL_QUERY: + if ($codePoint === ord('\'')) { + return true; + } + + // no break + + case EncodeSet::QUERY: + switch ($codePoint) { + case ord("\x20"): + case ord('"'): + case ord('#'): + case ord('<'): + case ord('>'): + return true; + } + + break; + + case EncodeSet::FRAGMENT: + switch ($codePoint) { + case ord("\x20"): + case ord('"'): + case ord('<'): + case ord('>'): + case ord('`'): + return true; + } + } + + // C0_CONTROL + return $codePoint < 0x20 || $codePoint > 0x7E; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/StringBuffer.php b/transfer-protocol/vendor/rowbot/url/src/String/StringBuffer.php new file mode 100644 index 0000000..a258567 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/StringBuffer.php @@ -0,0 +1,34 @@ +string) === 1; + } + + public function toInt(int $base = 10): int + { + return intval($this->string, $base); + } + + public function toPath(): PathSegment + { + return new PathSegment($this->string); + } + + public function toScheme(): Scheme + { + return new Scheme($this->string); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/StringBufferInterface.php b/transfer-protocol/vendor/rowbot/url/src/String/StringBufferInterface.php new file mode 100644 index 0000000..59b659d --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/StringBufferInterface.php @@ -0,0 +1,42 @@ + + */ +interface StringBufferInterface extends IteratorAggregate +{ + public function append(string $string): void; + + public function clear(): void; + + public function isEmpty(): bool; + + /** + * @see https://url.spec.whatwg.org/#windows-drive-letter + */ + public function isWindowsDriveLetter(): bool; + + public function length(): int; + + public function prepend(string $string): void; + + public function setCodePointAt(int $index, string $codePoint): void; + + public function toInt(int $base = 10): int; + + public function toPath(): PathSegment; + + public function toScheme(): Scheme; + + public function toUtf8String(): USVStringInterface; + + public function __toString(): string; +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/StringIteratorInterface.php b/transfer-protocol/vendor/rowbot/url/src/String/StringIteratorInterface.php new file mode 100644 index 0000000..c58f5ab --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/StringIteratorInterface.php @@ -0,0 +1,32 @@ + + */ +interface StringIteratorInterface extends SeekableIterator +{ + public function current(): string; + + public function key(): int; + + public function next(): void; + + public function peek(int $count = 1): string; + + public function prev(): void; + + /** + * @param int $position The position to seek to relative to the current position. + */ + public function seek(int $position): void; + + public function rewind(): void; + + public function valid(): bool; +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/StringList.php b/transfer-protocol/vendor/rowbot/url/src/String/StringList.php new file mode 100644 index 0000000..83bf911 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/StringList.php @@ -0,0 +1,12 @@ + + */ +class StringList extends AbstractStringList implements StringListInterface +{ +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/StringListInterface.php b/transfer-protocol/vendor/rowbot/url/src/String/StringListInterface.php new file mode 100644 index 0000000..48dca21 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/StringListInterface.php @@ -0,0 +1,36 @@ + + */ +interface StringListInterface extends Countable, IteratorAggregate +{ + /** + * @return \Rowbot\URL\String\USVStringInterface + */ + public function first(); + + public function isEmpty(): bool; + + /** + * @return \Rowbot\URL\String\USVStringInterface + */ + public function last(); + + /** + * @return \Rowbot\URL\String\USVStringInterface|null + */ + public function pop(); + + /** + * @param \Rowbot\URL\String\USVStringInterface $item + */ + public function push($item): void; +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/USVStringInterface.php b/transfer-protocol/vendor/rowbot/url/src/String/USVStringInterface.php new file mode 100644 index 0000000..e2c815e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/USVStringInterface.php @@ -0,0 +1,53 @@ + + */ +interface USVStringInterface extends IteratorAggregate +{ + public function append(string $string): self; + + public function endsWith(string $string): bool; + + public function getIterator(): StringIteratorInterface; + + public function isEmpty(): bool; + + public function length(): int; + + /** + * @param array $matches + * @param int-mask<0, 256, 512> $flags + */ + public function matches(string $pattern, ?array &$matches = null, int $flags = 0, int $offset = 0): bool; + + public function replaceRegex( + string $pattern, + string $replacement, + int $limit = -1, + int &$count = 0 + ): self; + + public function split(string $delimiter, ?int $limit = null): StringListInterface; + + public function startsWith(string $string): bool; + + public function startsWithTwoAsciiHexDigits(): bool; + + /** + * @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter + */ + public function startsWithWindowsDriveLetter(): bool; + + public function substr(int $start, ?int $length = null): self; + + public function toInt(int $base = 10): int; + + public function __toString(): string; +} diff --git a/transfer-protocol/vendor/rowbot/url/src/String/Utf8String.php b/transfer-protocol/vendor/rowbot/url/src/String/Utf8String.php new file mode 100644 index 0000000..261170b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/String/Utf8String.php @@ -0,0 +1,48 @@ + + */ + private array $codePoints; + + private int $cursor; + + public function __construct(string $string) + { + $this->codePoints = mb_str_split($string, 1, 'utf-8'); + $this->cursor = 0; + } + + public function current(): string + { + return $this->codePoints[$this->cursor] ?? ''; + } + + public function key(): int + { + return $this->cursor; + } + + public function next(): void + { + ++$this->cursor; + } + + public function peek(int $count = 1): string + { + if ($count === 1) { + return $this->codePoints[$this->cursor + 1] ?? ''; + } + + $output = ''; + $cursor = $this->cursor + 1; + + for ($i = 0; $i < $count; ++$i) { + if (!isset($this->codePoints[$cursor])) { + break; + } + + $output .= $this->codePoints[$cursor]; + ++$cursor; + } + + return $output; + } + + public function prev(): void + { + --$this->cursor; + } + + public function rewind(): void + { + $this->cursor = 0; + } + + public function seek($position): void + { + $this->cursor += $position; + } + + public function valid(): bool + { + return $this->cursor > -1 && isset($this->codePoints[$this->cursor]); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/Support/EncodingHelper.php b/transfer-protocol/vendor/rowbot/url/src/Support/EncodingHelper.php new file mode 100644 index 0000000..e3282f3 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/Support/EncodingHelper.php @@ -0,0 +1,38 @@ +logger = null; + + if (isset($options['logger'])) { + if (!$options['logger'] instanceof LoggerInterface) { + throw new TypeError(sprintf( + 'The passed logger must be null or an instance of %s', + LoggerInterface::class + )); + } + + $this->logger = $options['logger']; + } + + // 1. Let parsedURL be the result of running the API URL parser on url with base, if given. + $parsedURL = self::parseURL($url, $base, $this->logger); + + if ($parsedURL->error === APIParserErrorType::NONE) { + // 3. Initialize this with parsedURL. + assert($parsedURL->url !== null); + self::initializeURL($this, $parsedURL->url); + + return; + } + + // 2. If parsedURL is failure, then throw a TypeError. + $message = match ($parsedURL->error) { + APIParserErrorType::BASE => 'Invalid base URL', + APIParserErrorType::URL => 'Invalid URL' + }; + + throw new TypeError($message); + } + + /** + * @see https://url.spec.whatwg.org/#dom-url-parse + */ + public static function parse(string|Stringable $url, string|Stringable|null $base = null): ?self + { + try { + return new self($url, $base); + } catch (Throwable) { + return null; + } + } + + /** + * @see https://url.spec.whatwg.org/#dom-url-canparse + */ + public static function canParse(string|Stringable $url, string|Stringable|null $base = null): bool + { + $parsedURL = self::parseURL($url, $base); + + return $parsedURL->error === APIParserErrorType::NONE; + } + + public function toString(): string + { + return $this->url->serializeURL(); + } + + /** + * Returns a JSON encoded string without escaping forward slashes. If you + * need forward slashes to be escaped, pass the URL object to json_encode() + * instead of calling this method. + * + * @see https://url.spec.whatwg.org/#dom-url-tojson + */ + public function toJSON(): string + { + // Use JSON_UNESCAPED_SLASHES here since JavaScript's JSON.stringify() + // method does not escape forward slashes by default. + return json_encode($this->url->serializeURL(), JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES); + } + + /** + * Returns the serialized URL for consumption by json_encode(). To match + * JavaScript's behavior, you should pass the JSON_UNESCAPED_SLASHES option + * to json_encode(). + */ + public function jsonSerialize(): string + { + return $this->url->serializeURL(); + } + + /** + * @see https://url.spec.whatwg.org/#api-url-parser + */ + private static function parseURL( + string|Stringable $url, + string|Stringable|null $base = null, + ?LoggerInterface $logger = null + ): APIParserResult { + // 1. Let parsedBase be null. + $parsedBase = null; + $parser = new BasicURLParser($logger); + + // 2. If base is non-null: + if ($base !== null) { + // 2.1. Set parsedBase to the result of running the basic URL parser on base. + $stringBase = (string) $base; + $parsedBase = $parser->parse(Utf8String::fromUnsafe($stringBase)); + + // 2.2. If parsedBase is failure, then return failure. + if ($parsedBase === false) { + return new APIParserResult(null, APIParserErrorType::BASE); + } + } + + // 3. Return the result of running the basic URL parser on url with parsedBase. + $stringURL = (string) $url; + $parsedURL = $parser->parse(Utf8String::fromUnsafe($stringURL), $parsedBase); + + if ($parsedURL === false) { + return new APIParserResult(null, APIParserErrorType::URL); + } + + return new APIParserResult($parsedURL, APIParserErrorType::NONE); + } + + /** + * @see https://url.spec.whatwg.org/#url-initialize + */ + private static function initializeURL(self $url, URLRecord $urlRecord): void + { + // 1. Let query be urlRecord’s query, if that is non-null; otherwise the empty string. + $query = $urlRecord->query ?? ''; + + // 2. Set url’s URL to urlRecord. + $url->url = $urlRecord; + + // 3. Set url’s query object to a new URLSearchParams object. + $url->queryObject = new URLSearchParams(); + + // 4. Initialize url’s query object with query. + $url->queryObject->setList(QueryList::fromString($query)); + + // 5. Set url’s query object’s URL object to url. + $url->queryObject->setUrl($urlRecord); + } + + public function __clone(): void + { + $this->url = clone $this->url; + $this->queryObject = clone $this->queryObject; + $this->queryObject->setUrl($this->url); + } + + /** + * @throws \InvalidArgumentException When an invalid $name value is passed. + */ + public function __get(string $name): string|URLSearchParams + { + if ($name === 'hash') { + if ($this->url->fragment === null || $this->url->fragment === '') { + return ''; + } + + return '#' . $this->url->fragment; + } + + if ($name === 'host') { + if ($this->url->host->isNull()) { + return ''; + } + + $serializer = $this->url->host->getSerializer(); + + if ($this->url->port === null) { + return $serializer->toFormattedString(); + } + + return $serializer->toFormattedString() . ':' . $this->url->port; + } + + if ($name === 'hostname') { + if ($this->url->host->isNull()) { + return ''; + } + + return $this->url->host->getSerializer()->toFormattedString(); + } + + if ($name === 'href') { + return $this->url->serializeURL(); + } + + if ($name === 'origin') { + return (string) $this->url->getOrigin(); + } + + if ($name === 'password') { + return $this->url->password; + } + + if ($name === 'pathname') { + return (string) $this->url->path; + } + + if ($name === 'port') { + if ($this->url->port === null) { + return ''; + } + + return (string) $this->url->port; + } + + if ($name === 'protocol') { + return $this->url->scheme . ':'; + } + + if ($name === 'search') { + if ($this->url->query === null || $this->url->query === '') { + return ''; + } + + return '?' . $this->url->query; + } + + if ($name === 'searchParams') { + return $this->queryObject; + } + + if ($name === 'username') { + return $this->url->username; + } + + throw new InvalidArgumentException(sprintf('"%s" is not a valid property.', $name)); + } + + /** + * @throws \InvalidArgumentException When an invalid $name or $value value is passed. + * @throws \Rowbot\URL\Exception\TypeError Only when trying to set URL::$searchParams + */ + public function __set(string $name, string $value): void + { + if ($name === 'searchParams') { + throw new TypeError('Cannot redefine the searchParams property.'); + } + + $input = Utf8String::fromUnsafe($value); + $parser = new BasicURLParser($this->logger); + + if ($name === 'hash') { + if ($input->isEmpty()) { + $this->url->fragment = null; + $this->url->path->potentiallyStripTrailingSpaces($this->url); + + // Terminate these steps + return; + } + + if ($input->startsWith('#')) { + $input = $input->substr(1); + } + + $this->url->fragment = ''; + $parser->parse($input, null, null, $this->url, ParserState::FRAGMENT); + } elseif ($name === 'host') { + if ($this->url->path->isOpaque()) { + // Terminate these steps + return; + } + + $parser->parse($input, null, null, $this->url, ParserState::HOST); + } elseif ($name === 'hostname') { + if ($this->url->path->isOpaque()) { + // Terminate these steps + return; + } + + $parser->parse($input, null, null, $this->url, ParserState::HOSTNAME); + } elseif ($name === 'href') { + $parsedURL = $parser->parse($input); + + if ($parsedURL === false) { + throw new TypeError(sprintf('"%s" is not a valid URL.', $value)); + } + + $this->url = $parsedURL; + $this->queryObject->setUrl($this->url); + + if ($this->url->query === null) { + return; + } + + $this->queryObject->setList(QueryList::fromString($this->url->query)); + } elseif ($name === 'password') { + if ($this->url->cannotHaveUsernamePasswordPort()) { + return; + } + + $this->url->setPassword($input); + } elseif ($name === 'pathname') { + if ($this->url->path->isOpaque()) { + // Terminate these steps + return; + } + + $this->url->path = new PathList(); + $parser->parse($input, null, null, $this->url, ParserState::PATH_START); + } elseif ($name === 'port') { + if ($this->url->cannotHaveUsernamePasswordPort()) { + return; + } + + if ($value === '') { + $this->url->port = null; + + return; + } + + $parser->parse($input, null, null, $this->url, ParserState::PORT); + } elseif ($name === 'protocol') { + $parser->parse($input->append(':'), null, null, $this->url, ParserState::SCHEME_START); + } elseif ($name === 'search') { + if ($value === '') { + $this->url->query = null; + $this->queryObject->setList(new QueryList()); + $this->url->path->potentiallyStripTrailingSpaces($this->url); + + return; + } + + if ($input->startsWith('?')) { + $input = $input->substr(1); + } + + $this->url->query = ''; + $parser->parse($input, null, null, $this->url, ParserState::QUERY); + $this->queryObject->setList(QueryList::fromString((string) $input)); + } elseif ($name === 'username') { + if ($this->url->cannotHaveUsernamePasswordPort()) { + return; + } + + $this->url->setUsername($input); + } else { + throw new InvalidArgumentException(sprintf('"%s" is not a valid property.', $name)); + } + } + + public function __toString(): string + { + return $this->url->serializeURL(); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/URLRecord.php b/transfer-protocol/vendor/rowbot/url/src/URLRecord.php new file mode 100644 index 0000000..c5403ea --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/URLRecord.php @@ -0,0 +1,228 @@ +scheme = new Scheme(); + $this->username = ''; + $this->password = ''; + $this->host = new NullHost(); + $this->port = null; + $this->path = new PathList(); + $this->query = null; + $this->fragment = null; + } + + /** + * Whether or not a URL can have a username, password, or port set. + * + * @see https://url.spec.whatwg.org/#cannot-have-a-username-password-port + */ + public function cannotHaveUsernamePasswordPort(): bool + { + return $this->host->isNull() || $this->host->isEmpty() || $this->scheme->isFile(); + } + + /** + * Whether or not the URL has a username or password. + * + * @see https://url.spec.whatwg.org/#include-credentials + */ + public function includesCredentials(): bool + { + return $this->username !== '' || $this->password !== ''; + } + + /** + * Computes a URL's origin. + * + * @see https://url.spec.whatwg.org/#origin + */ + public function getOrigin(): Origin + { + if ($this->scheme->isBlob()) { + $parser = new BasicURLParser(); + $url = $parser->parse($this->path->first()->toUtf8String()); + + if ($url === false) { + // Return a new opaque origin + return new OpaqueOrigin(); + } + + return match ((string) $url->scheme) { + 'https', 'http', 'file' => $url->getOrigin(), + default => new OpaqueOrigin(), + }; + } + + if ($this->scheme->isFile()) { + // Unfortunate as it is, this is left as an exercise to the + // reader. When in doubt, return a new opaque origin. + return new OpaqueOrigin(); + } + + if ($this->scheme->isSpecial()) { + // Return a tuple consiting of URL's scheme, host, port, and null + return new TupleOrigin((string) $this->scheme, $this->host, $this->port); + } + + // Return a new opaque origin. + return new OpaqueOrigin(); + } + + /** + * Determines whether two URLs are equal to eachother. + * + * @see https://url.spec.whatwg.org/#concept-url-equals + * + * @param bool $excludeFragment (optional) determines whether a URL's fragment should be factored into equality. + */ + public function isEqual(self $otherUrl, bool $excludeFragment = false): bool + { + return $this->serializeURL($excludeFragment) === $otherUrl->serializeURL($excludeFragment); + } + + /** + * Serializes a URL object. + * + * @see https://url.spec.whatwg.org/#concept-url-serializer + * + * @param bool $excludeFragment (optional) When specified it will exclude the URL's fragment from being serialized. + */ + public function serializeURL(bool $excludeFragment = false): string + { + $output = $this->scheme . ':'; + $isNullHost = $this->host->isNull(); + + if (!$isNullHost) { + $output .= '//'; + + if ($this->username !== '' || $this->password !== '') { + $output .= $this->username; + + if ($this->password !== '') { + $output .= ':' . $this->password; + } + + $output .= '@'; + } + + $output .= $this->host->getSerializer()->toFormattedString(); + + if ($this->port !== null) { + $output .= ':' . $this->port; + } + } + + // 3. If url’s host is null, url does not have an opaque path, url’s path’s size is greater than 1, and url’s + // path[0] is the empty string, then append U+002F (/) followed by U+002E (.) to output. + if ($isNullHost && !$this->path->isOpaque() && $this->path->count() > 1 && $this->path->first()->isEmpty()) { + // NOTE: This prevents web+demo:/.//not-a-host/ or web+demo:/path/..//not-a-host/, when parsed and then + // serialized, from ending up as web+demo://not-a-host/ (they end up as web+demo:/.//not-a-host/) + $output .= '/.'; + } + + // 4. Append the result of URL path serializing url to output. + $output .= $this->path; + + // 5. If url’s query is non-null, append U+003F (?), followed by url’s query, to output. + if ($this->query !== null) { + $output .= '?' . $this->query; + } + + // 6. If exclude fragment is false and url’s fragment is non-null, then append U+0023 (#), followed by url’s + // fragment, to output. + if (!$excludeFragment && $this->fragment !== null) { + $output .= '#' . $this->fragment; + } + + // 7. Return output. + return $output; + } + + /** + * @see https://url.spec.whatwg.org/#set-the-password + */ + public function setPassword(USVStringInterface $input): void + { + $percentEncoder = new PercentEncoder(); + $this->password = $percentEncoder->percentEncodeAfterEncoding( + 'utf-8', + (string) $input, + EncodeSet::USERINFO + ); + } + + /** + * @see https://url.spec.whatwg.org/#set-the-username + */ + public function setUsername(USVStringInterface $input): void + { + $percentEncoder = new PercentEncoder(); + $this->username = $percentEncoder->percentEncodeAfterEncoding( + 'utf-8', + (string) $input, + EncodeSet::USERINFO + ); + } + + public function __clone(): void + { + $this->scheme = clone $this->scheme; + $this->host = clone $this->host; + $this->path = clone $this->path; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/src/URLSearchParams.php b/transfer-protocol/vendor/rowbot/url/src/URLSearchParams.php new file mode 100644 index 0000000..650d81b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/src/URLSearchParams.php @@ -0,0 +1,414 @@ + + * + * @property-read int<0, max> $size + */ +class URLSearchParams implements Countable, Iterator, Stringable +{ + /** + * @var 0|positive-int + */ + private int $cursor; + + private QueryList $list; + + private ?URLRecord $url; + + /** + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams + * + * @param iterable|(\Traversable&\Countable)>|object|string|\Stringable $init + */ + public function __construct(array|object|string $init = '') + { + $this->list = new QueryList(); + $this->url = null; + $this->cursor = 0; + + if (func_num_args() < 1) { + return; + } + + if ($this->isStringable($init)) { + $init = Utf8String::scrub((string) $init); + + if ($init !== '' && $init[0] === '?') { + $init = substr($init, 1); + } + + $this->list = QueryList::fromString($init); + + return; + } + + if (is_iterable($init)) { + $this->initIterator($init); + + return; + } + + if (is_object($init)) { + $this->initObject($init); + + return; + } + } + + /** + * Appends a new name-value pair to the end of the query string. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-append + * + * @param string $name The name of the key in the pair. + * @param string $value The value assigned to the key. + */ + public function append(string $name, string $value): void + { + $this->list->append(Utf8String::scrub($name), Utf8String::scrub($value)); + $this->update(); + } + + public function count(): int + { + return $this->list->count(); + } + + /** + * @return array{0: string, 1: string}|null + */ + public function current(): array|null + { + $tuple = $this->list->getTupleAt($this->cursor); + + if ($tuple === null) { + return null; + } + + return [$tuple['name'], $tuple['value']]; + } + + /** + * Deletes all occurances of pairs with the specified key name. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-delete + * + * @param string $name The name of the key to delete. + */ + public function delete(string $name, ?string $value = null): void + { + if ($value !== null) { + $value = Utf8String::scrub($value); + } + + $this->list->remove(Utf8String::scrub($name), $value); + $this->update(); + } + + /** + * Get the value of the first name-value pair with the specified key name. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-get + * + * @param string $name The name of the key whose value you want to retrive. + * + * @return string|null The value of the specified key. + */ + public function get(string $name): ?string + { + return $this->list->first(Utf8String::scrub($name)); + } + + /** + * Gets all name-value pairs that has the specified key name. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-getall + * + * @param string $name The name of the key whose values you want to retrieve. + * + * @return array An array containing all the values of the specified key. + */ + public function getAll(string $name): array + { + $name = Utf8String::scrub($name); + + return array_column($this->list->filter(static fn(array $pair): bool => $pair['name'] === $name), 'value'); + } + + /** + * Indicates whether or not a query string contains any keys with the specified key name. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-has + * + * @param string $name The key name you want to test if it exists. + * + * @return bool Returns true if the key exits, otherwise false. + */ + public function has(string $name, ?string $value = null): bool + { + if ($value !== null) { + $value = Utf8String::scrub($value); + } + + return $this->list->contains(Utf8String::scrub($name), $value); + } + + public function key(): int + { + return $this->cursor; + } + + public function next(): void + { + ++$this->cursor; + } + + public function rewind(): void + { + $this->cursor = 0; + } + + /** + * Sets the value of the specified key name. If multiple pairs exist with the same key name it + * will set the value for the first occurance of the key in the query string and all other + * occurances will be removed from the query string. If the key does not already exist in the + * query string, it will be added to the end of the query string. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-set + * + * @param string $name The name of the key you want to modify the value of. + * @param string $value The value you want to associate with the key name. + */ + public function set(string $name, string $value): void + { + $name = Utf8String::scrub($name); + $value = Utf8String::scrub($value); + + if ($this->list->contains($name)) { + $this->list->set($name, $value); + } else { + $this->list->append($name, $value); + } + + $this->update(); + } + + /** + * @internal + */ + public function setList(QueryList $list): void + { + $this->list = $list; + } + + /** + * Sets the associated url record. + * + * @internal + */ + public function setUrl(URLRecord $url): void + { + $this->url = $url; + } + + /** + * Sorts the list of search params by their names by comparing their code unit values, + * preserving the relative order between pairs with the same name. + * + * @see https://url.spec.whatwg.org/#dom-urlsearchparams-sort + */ + public function sort(): void + { + $this->list->sort(); + $this->update(); + } + + public function toString(): string + { + return $this->list->toUrlencodedString(); + } + + /** + * @phpstan-assert-if-true array{0: string, 1: string} $this->current() + */ + public function valid(): bool + { + return $this->list->getTupleAt($this->cursor) !== null; + } + + /** + * Set's the associated URL object's query to the serialization of URLSearchParams. + * + * @see https://url.spec.whatwg.org/#concept-urlsearchparams-update + * + * @internal + */ + protected function update(): void + { + if ($this->url === null) { + return; + } + + $query = $this->list->toUrlencodedString(); + + if ($query === '') { + $query = null; + } + + $this->url->query = $query; + + if ($query === null) { + $this->url->path->potentiallyStripTrailingSpaces($this->url); + } + } + + /** + * @param iterable&\Countable> $input + * + * @throws \Rowbot\URL\Exception\TypeError + */ + private function initIterator(iterable $input): void + { + foreach ($input as $key => $pair) { + // Try to catch cases where $pair isn't countable or $pair is + // countable, but isn't a valid sequence, such as: + // + // class CountableClass implements \Countable + // { + // public function count() + // { + // return 2; + // } + // } + // + // $s = new \Rowbot\URL\URLSearchParams([new CountableClass()]); + // + // or: + // + // $a = new \ArrayObject(['x', 'y']); + // $s = new \Rowbot\URL\URLSearchParams($a); + // + // while still allowing things like: + // + // $a = new \ArrayObject(new \ArrayObject(['x', 'y'])); + // $s = new \Rowbot\URL\URLSearchParams($a);' + if (!is_countable($pair) || !is_iterable($pair)) { + throw new TypeError(sprintf( + 'Expected a valid sequence such as an Array or iterable Object that implements ' + . 'the \\Countable interface. %s found instead.', + get_debug_type($pair) + )); + } + + if (count($pair) !== 2) { + throw new TypeError(sprintf( + 'Expected sequence with exactly 2 items. Sequence contained %d items.', + count($pair) + )); + } + + [$name, $value] = $pair; + + if (!$this->isStringable($name)) { + throw new TypeError(sprintf( + 'The name of the name-value pair at index "%s" must be a scalar value or stringable.', + $key + )); + } + + if (!$this->isStringable($value)) { + throw new TypeError(sprintf( + 'The value of the name-value pair at index "%s" must be a scalar value or stringable.', + $key + )); + } + + $this->list->append(Utf8String::scrub((string) $name), Utf8String::scrub((string) $value)); + } + } + + private function initObject(object $input): void + { + $reflection = new ReflectionObject($input); + + foreach ($reflection->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { + $value = $property->getValue($input); + + if (!$this->isStringable($value)) { + throw new TypeError(sprintf( + 'The value of property "%s" must be a scalar value or \\Stringable.', + $reflection->getName() + )); + } + + $this->list->append(Utf8String::scrub($property->getName()), Utf8String::scrub((string) $value)); + } + } + + /** + * @phpstan-assert-if-true scalar|\Stringable $value + */ + private function isStringable(mixed $value): bool + { + return $value instanceof Stringable || is_scalar($value); + } + + public function __clone(): void + { + $this->list = clone $this->list; + + // Null out the url in-case someone tries cloning the object returned by + // the URL::searchParams attribute. + $this->url = null; + } + + /** + * @return mixed + */ + public function __get(string $name) + { + return match ($name) { + 'size' => $this->list->count(), + default => null, + }; + } + + /** + * Returns all name-value pairs stringified in the correct order. + */ + public function __toString(): string + { + return $this->list->toUrlencodedString(); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/EncodingHelperTest.php b/transfer-protocol/vendor/rowbot/url/tests/EncodingHelperTest.php new file mode 100644 index 0000000..369d065 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/EncodingHelperTest.php @@ -0,0 +1,22 @@ +getIterator(), new StringBuffer(), new URLRecord(), null, null, null, null); + + foreach ($output as $i => $expected) { + $isOpaque = $i % 2 === 1; + $host = $parser->parse($context, $in, $isOpaque); + + if ($expected === false) { + self::assertFalse($host); + } else { + self::assertInstanceOf(HostInterface::class, $host); + self::assertSame($expected, $host->getSerializer()->toFormattedString()); + } + } + } + + public static function exampleDataProvider(): array + { + return [ + ['input' => 'EXAMPLE.COM', 'output' => ['example.com', 'EXAMPLE.COM']], + ['input' => 'example%2Ecom', 'output' => ['example.com', 'example%2Ecom']], + ['input' => 'faß.example', 'output' => ['xn--fa-hia.example', 'fa%C3%9F.example']], + ['input' => '0', 'output' => ['0.0.0.0', '0']], + ['input' => '%30', 'output' => ['0.0.0.0', '%30']], + ['input' => '0x', 'output' => ['0.0.0.0', '0x']], + ['input' => '0xffffffff', 'output' => ['255.255.255.255', '0xffffffff']], + ['input' => '[0:0::1]', 'output' => ['[::1]', '[::1]']], + ['input' => '[0:0::1%5D', 'output' => [false, false]], + ['input' => '[0:0::%31]', 'output' => [false, false]], + ['input' => '09', 'output' => [false, '09']], + ['input' => 'example.255', 'output' => [false, 'example.255']], + ['input' => 'example^example', 'output' => [false, false]], + ]; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/Math/BrickMathAdapterTest.php b/transfer-protocol/vendor/rowbot/url/tests/Math/BrickMathAdapterTest.php new file mode 100644 index 0000000..851dde4 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/Math/BrickMathAdapterTest.php @@ -0,0 +1,36 @@ +expectException(MathException::class); + (new BrickMathAdapter(42))->isEqualTo(new NativeIntAdapter(42)); + } + + public function testIsGreaterThanOrEqualToError(): void + { + $this->expectException(MathException::class); + (new BrickMathAdapter(42))->isGreaterThanOrEqualTo(new NativeIntAdapter(42)); + } + + public function testPlusError(): void + { + $this->expectException(MathException::class); + (new BrickMathAdapter(42))->plus(new NativeIntAdapter(42)); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/Math/MathTestCase.php b/transfer-protocol/vendor/rowbot/url/tests/Math/MathTestCase.php new file mode 100644 index 0000000..c07ca7a --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/Math/MathTestCase.php @@ -0,0 +1,115 @@ +createNumber(42); + $computedQuotient = $dividend->intdiv($divisor); + + self::assertTrue($computedQuotient->isEqualTo($this->createNumber($quoient))); + self::assertSame($quoient, (string) $computedQuotient); + } + + public static function equalityNumberProvider(): array + { + return [ + [PHP_INT_MAX, 10, (string) PHP_INT_MAX], + ['01234567', 8, '342391'], + ['DF', 16, '223'], + ['-24', 10, '-24'], + ]; + } + + #[DataProvider('equalityNumberProvider')] + public function testIsEqualTo(int|string $number, int $base, string $expected): void + { + self::assertTrue($this->createNumber($number, $base)->isEqualTo($this->createNumber($expected))); + } + + #[TestWith([42, 9000, false])] + #[TestWith([9000, 42, true])] + #[TestWith([42, 42, false])] + #[TestWith([-2, -3, true])] + public function testIsGreaterThan(int $number1, int $number2, bool $result): void + { + self::assertSame($result, $this->createNumber($number1)->isGreaterThan($number2)); + } + + #[TestWith([42, 9000, false])] + #[TestWith([9000, 42, true])] + #[TestWith([42, 42, true])] + #[TestWith([-2, -3, true])] + public function testIsGreaterThanOrEqualTo(int $number1, int $number2, bool $result): void + { + self::assertSame($result, $this->createNumber($number1)->isGreaterThanOrEqualTo($this->createNumber($number2))); + } + + #[TestWith([2, 2, 0])] + #[TestWith([5, 3, 2])] + #[TestWith([17, 6, 5])] + public function testMod(int $dividend, int $divisor, int $remainder): void + { + $computedRemainder = $this->createNumber($dividend)->mod($divisor); + + self::assertTrue($computedRemainder->isEqualTo($this->createNumber($remainder))); + self::assertSame((string) $remainder, (string) $computedRemainder); + } + + #[TestWith([7, 2, 14])] + #[TestWith([5, 3, 15])] + #[TestWith([17, 6, 102])] + #[TestWith([-4, 3, -12])] + public function testMultipliedBy(int $multiplicand, int $multiplier, int $product): void + { + $computedProduct = $this->createNumber($multiplicand)->multipliedBy($multiplier); + + self::assertTrue($computedProduct->isEqualTo($this->createNumber($product))); + self::assertSame((string) $product, (string) $computedProduct); + } + + #[TestWith([6, 6, '12'])] + #[TestWith([4, -3, '1'])] + #[TestWith([-256, 6, '-250'])] + public function testPlus(int $addend1, int $addend2, string $sum): void + { + $computedSum = $this->createNumber($addend1)->plus($this->createNumber($addend2)); + + self::assertTrue($computedSum->isEqualTo($this->createNumber($sum))); + self::assertSame($sum, (string) $computedSum); + } + + #[TestWith([256, 2, '65536'])] + #[TestWith([2, 2, '4'])] + public function testPow(int $base, int $exponent, string $power): void + { + $computedPower = $this->createNumber($base)->pow($exponent); + + self::assertTrue($computedPower->isEqualTo($this->createNumber($power))); + self::assertSame($power, (string) $computedPower); + } + + #[DataProvider('equalityNumberProvider')] + public function testToString(int|string $number, int $base, string $result): void + { + self::assertSame($result, (string) $this->createNumber($number, $base)); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/Math/NativeIntAdapterTest.php b/transfer-protocol/vendor/rowbot/url/tests/Math/NativeIntAdapterTest.php new file mode 100644 index 0000000..60f3c69 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/Math/NativeIntAdapterTest.php @@ -0,0 +1,36 @@ +expectException(MathException::class); + (new NativeIntAdapter(42))->isEqualTo(new BrickMathAdapter(42)); + } + + public function testIsGreaterThanOrEqualToError(): void + { + $this->expectException(MathException::class); + (new NativeIntAdapter(42))->isGreaterThanOrEqualTo(new BrickMathAdapter(42)); + } + + public function testPlusError(): void + { + $this->expectException(MathException::class); + (new NativeIntAdapter(42))->plus(new BrickMathAdapter(42)); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/NullHostTest.php b/transfer-protocol/vendor/rowbot/url/tests/NullHostTest.php new file mode 100644 index 0000000..5eff2fe --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/NullHostTest.php @@ -0,0 +1,28 @@ +getSerializer(); + self::assertEmpty($serializer->toFormattedString()); + self::assertEmpty($serializer->toString()); + } + + public function testNullHostIsEqualOnlyToItself(): void + { + $host = new NullHost(); + self::assertTrue($host->equals($host)); + self::assertTrue($host->equals(new NullHost())); + self::assertFalse($host->equals(new StringHost())); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/OriginTest.php b/transfer-protocol/vendor/rowbot/url/tests/OriginTest.php new file mode 100644 index 0000000..8885166 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/OriginTest.php @@ -0,0 +1,212 @@ +parse($context, new Utf8String('example.org'), false), + null, + null + ); + $tupleDomain = new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + null, + 'example.org' + ); + $opaque = new OpaqueOrigin(); + $urlParser = new BasicURLParser(); + + return [ + [ + $tuple, + new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + null, + null + ), + 'isSameOrigin' => true, + 'isSameOriginDomain' => true, + ], + [ + new TupleOrigin('https', $hostParser->parse($context, new Utf8String('example.org'), false), 314, null), + new TupleOrigin('https', $hostParser->parse($context, new Utf8String('example.org'), false), 420, null), + 'isSameOrigin' => false, + 'isSameOriginDomain' => false, + ], + [ + new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + 314, + 'example.org' + ), + new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + 420, + 'example.org' + ), + 'isSameOrigin' => false, + 'isSameOriginDomain' => true, + ], + [ + new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + null, + null + ), + new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + null, + 'example.org' + ), + 'isSameOrigin' => true, + 'isSameOriginDomain' => false, + ], + [ + new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + null, + 'example.org' + ), + new TupleOrigin( + 'http', + $hostParser->parse($context, new Utf8String('example.org'), false), + null, + 'example.org' + ), + 'isSameOrigin' => false, + 'isSameOriginDomain' => false, + ], + [ + new TupleOrigin('https', $hostParser->parse($context, new Utf8String('127.0.0.1'), false), null, null), + new TupleOrigin('https', $hostParser->parse($context, new Utf8String('1.1.1.1'), false), null, null), + 'isSameOrigin' => false, + 'isSameOriginDomain' => false, + ], + [ + new TupleOrigin('https', $hostParser->parse($context, new Utf8String('[::1]'), false), null, null), + new TupleOrigin('https', $hostParser->parse($context, new Utf8String('[1::1]'), false), null, null), + 'isSameOrigin' => false, + 'isSameOriginDomain' => false, + ], + [ + $urlParser->parse(new Utf8String('blob:https://foo.com'))->getOrigin(), + $urlParser->parse(new Utf8String('https://foo.com'))->getOrigin(), + 'isSameOrigin' => true, + 'isSameOriginDomain' => true, + ], + [ + $tuple, + $tuple, + 'isSameOrigin' => true, + 'isSameOriginDomain' => true, + ], + [ + $tuple, + $tupleDomain, + 'isSameOrigin' => true, + 'isSameOriginDomain' => false, + ], + [ + $opaque, + new OpaqueOrigin(), + 'isSameOrigin' => false, + 'isSameOriginDomain' => false, + ], + [ + $opaque, + $opaque, + 'isSameOrigin' => true, + 'isSameOriginDomain' => true, + ], + [ + $tuple, + $opaque, + 'isSameOrigin' => false, + 'isSameOriginDomain' => false, + ], + ]; + } + + #[DataProvider('originProvider')] + public function testSameOriginConcept( + Origin $originA, + Origin $originB, + bool $isSameOrigin, + bool $isSameOriginDomain + ): void { + self::assertSame($isSameOrigin, $originA->isSameOrigin($originB)); + self::assertSame($isSameOriginDomain, $originA->isSameOriginDomain($originB)); + } + + public function testEffectiveDomainConcept(): void + { + $origin = new OpaqueOrigin(); + self::assertTrue($origin->isOpaque()); + self::assertNull($origin->getEffectiveDomain()); + + $parser = new BasicURLParser(); + $record = $parser->parse(new Utf8String('blob:https://foo.com')); + $origin = $record->getOrigin(); + self::assertFalse($origin->isOpaque()); + self::assertNotNull($origin->getEffectiveDomain()); + self::assertSame('foo.com', $origin->getEffectiveDomain()); + + $hostParser = new HostParser(); + $context = new ParserContext( + new Utf8String(''), + new Utf8StringIterator(''), + new StringBuffer(''), + new URLRecord(), + null, + null, + null, + null + ); + $origin = new TupleOrigin( + 'https', + $hostParser->parse($context, new Utf8String('example.org'), false), + 314, + 'example.org' + ); + self::assertFalse($origin->isOpaque()); + self::assertNotNull($origin->getEffectiveDomain()); + self::assertSame('example.org', $origin->getEffectiveDomain()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/PathTest.php b/transfer-protocol/vendor/rowbot/url/tests/PathTest.php new file mode 100644 index 0000000..64def45 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/PathTest.php @@ -0,0 +1,54 @@ +isNormalizedWindowsDriveLetter()); + } + + public function testOpaquePathThrowsOnShorten(): void + { + $path = new OpaquePath(new PathSegment()); + $this->expectException(URLException::class); + $path->shorten(new Scheme('file')); + } + + public function testOpaquePathThrowsOnPush(): void + { + $path = new OpaquePath(new PathSegment()); + $this->expectException(URLException::class); + $path->push(new PathSegment()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/QueryListTest.php b/transfer-protocol/vendor/rowbot/url/tests/QueryListTest.php new file mode 100644 index 0000000..d1d3b31 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/QueryListTest.php @@ -0,0 +1,22 @@ + 'a', 'value' => 'b'], + ['name' => 'a', 'value' => 'c'], + ]; + $list = new QueryList($input); + $list->set('Foo', 'Bar'); + self::assertSame($input, $list->getIterator()->getArrayCopy()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/QueryStateTest.php b/transfer-protocol/vendor/rowbot/url/tests/QueryStateTest.php new file mode 100644 index 0000000..8908e54 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/QueryStateTest.php @@ -0,0 +1,47 @@ +parse($input, null, 'windows-1252'); + + self::assertInstanceOf(URLRecord::class, $record); + self::assertSame('sm%F6rg%E5sbord', $record->query); + + $record = $parser->parse($input, null); + + self::assertInstanceOf(URLRecord::class, $record); + self::assertSame('sm%C3%B6rg%C3%A5sbord', $record->query); + } + + public function testParsingWebsocketForcesUtf8EncodingInQueryString(): void + { + $string = 'wss://example.com/?' . html_entity_decode('smörgåsbord', ENT_HTML5, 'utf-8'); + $input = new Utf8String($string); + $parser = new BasicURLParser(); + $record = $parser->parse($input, null, 'windows-1252'); + + self::assertInstanceOf(URLRecord::class, $record); + self::assertSame('sm%C3%B6rg%C3%A5sbord', $record->query); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/SchemeTest.php b/transfer-protocol/vendor/rowbot/url/tests/SchemeTest.php new file mode 100644 index 0000000..2f99681 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/SchemeTest.php @@ -0,0 +1,45 @@ +getConstant('SPECIAL_SCHEMES'); + + foreach ($schemes as $scheme => $port) { + if ($port === null) { + continue; + } + + yield [$scheme, $port]; + } + } + + #[DataProvider('specialSchemeNonNullDefaultPortProvider')] + public function testIsDefaultPortReturnsTrueForNonNullPortSpecialSchemes(string $scheme, int $port): void + { + $scheme = new Scheme($scheme); + self::assertTrue($scheme->isDefaultPort($port)); + } + + #[TestWith(['sftp', 22])] + #[TestWith(['ssh', 22])] + #[TestWith(['smtp', 25])] + #[TestWith(['file', null])] // special scheme, but has no default port + public function testIsDefaultPortReturnsFalseForNonSpecialSchemesAndNullPorts(string $scheme, ?int $port): void + { + $scheme = new Scheme($scheme); + self::assertFalse($scheme->isDefaultPort($port)); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/StringsTest.php b/transfer-protocol/vendor/rowbot/url/tests/StringsTest.php new file mode 100644 index 0000000..8f2f4dd --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/StringsTest.php @@ -0,0 +1,120 @@ +expectException(ValueError::class); + Utf8String::transcode('stuff', 'gallifreyan', 'utf-8'); + } + + public static function startsWithTwoAsciiHexDigitsProvider(): array + { + return [ + ['ab', true], + ['a', false], + ['99', true], + ['a3', true], + ['3a', true], + ['a4x', true], + ['AB', true], + ['3F', true], + ['gab', false], + ['', false], + ]; + } + + #[DataProvider('startsWithTwoAsciiHexDigitsProvider')] + public function testStartsWithTwoAsciiHexDigits(string $input, bool $expected): void + { + $s = new Utf8String($input); + self::assertSame($expected, $s->startsWithTwoAsciiHexDigits()); + } + + public static function startsWithWindowsDriveLetterProvider(): array + { + return [ + ['c:', true], + ['c:/', true], + ['c:a', false], + ['4:', false], + ['az:', false], + ['a|', true], + ['a:|', false], + ['', false], + ['c:\\', true], + ['c:?', true], + ['c:#', true], + ['c:/f', true], + ]; + } + + #[DataProvider('startsWithWindowsDriveLetterProvider')] + public function testStartsWithWindowsDriveLetter(string $input, bool $expected): void + { + $s = new Utf8String($input); + self::assertSame($expected, $s->startsWithWindowsDriveLetter()); + } + + public function testMatchesThrowsWhenOffsetExceedsLength(): void + { + $this->expectException(RegexException::class); + $s = new Utf8String(''); + $s->matches('/[A-Z]/', $matches, 0, 1); + } + + public function testMatchesThrowsOnInvalidUtf8Text(): void + { + $this->expectException(RegexException::class); + $s = new Utf8String("\xC3\x7F"); + $s->matches('/[A-Z]/u'); + } + + public function testReplaceRegexThrowsOnInvalidUtf8Text(): void + { + $this->expectException(RegexException::class); + $s = new Utf8String("\xC3\x7F"); + $s->replaceRegex('/[A-Z]/u', 'foo'); + } + + public function testSplitReturnsEmptyListWithEmptyDelimiter(): void + { + $s = new Utf8String(''); + self::assertTrue($s->split('')->isEmpty()); + } + + public function testStringListFirstThrowsWithEmptyList(): void + { + $this->expectException(UndefinedIndexException::class); + $list = new StringList(); + $list->first(); + } + + public function testStringListLastThrowsWithEmptyList(): void + { + $this->expectException(UndefinedIndexException::class); + $list = new StringList(); + $list->last(); + } + + public function testStringListKeyReturnsInteger(): void + { + $s = new Utf8String('a=b=c=d'); + + foreach ($s->split('=') as $key => $string) { + self::assertIsInt($key); + } + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/URLRecordTest.php b/transfer-protocol/vendor/rowbot/url/tests/URLRecordTest.php new file mode 100644 index 0000000..83f2bea --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/URLRecordTest.php @@ -0,0 +1,48 @@ +parse(new Utf8String('blob:failure')); + $origin = $record->getOrigin(); + self::assertTrue($origin->isOpaque()); + self::assertNull($origin->getEffectiveDomain()); + } + + public function testFileSchemeCreatesOpaqueOrigin(): void + { + $parser = new BasicURLParser(); + $record = $parser->parse(new Utf8String('file:///C:/Users/Desktop/')); + $origin = $record->getOrigin(); + self::assertTrue($origin->isOpaque()); + self::assertNull($origin->getEffectiveDomain()); + } + + #[TestWith(['file:///C:/Users/Desktop/', 'file:///C|/Users/Desktop/', true, true])] + #[TestWith(['https://example.com/path/?query#foo', 'https://example.com/path/?query', false, true])] + #[TestWith(['http://example.com/path/foo/#bar', 'http://example.com/bar/../path/foo/#bar', true, true])] + public function testEquality( + string $urlA, + string $urlB, + bool $isEqualWithHash, + bool $isEqualWithoutHash + ): void { + $parser = new BasicURLParser(); + $recordA = $parser->parse(new Utf8String($urlA)); + $recordB = $parser->parse(new Utf8String($urlB)); + + self::assertSame($isEqualWithHash, $recordA->isEqual($recordB, false)); + self::assertSame($isEqualWithoutHash, $recordA->isEqual($recordB, true)); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/URLSearchParamsTest.php b/transfer-protocol/vendor/rowbot/url/tests/URLSearchParamsTest.php new file mode 100644 index 0000000..39bda28 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/URLSearchParamsTest.php @@ -0,0 +1,119 @@ +append('foo', 'bar'); + + self::assertSame('foo=bar', $query->toString()); + } + + public function testCloningAttachedURLSearchParams(): void + { + $url = new URL('http://example.com/?foo=bar'); + $query = clone $url->searchParams; + $query->append('foo', 'bar'); + + self::assertSame('?foo=bar', $url->search); + self::assertSame('foo=bar', $url->searchParams->toString()); + } + + public function testIterationKey(): void + { + $query = new URLSearchParams('foo=bar&qux=baz'); + $result = [ + ['foo', 'bar'], + ['qux', 'baz'], + ]; + + foreach ($query as $index => $pair) { + self::assertSame($result[$index], $pair); + } + } + + public static function getInvalidIteratorInput(): array + { + $generator = static function (): Generator { + yield 'foo'; + yield 'bar'; + }; + $anonClass = new class ($generator()) implements Countable + { + public Generator $foo; + + public function __construct(Generator $foo) + { + $this->foo = $foo; + } + + public function count(): int + { + return 2; + } + }; + + return [ + 'sequences not equal to 2' => [[['foo', 'bar'], ['baz']]], + 'non-iterable' => [new ArrayObject(['x', 'y'])], + 'generator' => [[$generator()]], + 'invalid-name' => [[[null, 'foo']]], + 'invalid-value' => [[['foo', null]]], + 'countable-only' => [[[$anonClass]]], + 'invalid-property-value' => [$anonClass], + 'iterable-non-countable' => [new ArrayObject([$generator(), $generator()])], + ]; + } + + #[DataProvider('getInvalidIteratorInput')] + public function testInvalidIteratorInput(array|object $input): void + { + $this->expectException(TypeError::class); + new URLSearchParams($input); + } + + public static function unhandledInputProvider(): array + { + return [ + [static function (): void { + return; + }], + ]; + } + + #[DataProvider('unhandledInputProvider')] + public function testUnhandledInputDoesNothing($input): void + { + $params = new URLSearchParams($input); + self::assertFalse($params->valid()); + } + + public function testInvalidIteratorReturnsNull(): void + { + $params = new URLSearchParams(); + self::assertNull($params->current()); + self::assertFalse($params->valid()); + } + + public function testSortingPairWithEmptyName(): void + { + $params = new URLSearchParams('=foo&x=bar&c=bar'); + $params->sort(); + self::assertSame('=foo&c=bar&x=bar', $params->toString()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/URLTest.php b/transfer-protocol/vendor/rowbot/url/tests/URLTest.php new file mode 100644 index 0000000..22a1c58 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/URLTest.php @@ -0,0 +1,124 @@ +href = 'https://foo:bar@foo.com/foo/bar/?foo=bar#foo'; + + self::assertSame('http:', $url1->protocol); + self::assertEmpty($url1->username); + self::assertEmpty($url1->password); + self::assertSame('127.0.0.1', $url1->host); + self::assertSame('127.0.0.1', $url1->hostname); + self::assertEmpty($url1->port); + self::assertSame('/', $url1->pathname); + self::assertEmpty($url1->search); + self::assertEmpty($url1->hash); + } + + /** + * Test variations of percent encoded dot path segements not covered by the WHATWG tests. + */ + public function testPercentEncodedDotPathSegments(): void + { + $url = new URL('http://example.com/foo/bar/%2e%2E/%2E%2e'); + self::assertSame('http://example.com/', $url->href); + self::assertSame('/', $url->pathname); + } + + public function testInvalidGetterPropertyName(): void + { + $this->expectException(InvalidArgumentException::class); + $url = new URL('http://example.com'); + $url->nonExistantProperty; + } + + public function testInvalidSetterPropertyName(): void + { + $this->expectException(InvalidArgumentException::class); + $url = new URL('http://example.com'); + $url->nonExistantProperty = 'foo'; + } + + public function testHrefSetterFailure(): void + { + $this->expectException(TypeError::class); + $url = new URL('http://example.com'); + $url->href = 'foo'; + } + + public function testCastingURLObjectToString(): void + { + $url = new URL('http://example.com'); + self::assertSame('http://example.com/', (string) $url); + self::assertSame('http://example.com/', $url->toString()); + } + + public function testHrefSetterWithNoQueryString(): void + { + $url = new URL('http://example.com'); + $url->href = 'ssh://example.org'; + self::assertSame('ssh://example.org', $url->href); + } + + public function testValidLoggerDoesNotThrow(): void + { + $url = 'https://example.com'; + self::assertInstanceOf(URL::class, new URL($url, null, [])); + self::assertInstanceOf(URL::class, new URL($url, null, ['logger' => null])); + self::assertInstanceOf(URL::class, new URL($url, null, ['logger' => new ValidationErrorLogger()])); + } + + #[TestWith(['foo'])] + #[TestWith([true])] + #[TestWith([2])] + #[TestWith([new stdClass()])] + public function testInvalidLoggerThrows($value): void + { + $this->expectException(TypeError::class); + new URL('https://example.com', null, ['logger' => $value]); + } + + public function testURLConstructorAcceptsStringable(): void + { + $foo = new class implements Stringable { + public function __toString(): string + { + return 'https://foo.com'; + } + }; + $bar = new class implements Stringable { + public function __toString(): string + { + return 'https://bar.com'; + } + }; + + self::assertInstanceOf(URL::class, new URL($foo)); + self::assertInstanceOf(URL::class, new URL($foo, $bar)); + } + + #[TestWith([new stdClass(), null])] + #[TestWith(['https://example.com', new stdClass()])] + public function testURLConstructorWithNonStringableObject(null|object|string $url, null|object|string $base): void + { + $this->expectException(NativeTypeError::class); + new URL($url, $base); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/ValidationErrorLogger.php b/transfer-protocol/vendor/rowbot/url/tests/ValidationErrorLogger.php new file mode 100644 index 0000000..ba3f861 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/ValidationErrorLogger.php @@ -0,0 +1,21 @@ +messages[] = [$level, $message, $context]; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/FailureTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/FailureTest.php new file mode 100644 index 0000000..935d15a --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/FailureTest.php @@ -0,0 +1,42 @@ +expectException(TypeError::class); + new URL('about:blank', $test['input']); + } + + #[DataProvider('urlTestDataFailureProvider')] + public function testUrlHrefSetterThrows(array $test): void + { + $this->expectException(TypeError::class); + $url = new URL('about:blank'); + $url->href = $test['input']; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/PercentEncodingTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/PercentEncodingTest.php new file mode 100644 index 0000000..50808bf --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/PercentEncodingTest.php @@ -0,0 +1,68 @@ + $expected) { + $url = $parser->parse($in, null, $encoding); + + self::assertNotFalse($url); + self::assertSame($expected, $url->query, $encoding); + self::assertSame($output['utf-8'], $url->fragment); + } + } + + public static function percentEncodedDataProvider(): iterable + { + foreach (self::loadTestData('percent-encoding.json') as $data) { + // Skip tests for encodings where mbstring produces a result that is different from what is expected + foreach (['iso-2022-jp', 'gb18030'] as $encoding) { + if (isset($data['output'][$encoding])) { + unset($data['output'][$encoding]); + } + } + + yield $data; + } + } + + /** + * @see https://url.spec.whatwg.org/#example-percent-encode-operations + */ + #[DataProvider('exampleDataProvider')] + public function testPercentEncodingExamples(string $encoding, string $input, string $output, EncodeSet $encodeSet, bool $spaceAsPlus): void + { + $percentEncoder = new PercentEncoder(); + $result = $percentEncoder->percentEncodeAfterEncoding($encoding, $input, $encodeSet, $spaceAsPlus); + self::assertSame($output, $result); + } + + public static function exampleDataProvider(): array + { + return [ + ['encoding' => 'Shift_JIS', 'input' => ' ', 'output' => '%20', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + ['encoding' => 'Shift_JIS', 'input' => '≡', 'output' => '%81%DF', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + ['encoding' => 'Shift_JIS', 'input' => '‽', 'output' => '%26%238253%3B', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + // ['encoding' => 'ISO-2022-JP', 'input' => '¥', 'output' => '%1B(J\%1B(B', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + ['encoding' => 'Shift_JIS', 'input' => '1+1 ≡ 2%20‽', 'output' => '1+1+%81%DF+2%20%26%238253%3B', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => true], + ['encoding' => 'UTF-8', 'input' => '≡', 'output' => '%E2%89%A1', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + ['encoding' => 'UTF-8', 'input' => '‽', 'output' => '%E2%80%BD', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + ['encoding' => 'UTF-8', 'input' => 'Say what‽', 'output' => 'Say%20what%E2%80%BD', 'encodeSet' => EncodeSet::USERINFO, 'spaceAsPlus' => false], + ]; + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/ToASCIIWindowTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/ToASCIIWindowTest.php new file mode 100644 index 0000000..07faa5a --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/ToASCIIWindowTest.php @@ -0,0 +1,55 @@ +host); + self::assertSame($hostTest['output'], $url->hostname); + self::assertSame('/x', $url->pathname); + self::assertSame('https://' . $hostTest['output'] . '/x', $url->href); + + return; + } + + $this->expectException(TypeError::class); + new URL($hostTest['input']); + } + + #[DataProvider('toAsciiTestProvider')] + public function testHostSetter(array $hostTest): void + { + $url = new URL('https://x/x'); + $url->host = $hostTest['input']; + + self::assertSame($hostTest['output'] ?? 'x', $url->host); + } + + #[DataProvider('toAsciiTestProvider')] + public function testHostnameSetter(array $hostTest): void + { + $url = new URL('https://x/x'); + $url->hostname = $hostTest['input']; + + self::assertSame($hostTest['output'] ?? 'x', $url->hostname); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLConstructorTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLConstructorTest.php new file mode 100644 index 0000000..7d02a8c --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLConstructorTest.php @@ -0,0 +1,63 @@ +href, 'href'); + self::assertSame($expected['protocol'], $url->protocol, 'protocol'); + self::assertSame($expected['username'], $url->username, 'username'); + self::assertSame($expected['password'], $url->password, 'password'); + self::assertSame($expected['host'], $url->host, 'host'); + self::assertSame($expected['hostname'], $url->hostname, 'hostname'); + self::assertSame($expected['port'], $url->port, 'port'); + self::assertSame($expected['pathname'], $url->pathname, 'pathname'); + self::assertSame($expected['search'], $url->search, 'search'); + + if (array_key_exists('searchParams', $expected)) { + self::assertTrue((bool) $url->searchParams); + self::assertSame($expected['searchParams'], $url->searchParams->toString(), 'searchParams'); + } + + self::assertSame($expected['hash'], $url->hash, 'hash'); + } + + public static function urlTestDataFailureProvider(): iterable + { + foreach (self::loadTestData('urltestdata.json') as $inputs) { + if (isset($inputs['failure'])) { + yield [$inputs]; + } + } + } + + #[DataProvider('urlTestDataFailureProvider')] + public function testUrlConstructorFailed(array $expected): void + { + $this->expectException(TypeError::class); + isset($expected['base']) ? new URL($expected['input'], $expected['base']) : new URL($expected['input']); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLEncodedParserTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLEncodedParserTest.php new file mode 100644 index 0000000..38f5a19 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLEncodedParserTest.php @@ -0,0 +1,75 @@ + 'test', 'output' => [['test', '']]], + ['input' => "\u{FEFF}test=\u{FEFF}", 'output' => [["\u{FEFF}test", "\u{FEFF}"]]], + ['input' => '%EF%BB%BFtest=%EF%BB%BF', 'output' => [["\u{FEFF}test", "\u{FEFF}"]]], + ['input' => '%EF%BF%BF=%EF%BF%BF', 'output' => [["\u{FFFF}", "\u{FFFF}"]]], + ['input' => '%FE%FF', 'output' => [["\u{FFFD}\u{FFFD}", '']]], + ['input' => '†&†=x', 'output' => [['†', ''], ['†', 'x']]], + ['input' => '%C2', 'output' => [["\u{FFFD}", '']]], + ['input' => '%C2x', 'output' => [["\u{FFFD}x", '']]], + [ + 'input' => '_charset_=windows-1252&test=%C2x', + 'output' => [['_charset_', 'windows-1252'], ['test', "\u{FFFD}x"]], + ], + ['input' => '', 'output' => []], + ['input' => 'a', 'output' => [['a', '']]], + ['input' => 'a=b', 'output' => [['a', 'b']]], + ['input' => 'a=', 'output' => [['a', '']]], + ['input' => '=b', 'output' => [['', 'b']]], + ['input' => '&', 'output' => []], + ['input' => '&a', 'output' => [['a', '']]], + ['input' => 'a&', 'output' => [['a', '']]], + ['input' => 'a&a', 'output' => [['a', ''], ['a', '']]], + ['input' => 'a&b&c', 'output' => [['a', ''], ['b', ''], ['c', '']]], + ['input' => 'a=b&c=d', 'output' => [['a', 'b'], ['c', 'd']]], + ['input' => 'a=b&c=d&', 'output' => [['a', 'b'], ['c', 'd']]], + ['input' => '&&&a=b&&&&c=d&', 'output' => [['a', 'b'], ['c', 'd']]], + ['input' => 'a=a&a=b&a=c', 'output' => [['a', 'a'], ['a', 'b'], ['a', 'c']]], + ['input' => 'a==a', 'output' => [['a', '=a']]], + ['input' => 'a=a+b+c+d', 'output' => [['a', 'a b c d']]], + ['input' => '%=a', 'output' => [['%', 'a']]], + ['input' => '%a=a', 'output' => [['%a', 'a']]], + ['input' => '%a_=a', 'output' => [['%a_', 'a']]], + ['input' => '%61=a', 'output' => [['a', 'a']]], + ['input' => '%61+%4d%4D=', 'output' => [['a MM', '']]], + ['input' => 'id=0&value=%', 'output' => [['id', '0'], ['value', '%']]], + ['input' => 'b=%2sf%2a', 'output' => [['b', '%2sf*']]], + ['input' => 'b=%2%2af%2a', 'output' => [['b', '%2*f*']]], + ['input' => 'b=%%2a', 'output' => [['b', '%*']]], + ]; + } + + #[DataProvider('getTestData')] + public function test(string $input, array $output): void + { + $sp = new URLSearchParams($input); + $i = 0; + + if (in_array($input, ['', '&'], true)) { + self::assertFalse($sp->valid()); + + return; + } + + foreach ($sp as $item) { + self::assertSame($output[$i++], $item); + } + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLOriginTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLOriginTest.php new file mode 100644 index 0000000..7500983 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLOriginTest.php @@ -0,0 +1,28 @@ +origin); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsAppendTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsAppendTest.php new file mode 100644 index 0000000..37778c4 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsAppendTest.php @@ -0,0 +1,48 @@ +append('a', 'b'); + self::assertSame('a=b', $params . ''); + $params->append('a', 'b'); + self::assertSame('a=b&a=b', $params . ''); + $params->append('a', 'c'); + self::assertSame('a=b&a=b&a=c', $params . ''); + } + + public function testAppendEmptyString(): void + { + $params = new URLSearchParams(); + $params->append('', ''); + self::assertSame('=', $params . ''); + $params->append('', ''); + self::assertSame('=&=', $params . ''); + $params->append('a', 'c'); + } + + public function testAppendMultiple(): void + { + $params = new URLSearchParams(); + $params->append('first', 1); + $params->append('second', 2); + $params->append('third', ''); + $params->append('first', 10); + self::assertTrue($params->has('first')); + self::assertSame('1', $params->get('first')); + self::assertSame('2', $params->get('second')); + self::assertSame('', $params->get('third')); + $params->append('first', 10); + self::assertSame('1', $params->get('first')); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsConstructorTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsConstructorTest.php new file mode 100644 index 0000000..a096895 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsConstructorTest.php @@ -0,0 +1,275 @@ +toString()); + } + + public function testRemovingLeadingQuestionMark(): void + { + $params = new URLSearchParams('?a=b'); + self::assertSame('a=b', $params->toString()); + } + + public function testConstructorEmptyObject(): void + { + $params = new URLSearchParams(new stdClass()); + self::assertSame('', (string) $params); + } + + public function testConstructorString(): void + { + $params = new URLSearchParams('a=b'); + self::assertNotNull($params); + self::assertTrue($params->has('a')); + self::assertFalse($params->has('b')); + $params = new URLSearchParams('a=b&c'); + self::assertNotNull($params); + self::assertTrue($params->has('a')); + self::assertTrue($params->has('c')); + $params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); + self::assertNotNull($params); + self::assertTrue($params->has('a')); + self::assertTrue($params->has('a b')); + self::assertTrue($params->has(' ')); + self::assertFalse($params->has('c')); + self::assertTrue($params->has(' c')); + self::assertTrue($params->has('møø')); + + $params = new URLSearchParams('id=0&value=%'); + self::assertNotNull($params); + self::assertTrue($params->has('id')); + self::assertTrue($params->has('value')); + self::assertSame('0', $params->get('id')); + self::assertSame('%', $params->get('value')); + + $params = new URLSearchParams('b=%2sf%2a'); + self::assertNotNull($params); + self::assertTrue($params->has('b')); + self::assertSame('%2sf*', $params->get('b')); + + $params = new URLSearchParams('b=%2%2af%2a'); + self::assertNotNull($params); + self::assertTrue($params->has('b')); + self::assertSame('%2*f*', $params->get('b')); + + $params = new URLSearchParams('b=%%2a'); + self::assertNotNull($params); + self::assertTrue($params->has('b')); + self::assertSame('%*', $params->get('b')); + } + + public function testConstructorObject(): void + { + $seed = new URLSearchParams('a=b&c=d'); + $params = new URLSearchParams($seed); + self::assertNotNull($params, 'message'); + self::assertSame('b', $params->get('a')); + self::assertSame('d', $params->get('c')); + self::assertFalse($params->has('d'), 'message'); + // The name-value pairs are copied when created; later, updates should + // not be observable. + $seed->append('e', 'f'); + self::assertFalse($params->has('e')); + $params->append('g', 'h'); + self::assertFalse($seed->has('g')); + } + + public function testParsePlusSign(): void + { + $params = new URLSearchParams('a=b+c'); + self::assertSame('b c', $params->get('a')); + $params = new URLSearchParams('a+b=c'); + self::assertSame('c', $params->get('a b')); + } + + public function testParsePlusSignPercentEncoded(): void + { + $testValue = '+15555555555'; + $params = new URLSearchParams(); + $params->set('query', $testValue); + + $newParams = new URLSearchParams($params->toString()); + self::assertSame('query=%2B15555555555', $params->toString()); + self::assertSame($testValue, $params->get('query')); + self::assertSame($testValue, $newParams->get('query')); + } + + public function testParseSpace(): void + { + $params = new URLSearchParams('a=b c'); + self::assertSame('b c', $params->get('a')); + $params = new URLSearchParams('a b=c'); + self::assertSame('c', $params->get('a b')); + } + + public function testParseSpacePercentEncoded(): void + { + $params = new URLSearchParams('a=b%20c'); + self::assertSame('b c', $params->get('a')); + $params = new URLSearchParams('a%20b=c'); + self::assertSame('c', $params->get('a b')); + } + + public function testParseNullByte(): void + { + $params = new URLSearchParams("a=b\0c"); + self::assertSame("b\0c", $params->get('a')); + $params = new URLSearchParams("a\0b=c"); + self::assertSame('c', $params->get("a\0b")); + } + + public function testParseNullBytePercentEncoded(): void + { + $params = new URLSearchParams('a=b%00c'); + self::assertSame("b\0c", $params->get('a')); + $params = new URLSearchParams('a%00b=c'); + self::assertSame('c', $params->get("a\0b")); + } + + public function testParseUnicodeCompositionSymbol(): void + { + $params = new URLSearchParams("a=b\u{2384}"); + self::assertSame("b\u{2384}", $params->get('a')); + $params = new URLSearchParams("a\u{2384}=c"); + self::assertSame('c', $params->get("a\u{2384}")); + } + + public function testParseUnicodeCompositionSymbolPercentEncoded(): void + { + $params = new URLSearchParams('a=b%E2%8E%84'); + self::assertSame("b\u{2384}", $params->get('a')); + $params = new URLSearchParams('a%E2%8E%84=c'); + self::assertSame('c', $params->get("a\u{2384}")); + } + + public function testParseUnicodePileOfPoo(): void + { + $params = new URLSearchParams("a=b\u{1F4A9}c"); + self::assertSame("b\u{1F4A9}c", $params->get('a')); + $params = new URLSearchParams("a\u{1F4A9}b=c"); + self::assertSame('c', $params->get("a\u{1F4A9}b")); + } + + public function testParseUnicodePileOfPooPercentEncoded(): void + { + $params = new URLSearchParams('a=b%f0%9f%92%a9c'); + self::assertSame("b\u{1F4A9}c", $params->get('a')); + $params = new URLSearchParams('a%f0%9f%92%a9b=c'); + self::assertSame('c', $params->get("a\u{1F4A9}b")); + } + + public function testSequenceOfSequences(): void + { + $params = new URLSearchParams([]); + self::assertNotNull($params); + $params = new URLSearchParams([['a', 'b'], ['c', 'd']]); + self::assertSame('b', $params->get('a')); + self::assertSame('d', $params->get('c')); + + try { + new URLSearchParams([[1]]); + self::assertTrue(false); + } catch (TypeError) { + self::assertTrue(true); + } + + try { + new URLSearchParams([[1, 2, 3]]); + self::assertTrue(false); + } catch (TypeError) { + self::assertTrue(true); + } + } + + public static function getTestData(): array + { + $obj = new stdClass(); + $obj->{'+'} = '%C2'; + + $obj2 = new stdClass(); + $obj2->c = 'x'; + $obj2->a = '?'; + + $obj3 = new stdClass(); + $obj3->{"a\0b"} = '42'; + $obj3->{"c\u{D83D}"} = '23'; + $obj3->{"d\u{1234}"} = 'foo'; + + // Mimic error handling of JavaScript Object keys + $json = json_encode($obj3, JSON_INVALID_UTF8_SUBSTITUTE | JSON_THROW_ON_ERROR); + $obj3 = json_decode($json, false, 512, JSON_THROW_ON_ERROR); + + return [ + ['input' => $obj, 'output' => [['+', '%C2']]], + [ + 'input' => $obj2, + 'output' => [ + ['c', 'x'], + ['a', '?'], + ], + ], + [ + 'input' => [ + ['c', 'x'], + ['a', '?'], + ], + 'output' => [ + ['c', 'x'], + ['a', '?'], + ], + ], + [ + 'input' => $obj3, + 'output' => [ + ["a\0b", '42'], + ["c\u{FFFD}", '23'], + ["d\u{1234}", 'foo'], + ], + ], + ]; + } + + #[DataProvider('getTestData')] + public function test($input, array $output): void + { + $params = new URLSearchParams($input); + $i = 0; + + foreach ($params as $param) { + self::assertSame($output[$i++], $param); + } + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsDeleteTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsDeleteTest.php new file mode 100644 index 0000000..74c2739 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsDeleteTest.php @@ -0,0 +1,87 @@ +delete('a'); + self::assertSame('c=d', $params . ''); + $params = new URLSearchParams('a=a&b=b&a=a&c=c'); + $params->delete('a'); + self::assertSame('b=b&c=c', $params . ''); + $params = new URLSearchParams('a=a&=&b=b&c=c'); + $params->delete(''); + self::assertSame('a=a&b=b&c=c', $params . ''); + } + + public function testDeleteAppendMultiple(): void + { + $params = new URLSearchParams(); + $params->append('first', 1); + self::assertTrue($params->has('first')); + self::assertSame('1', $params->get('first')); + $params->delete('first'); + self::assertFalse($params->has('first')); + $params->append('first', 1); + $params->append('first', 10); + $params->delete('first'); + self::assertFalse($params->has('first')); + } + + public function testDeleteAllRemovesQuestionMark(): void + { + $url = new URL('http://example.com/?param1¶m2'); + $url->searchParams->delete('param1'); + $url->searchParams->delete('param2'); + self::assertSame('http://example.com/', $url->href); + self::assertSame('', $url->search); + } + + public function testDeleteNonExistentParamRemovesQuestionMark(): void + { + $url = new URL('http://example.com/?'); + $url->searchParams->delete('param1'); + self::assertSame('http://example.com/', $url->href); + self::assertSame('', $url->search); + } + + public function testChangingTheQueryOfAUrlWithAnOpaquePathCanImpactThePath(): void + { + $url = new URL('data:space ?test'); + self::assertTrue($url->searchParams->has('test')); + $url->searchParams->delete('test'); + self::assertFalse($url->searchParams->has('test')); + self::assertSame('', $url->search); + self::assertSame('space', $url->pathname); + self::assertSame('data:space', $url->href); + } + + public function testChangingTheQueryOfAUrlWithAnOpaquePathCanImpactThePathIfTheUrlHasNoFragment(): void + { + $url = new URL('data:space ?test#test'); + $url->searchParams->delete('test'); + self::assertSame('', $url->search); + self::assertSame('space ', $url->pathname); + self::assertSame('data:space #test', $url->href); + } + + public function testTwoArgumentDelete(): void + { + $params = new URLSearchParams(); + $params->append('a', 'b'); + $params->append('a', 'c'); + $params->append('a', 'd'); + $params->delete('a', 'c'); + self::assertSame('a=b&a=d', $params->toString()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsForeachTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsForeachTest.php new file mode 100644 index 0000000..9fb74f3 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsForeachTest.php @@ -0,0 +1,102 @@ +searchParams; + $c = []; + + foreach ($b as $i) { + $a->search = 'x=1&y=2&z=3'; + $c[] = $i; + } + + self::assertSame(['a', '1'], $c[0]); + self::assertSame(['y', '2'], $c[1]); + self::assertSame(['z', '3'], $c[2]); + } + + public function test3(): void + { + $a = new URL('http://a.b/c'); + $b = $a->searchParams; + self::assertFalse($b->valid()); + } + + public function testDeleteNextParamDuringIteration(): void + { + $url = new URL('http://localhost/query?param0=0¶m1=1¶m2=2'); + $searchParams = $url->searchParams; + $seen = []; + + foreach ($searchParams as $param) { + if ($param[0] === 'param0') { + $searchParams->delete('param1'); + } + + $seen[] = $param; + } + + self::assertSame(['param0', '0'], $seen[0]); + self::assertSame(['param2', '2'], $seen[1]); + } + + public function testDeleteCurrentParamDuringIteration(): void + { + $url = new URL('http://localhost/query?param0=0¶m1=1¶m2=2'); + $searchParams = $url->searchParams; + $seen = []; + + foreach ($searchParams as $param) { + if ($param[0] === 'param0') { + $searchParams->delete('param1'); + // 'param1=1' is now in the first slot, so the next iteration will see 'param2=2'. + } else { + $seen[] = $param; + } + } + + self::assertSame(['param2', '2'], $seen[0]); + } + + public function testDeleteEveryParamSeenDuringIteration(): void + { + $url = new URL('http://localhost/query?param0=0¶m1=1¶m2=2'); + $searchParams = $url->searchParams; + $seen = []; + + foreach ($searchParams as $param) { + $seen[] = $param[0]; + $searchParams->delete($param[0]); + } + + self::assertSame(['param0', 'param2'], $seen); + self::assertSame('param1=1', (string) $searchParams); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetAllTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetAllTest.php new file mode 100644 index 0000000..4b27747 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetAllTest.php @@ -0,0 +1,42 @@ +getAll('a')); + self::assertSame(['d'], $params->getAll('c')); + self::assertSame([], $params->getAll('e')); + $params = new URLSearchParams('a=b&c=d&a=e'); + self::assertSame(['b', 'e'], $params->getAll('a')); + $params = new URLSearchParams('=b&c=d'); + self::assertSame(['b'], $params->getAll('')); + $params = new URLSearchParams('a=&c=d&a=e'); + self::assertSame(['', 'e'], $params->getAll('a')); + } + + public function testGetAllMultiple(): void + { + $params = new URLSearchParams('a=1&a=2&a=3&a'); + self::assertTrue($params->has('a')); + $matches = $params->getAll('a'); + self::assertTrue($matches && count($matches) === 4); + self::assertSame(['1', '2', '3', ''], $matches); + $params->set('a', 'one'); + self::assertSame('one', $params->get('a')); + $matches = $params->getAll('a'); + self::assertTrue($matches && count($matches) === 1); + self::assertSame(['one'], $matches); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetTest.php new file mode 100644 index 0000000..1d12b6e --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsGetTest.php @@ -0,0 +1,37 @@ +get('a')); + self::assertSame('d', $params->get('c')); + self::assertNull($params->get('e')); + $params = new URLSearchParams('a=b&c=d&a=e'); + self::assertSame('b', $params->get('a')); + $params = new URLSearchParams('=b&c=d'); + self::assertSame('b', $params->get('')); + $params = new URLSearchParams('a=&c=d&a=e'); + self::assertSame('', $params->get('a')); + } + + public function testMoreGetBasics(): void + { + $params = new URLSearchParams('first=second&third&&'); + + self::assertNotNull($params); + self::assertTrue($params->has('first'), 'constructor returned non-null value.'); + self::assertSame('second', $params->get('first'), 'Search params object has name "first"'); + self::assertSame('', $params->get('third'), 'Search params object has name "third" with the empty value.'); + self::assertNull($params->get('fourth'), 'Search params object has no "fourth" name and value.'); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsHasTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsHasTest.php new file mode 100644 index 0000000..25ebf7b --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsHasTest.php @@ -0,0 +1,51 @@ +has('a')); + self::assertTrue($params->has('c')); + self::assertFalse($params->has('e')); + $params = new URLSearchParams('a=b&c=d&a=e'); + self::assertTrue($params->has('a')); + $params = new URLSearchParams('=b&c=d'); + self::assertTrue($params->has('')); + } + + public function testHasFollowingDelete(): void + { + $params = new URLSearchParams('a=b&c=d&&'); + $params->append('first', 1); + $params->append('first', 2); + self::assertTrue($params->has('a')); + self::assertTrue($params->has('c')); + self::assertTrue($params->has('first')); + self::assertFalse($params->has('d')); + $params->delete('first'); + self::assertFalse($params->has('first')); + } + + public function testTwoArgumentHas(): void + { + $params = new URLSearchParams('a=b&a=d&c&e&'); + self::assertTrue($params->has('a', 'b')); + self::assertFalse($params->has('a', 'c')); + self::assertTrue($params->has('a', 'd')); + self::assertTrue($params->has('e', '')); + $params->append('first', 'null'); + self::assertFalse($params->has('first', '')); + self::assertTrue($params->has('first', 'null')); + $params->delete('a', 'b'); + self::assertTrue($params->has('a', 'd')); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSetTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSetTest.php new file mode 100644 index 0000000..f9aeefa --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSetTest.php @@ -0,0 +1,63 @@ +set('a', 'B'); + self::assertSame('a=B&c=d', $params . ''); + $params = new URLSearchParams('a=b&c=d&a=e'); + $params->set('a', 'B'); + self::assertSame('a=B&c=d', $params . ''); + $params->set('e', 'f'); + self::assertSame('a=B&c=d&e=f', $params . ''); + } + + public function testURLSearchParamsSet(): void + { + $params = new URLSearchParams('a=1&a=2&a=3'); + + self::assertTrue( + $params->has('a'), + 'Search params object has name "a"' + ); + self::assertSame( + '1', + $params->get('a'), + 'Search params object has name "a" with a value of "1"' + ); + + $params->set('first', 4); + + self::assertTrue( + $params->has('a'), + 'Search params object has name "a"' + ); + self::assertSame( + '1', + $params->get('a'), + 'Search params object has name "a" with value "1"' + ); + + $params->set('a', 4); + + self::assertTrue( + $params->has('a'), + 'Search params object has name "a"' + ); + self::assertSame( + '4', + $params->get('a'), + 'Search params object has name "a" with value "4"' + ); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSizeTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSizeTest.php new file mode 100644 index 0000000..5f739d5 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSizeTest.php @@ -0,0 +1,63 @@ +size); + self::assertCount(3, $params); + + $params->delete('a'); + self::assertSame(1, $params->size); + self::assertCount(1, $params); + } + + public function testSizeAndAddition(): void + { + $params = new URLSearchParams('a=1&b=2&a=3'); + self::assertSame(3, $params->size); + self::assertCount(3, $params); + + $params->append('b', '4'); + self::assertSame(4, $params->size); + self::assertCount(4, $params); + } + + public function testSizeWhenObtainedFromAURL(): void + { + $url = new URL("http://localhost/query?a=1&b=2&a=3"); + self::assertSame(3, $url->searchParams->size); + self::assertCount(3, $url->searchParams); + + $url->searchParams->delete('a'); + self::assertSame(1, $url->searchParams->size); + self::assertCount(1, $url->searchParams); + + $url->searchParams->append('b', '4'); + self::assertSame(2, $url->searchParams->size); + self::assertCount(2, $url->searchParams); + } + + public function testSizeWhenObtainedFromAURLAndUsingSearch(): void + { + $url = new URL("http://localhost/query?a=1&b=2&a=3"); + self::assertSame(3, $url->searchParams->size); + self::assertCount(3, $url->searchParams); + + $url->search = '?'; + self::assertSame(0, $url->searchParams->size); + self::assertCount(0, $url->searchParams); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSortTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSortTest.php new file mode 100644 index 0000000..cadf776 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsSortTest.php @@ -0,0 +1,108 @@ + 'z=b&a=b&z=a&a=a', + 'output' => [ + ['a', 'b'], + ['a', 'a'], + ['z', 'b'], + ['z', 'a'], + ], + ], + [ + 'input' => "\u{FFFD}=x&\u{FFFC}&\u{FFFD}=a", + 'output' => [ + ["\u{FFFC}", ''], + ["\u{FFFD}", 'x'], + ["\u{FFFD}", 'a'], + ], + ], + [ + 'input' => 'ffi&🌈', + 'output' => [['🌈', ''], ['ffi', '']], + ], + [ + 'input' => "é&e\u{FFFD}&e\u{0301}", + 'output' => [ + ["e\u{0301}", ''], + ["e\u{FFFD}", ''], + ['é', ''], + ], + ], + [ + 'input' => 'z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g', + 'output' => [ + ['a', 'a'], + ['a', 'b'], + ['a', 'c'], + ['a', 'd'], + ['a', 'e'], + ['a', 'f'], + ['a', 'g'], + ['z', 'z'], + ['z', 'y'], + ['z', 'x'], + ['z', 'w'], + ['z', 'v'], + ['z', 'u'], + ['z', 't'], + ], + ], + [ + 'input' => 'bbb&bb&aaa&aa=x&aa=y', + 'output' => [ + ['aa', 'x'], + ['aa', 'y'], + ['aaa', ''], + ['bb', ''], + ['bbb', ''], + ], + ], + [ + 'input' => 'z=z&=f&=t&=x', + 'output' => [['', 'f'], ['', 't'], ['', 'x'], ['z', 'z']], + ], + [ + 'input' => 'a🌈&a💩', + 'output' => [['a🌈', ''], ['a💩', '']], + ], + ]; + } + + #[DataProvider('getTestData')] + public function testSort(string $input, array $output): void + { + $url = new URL('?' . $input, 'https://example/'); + $url->searchParams->sort(); + + $params = new URLSearchParams($url->search); + $i = 0; + + foreach ($params as $param) { + self::assertSame($output[$i++], $param); + } + } + + public function testSortingNonExistentParamsRemovesQuestionMark(): void + { + $url = new URL('http://example.com/?'); + $url->searchParams->sort(); + self::assertSame('http://example.com/', $url->href); + self::assertSame('', $url->search); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsStringifierTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsStringifierTest.php new file mode 100644 index 0000000..4ab081d --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsStringifierTest.php @@ -0,0 +1,175 @@ +append('a', 'b c'); + self::assertSame('a=b+c', $params . ''); + $params->delete('a'); + $params->append('a b', 'c'); + self::assertSame('a+b=c', $params . ''); + } + + public function testSerializeEmptyValue(): void + { + $params = new URLSearchParams(); + $params->append('a', ''); + self::assertSame('a=', $params . ''); + $params->append('a', ''); + self::assertSame('a=&a=', $params . ''); + $params->append('', 'b'); + self::assertSame('a=&a=&=b', $params . ''); + $params->append('', ''); + self::assertSame('a=&a=&=b&=', $params . ''); + $params->append('', ''); + self::assertSame('a=&a=&=b&=&=', $params . ''); + } + + public function testSerializeEmptyName(): void + { + $params = new URLSearchParams(); + $params->append('', 'b'); + self::assertSame('=b', $params . ''); + $params->append('', 'b'); + self::assertSame('=b&=b', $params . ''); + } + + public function testSerialzieEmptyNameAndValue(): void + { + $params = new URLSearchParams(); + $params->append('', ''); + self::assertSame('=', $params . ''); + $params->append('', ''); + self::assertSame('=&=', $params . ''); + } + + public function testSerialziePlusSign(): void + { + $params = new URLSearchParams(); + $params->append('a', 'b+c'); + self::assertSame('a=b%2Bc', $params . ''); + $params->delete('a'); + $params->append('a+b', 'c'); + self::assertSame('a%2Bb=c', $params . ''); + } + + public function testSerializeEqualSign(): void + { + $params = new URLSearchParams(); + $params->append('=', 'a'); + self::assertSame('%3D=a', $params . ''); + $params->append('b', '='); + self::assertSame('%3D=a&b=%3D', $params . ''); + } + + public function testSerializeAmpersand(): void + { + $params = new URLSearchParams(); + $params->append('&', 'a'); + self::assertSame('%26=a', $params . ''); + $params->append('b', '&'); + self::assertSame('%26=a&b=%26', $params . ''); + } + + public function testSerializeSpecialChars(): void + { + $params = new URLSearchParams(); + $params->append('a', '*-._'); + self::assertSame('a=*-._', $params . ''); + $params->delete('a'); + $params->append('*-._', 'c'); + self::assertSame('*-._=c', $params . ''); + } + + public function testSerializePercentSign(): void + { + $params = new URLSearchParams(); + $params->append('a', 'b%c'); + self::assertSame('a=b%25c', $params . ''); + $params->delete('a'); + $params->append('a%b', 'c'); + self::assertSame('a%25b=c', $params . ''); + + $params = new URLSearchParams('id=0&value=%'); + self::assertSame('id=0&value=%25', $params . ''); + } + + public function testSerializeNullByte(): void + { + $params = new URLSearchParams(); + $params->append('a', "b\0c"); + self::assertSame('a=b%00c', $params . ''); + $params->delete('a'); + $params->append("a\0b", 'c'); + self::assertSame('a%00b=c', $params . ''); + } + + public function testSerializeUnicodePileOfPoo(): void + { + $params = new URLSearchParams(); + $params->append('a', "b\u{1F4A9}c"); + self::assertSame('a=b%F0%9F%92%A9c', $params . ''); + $params->delete('a'); + $params->append("a\u{1F4A9}b", 'c'); + self::assertSame('a%F0%9F%92%A9b=c', $params . ''); + } + + public function testStringification(): void + { + $params = new URLSearchParams('a=b&c=d&&e&&'); + self::assertSame('a=b&c=d&e=', $params->toString()); + $params = new URLSearchParams('a = b &a=b&c=d%20'); + self::assertSame('a+=+b+&a=b&c=d+', $params->toString()); + // The lone '=' _does_ survive the roundtrip. + $params = new URLSearchParams('a=&a=b'); + self::assertSame('a=&a=b', $params->toString()); + + $params = new URLSearchParams('b=%2sf%2a'); + self::assertSame('b=%252sf*', $params->toString()); + + $params = new URLSearchParams('b=%2%2af%2a'); + self::assertSame('b=%252*f*', $params->toString()); + + $params = new URLSearchParams('b=%%2a'); + self::assertSame('b=%25*', $params->toString()); + } + + public function testURLSearchParamsConnectedToURL(): void + { + $url = new URL('http://www.example.com/?a=b,c'); + $params = $url->searchParams; + + self::assertSame('http://www.example.com/?a=b,c', $url->toString()); + self::assertSame('a=b%2Cc', $params->toString()); + + $params->append('x', 'y'); + + self::assertSame( + 'http://www.example.com/?a=b%2Cc&x=y', + $url->toString() + ); + self::assertSame('a=b%2Cc&x=y', $params->toString()); + } + + public function testURLSearchParamsMustNotDoNewlineNormalization(): void + { + $url = new URL('http://www.example.com/'); + $params = $url->searchParams; + + $params->append("a\nb", "c\rd"); + $params->append("e\n\rf", "g\r\nh"); + + self::assertSame('a%0Ab=c%0Dd&e%0A%0Df=g%0D%0Ah', $params->toString()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsTest.php new file mode 100644 index 0000000..e16f188 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSearchParamsTest.php @@ -0,0 +1,87 @@ +searchParams); + $searchParams = $url->searchParams; + self::assertSame($searchParams, $url->searchParams); + } + + /** + * Test URL.searchParams updating, clearing. + */ + public function testURLSearchParamsUpdatingClearing(): void + { + $url = new URL('http://example.org/?a=b', 'about:blank'); + self::assertNotNull($url->searchParams); + $searchParams = $url->searchParams; + self::assertSame('a=b', $searchParams->toString()); + + $searchParams->set('a', 'b'); + self::assertSame('a=b', $url->searchParams->toString()); + self::assertSame('?a=b', $url->search); + $url->search = ''; + self::assertSame('', $url->searchParams->toString()); + self::assertSame('', $url->search); + self::assertSame('', $searchParams->toString()); + } + + public function testURLSearchParamsSetterInvalidValues(): void + { + $this->expectException(TypeError::class); + $urlString = 'http://example.org'; + $url = new URL($urlString, 'about:blank'); + $url->searchParams = new URLSearchParams($urlString); + } + + public function testURLSearchParamsAndURLSearchSettersUpdatePropagation(): void + { + $url = new URL('http://example.org/file?a=b&c=d'); + self::assertInstanceOf(URLSearchParams::class, $url->searchParams); + $searchParams = $url->searchParams; + self::assertSame('?a=b&c=d', $url->search); + self::assertSame('a=b&c=d', $searchParams->toString()); + + // Test that setting 'search' propagates to the URL object's query + // object + $url->search = 'e=f&g=h'; + self::assertSame('?e=f&g=h', $url->search); + self::assertSame('e=f&g=h', $url->searchParams->toString()); + + // ...and same, but with a leading '?' + $url->search = '?e=f&g=h'; + self::assertSame('?e=f&g=h', $url->search); + self::assertSame('e=f&g=h', $url->searchParams->toString()); + + // And in the other direction, altering searchParams propagates back + // to 'search' + $searchParams->append('i', ' j '); + self::assertSame('?e=f&g=h&i=+j+', $url->search); + self::assertSame('e=f&g=h&i=+j+', $url->searchParams->toString()); + self::assertSame(' j ', $searchParams->get('i')); + + $searchParams->set('e', 'updated'); + self::assertSame('?e=updated&g=h&i=+j+', $url->search); + self::assertSame('e=updated&g=h&i=+j+', $url->searchParams->__toString()); + + $url2 = new URL('http://example.org/file??a=b&c=d', 'about:blank'); + self::assertSame('??a=b&c=d', $url2->search); + self::assertSame('%3Fa=b&c=d', $url2->searchParams->toString()); + + $url2->href = 'http://example.org/file??a=b'; + self::assertSame('??a=b', $url2->search); + self::assertSame('%3Fa=b', $url2->searchParams->toString()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSettersTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSettersTest.php new file mode 100644 index 0000000..ae22c4f --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLSettersTest.php @@ -0,0 +1,39 @@ + $tests) { + if ($key === 'comment') { + continue; + } + + foreach ($tests as $inputs) { + unset($inputs['comment']); + $inputs['setter'] = $key; + + yield [$inputs]; + } + } + } + + #[DataProvider('urlSetterGetterDataProvider')] + public function testSetters(array $input): void + { + $url = new URL($input['href']); + $url->{$input['setter']} = $input['new_value']; + + foreach ($input['expected'] as $attribute => $value) { + self::assertSame($value, $url->$attribute, $attribute); + } + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLStaticsCanParseTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLStaticsCanParseTest.php new file mode 100644 index 0000000..2985388 --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLStaticsCanParseTest.php @@ -0,0 +1,24 @@ + 'a:b', 'base' => null, 'expected' => true])] + #[TestWith(['url' => 'a:/b', 'base' => null, 'expected' => true])] + #[TestWith(['url' => 'https://test:test', 'base' => null, 'expected' => false])] + #[TestWith(['url' => 'a', 'base' => 'https://b/', 'expected' => true])] + public function testCanParse(string $url, ?string $base, bool $expected): void + { + self::assertSame($expected, URL::canParse($url, $base)); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLToJSONTest.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLToJSONTest.php new file mode 100644 index 0000000..768bb3f --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/URLToJSONTest.php @@ -0,0 +1,24 @@ +href) . '"', json_encode($a, JSON_THROW_ON_ERROR)); + self::assertSame('"' . $a->href . '"', $a->toJSON()); + } +} diff --git a/transfer-protocol/vendor/rowbot/url/tests/WhatWg/WhatwgTestCase.php b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/WhatwgTestCase.php new file mode 100644 index 0000000..3ded1ee --- /dev/null +++ b/transfer-protocol/vendor/rowbot/url/tests/WhatWg/WhatwgTestCase.php @@ -0,0 +1,62 @@ +get($url, static function () use ($url): string { + self::$client ??= new Client([ + 'base_uri' => self::WHATWG_BASE_URI, + 'http_errors' => true, + ]); + $response = self::$client->get($url); + + // Replace all unpaired surrogate escape sequences with a \uFFFD escape sequence to avoid + // json_decode() having a stroke and emitting a JSON_ERROR_UTF16 error causing the decode + // to fail + $body = preg_replace( + '/ + (?(DEFINE) + (?\\\u[Dd][89AaBb][[:xdigit:]][[:xdigit:]]) + (?\\\u[Dd][C-Fc-f][[:xdigit:]][[:xdigit:]]) + ) + + # Match a low surrogate not preceded by a high surrogate + (?getBody() + ); + + // Remove comments and check to make sure it is valid JSON. + $json = array_filter(json_decode($body, true, self::JSON_DEPTH, JSON_THROW_ON_ERROR), 'is_array'); + + return json_encode($json, JSON_THROW_ON_ERROR); + }); + + return json_decode($data, true, self::JSON_DEPTH, JSON_THROW_ON_ERROR); + } +} diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/LICENSE b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/LICENSE new file mode 100644 index 0000000..6e3afce --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Normalizer.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Normalizer.php new file mode 100644 index 0000000..81704ab --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Normalizer.php @@ -0,0 +1,310 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Normalizer; + +/** + * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. + * + * It has been validated with Unicode 6.3 Normalization Conformance Test. + * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. + * + * @author Nicolas Grekas + * + * @internal + */ +class Normalizer +{ + public const FORM_D = \Normalizer::FORM_D; + public const FORM_KD = \Normalizer::FORM_KD; + public const FORM_C = \Normalizer::FORM_C; + public const FORM_KC = \Normalizer::FORM_KC; + public const NFD = \Normalizer::NFD; + public const NFKD = \Normalizer::NFKD; + public const NFC = \Normalizer::NFC; + public const NFKC = \Normalizer::NFKC; + + private static $C; + private static $D; + private static $KD; + private static $cC; + private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + + public static function isNormalized(string $s, int $form = self::FORM_C) + { + if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) { + return false; + } + if (!isset($s[strspn($s, self::$ASCII)])) { + return true; + } + if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { + return true; + } + + return self::normalize($s, $form) === $s; + } + + public static function normalize(string $s, int $form = self::FORM_C) + { + if (!preg_match('//u', $s)) { + return false; + } + + switch ($form) { + case self::NFC: $C = true; $K = false; break; + case self::NFD: $C = false; $K = false; break; + case self::NFKC: $C = true; $K = true; break; + case self::NFKD: $C = false; $K = true; break; + default: + if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { + return $s; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); + } + + if ('' === $s) { + return ''; + } + + if ($K && null === self::$KD) { + self::$KD = self::getData('compatibilityDecomposition'); + } + + if (null === self::$D) { + self::$D = self::getData('canonicalDecomposition'); + self::$cC = self::getData('combiningClass'); + } + + if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { + mb_internal_encoding('8bit'); + } + + $r = self::decompose($s, $K); + + if ($C) { + if (null === self::$C) { + self::$C = self::getData('canonicalComposition'); + } + + $r = self::recompose($r); + } + if (null !== $mbEncoding) { + mb_internal_encoding($mbEncoding); + } + + return $r; + } + + private static function recompose($s) + { + $ASCII = self::$ASCII; + $compMap = self::$C; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + + $result = $tail = ''; + + $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; + $len = \strlen($s); + + $lastUchr = substr($s, 0, $i); + $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + if ($j = strspn($s, $ASCII, $i + 1)) { + $lastUchr .= substr($s, $i, $j); + $i += $j; + } + + $result .= $lastUchr; + $lastUchr = $s[$i]; + $lastUcls = 0; + ++$i; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + + if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr + || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr + || $lastUcls) { + // Table lookup and combining chars composition + + $ucls = $combClass[$uchr] ?? 0; + + if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { + $lastUchr = $compMap[$lastUchr.$uchr]; + } elseif ($lastUcls = $ucls) { + $tail .= $uchr; + } else { + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + $result .= $lastUchr; + $lastUchr = $uchr; + } + } else { + // Hangul chars + + $L = \ord($lastUchr[2]) - 0x80; + $V = \ord($uchr[2]) - 0xA1; + $T = 0; + + $uchr = substr($s, $i + $ulen, 3); + + if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { + $T = \ord($uchr[2]) - 0xA7; + 0 > $T && $T += 0x40; + $ulen += 3; + } + + $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; + $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); + } + + $i += $ulen; + } + + return $result.$lastUchr.$tail; + } + + private static function decompose($s, $c) + { + $result = ''; + + $ASCII = self::$ASCII; + $decompMap = self::$D; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + if ($c) { + $compatMap = self::$KD; + } + + $c = []; + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = []; + } + + $j = 1 + strspn($s, $ASCII, $i + 1); + $result .= substr($s, $i, $j); + $i += $j; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { + // Table lookup + + if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) { + $uchr = $j; + + $j = \strlen($uchr); + $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; + + if ($ulen != $j) { + // Put trailing chars in $s + + $j -= $ulen; + $i -= $j; + + if (0 > $i) { + $s = str_repeat(' ', -$i).$s; + $len -= $i; + $i = 0; + } + + while ($j--) { + $s[$i + $j] = $uchr[$ulen + $j]; + } + + $uchr = substr($uchr, 0, $ulen); + } + } + if (isset($combClass[$uchr])) { + // Combining chars, for sorting + + if (!isset($c[$combClass[$uchr]])) { + $c[$combClass[$uchr]] = ''; + } + $c[$combClass[$uchr]] .= $uchr; + continue; + } + } else { + // Hangul chars + + $uchr = unpack('C*', $uchr); + $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; + + $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) + ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); + + if ($j %= 28) { + $uchr .= $j < 25 + ? ("\xE1\x86".\chr(0xA7 + $j)) + : ("\xE1\x87".\chr(0x67 + $j)); + } + } + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = []; + } + + $result .= $uchr; + } + + if ($c) { + ksort($c); + $result .= implode('', $c); + } + + return $result; + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } +} diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/README.md b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/README.md new file mode 100644 index 0000000..b9b762e --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/README.md @@ -0,0 +1,14 @@ +Symfony Polyfill / Intl: Normalizer +=================================== + +This component provides a fallback implementation for the +[`Normalizer`](https://php.net/Normalizer) class provided +by the [Intl](https://php.net/intl) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php new file mode 100644 index 0000000..0fdfc89 --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php @@ -0,0 +1,17 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '΅' => '΅', + 'Ά' => 'Ά', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ὲ' => 'ὲ', + 'ὴ' => 'ὴ', + 'ὶ' => 'ὶ', + 'ὸ' => 'ὸ', + 'ὺ' => 'ὺ', + 'ὼ' => 'ὼ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'ᾼ' => 'ᾼ', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Ὴ' => 'Ὴ', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ὼ' => 'Ὼ', + 'ῼ' => 'ῼ', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', +); diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php new file mode 100644 index 0000000..5a3e8e0 --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php @@ -0,0 +1,2065 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '̀' => '̀', + '́' => '́', + '̓' => '̓', + '̈́' => '̈́', + 'ʹ' => 'ʹ', + ';' => ';', + '΅' => '΅', + 'Ά' => 'Ά', + '·' => '·', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'क़' => 'क़', + 'ख़' => 'ख़', + 'ग़' => 'ग़', + 'ज़' => 'ज़', + 'ड़' => 'ड़', + 'ढ़' => 'ढ़', + 'फ़' => 'फ़', + 'य़' => 'य़', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ড়' => 'ড়', + 'ঢ়' => 'ঢ়', + 'য়' => 'য়', + 'ਲ਼' => 'ਲ਼', + 'ਸ਼' => 'ਸ਼', + 'ਖ਼' => 'ਖ਼', + 'ਗ਼' => 'ਗ਼', + 'ਜ਼' => 'ਜ਼', + 'ਫ਼' => 'ਫ਼', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ଡ଼' => 'ଡ଼', + 'ଢ଼' => 'ଢ଼', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'གྷ' => 'གྷ', + 'ཌྷ' => 'ཌྷ', + 'དྷ' => 'དྷ', + 'བྷ' => 'བྷ', + 'ཛྷ' => 'ཛྷ', + 'ཀྵ' => 'ཀྵ', + 'ཱི' => 'ཱི', + 'ཱུ' => 'ཱུ', + 'ྲྀ' => 'ྲྀ', + 'ླྀ' => 'ླྀ', + 'ཱྀ' => 'ཱྀ', + 'ྒྷ' => 'ྒྷ', + 'ྜྷ' => 'ྜྷ', + 'ྡྷ' => 'ྡྷ', + 'ྦྷ' => 'ྦྷ', + 'ྫྷ' => 'ྫྷ', + 'ྐྵ' => 'ྐྵ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ά' => 'ά', + 'ὲ' => 'ὲ', + 'έ' => 'έ', + 'ὴ' => 'ὴ', + 'ή' => 'ή', + 'ὶ' => 'ὶ', + 'ί' => 'ί', + 'ὸ' => 'ὸ', + 'ό' => 'ό', + 'ὺ' => 'ὺ', + 'ύ' => 'ύ', + 'ὼ' => 'ὼ', + 'ώ' => 'ώ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'Ά' => 'Ά', + 'ᾼ' => 'ᾼ', + 'ι' => 'ι', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Έ' => 'Έ', + 'Ὴ' => 'Ὴ', + 'Ή' => 'Ή', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ΐ' => 'ΐ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + 'Ί' => 'Ί', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ΰ' => 'ΰ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ύ' => 'Ύ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + '΅' => '΅', + '`' => '`', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ό' => 'Ό', + 'Ὼ' => 'Ὼ', + 'Ώ' => 'Ώ', + 'ῼ' => 'ῼ', + '´' => '´', + ' ' => ' ', + ' ' => ' ', + 'Ω' => 'Ω', + 'K' => 'K', + 'Å' => 'Å', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + '〈' => '〈', + '〉' => '〉', + '⫝̸' => '⫝̸', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '豈' => '豈', + '更' => '更', + '車' => '車', + '賈' => '賈', + '滑' => '滑', + '串' => '串', + '句' => '句', + '龜' => '龜', + '龜' => '龜', + '契' => '契', + '金' => '金', + '喇' => '喇', + '奈' => '奈', + '懶' => '懶', + '癩' => '癩', + '羅' => '羅', + '蘿' => '蘿', + '螺' => '螺', + '裸' => '裸', + '邏' => '邏', + '樂' => '樂', + '洛' => '洛', + '烙' => '烙', + '珞' => '珞', + '落' => '落', + '酪' => '酪', + '駱' => '駱', + '亂' => '亂', + '卵' => '卵', + '欄' => '欄', + '爛' => '爛', + '蘭' => '蘭', + '鸞' => '鸞', + '嵐' => '嵐', + '濫' => '濫', + '藍' => '藍', + '襤' => '襤', + '拉' => '拉', + '臘' => '臘', + '蠟' => '蠟', + '廊' => '廊', + '朗' => '朗', + '浪' => '浪', + '狼' => '狼', + '郎' => '郎', + '來' => '來', + '冷' => '冷', + '勞' => '勞', + '擄' => '擄', + '櫓' => '櫓', + '爐' => '爐', + '盧' => '盧', + '老' => '老', + '蘆' => '蘆', + '虜' => '虜', + '路' => '路', + '露' => '露', + '魯' => '魯', + '鷺' => '鷺', + '碌' => '碌', + '祿' => '祿', + '綠' => '綠', + '菉' => '菉', + '錄' => '錄', + '鹿' => '鹿', + '論' => '論', + '壟' => '壟', + '弄' => '弄', + '籠' => '籠', + '聾' => '聾', + '牢' => '牢', + '磊' => '磊', + '賂' => '賂', + '雷' => '雷', + '壘' => '壘', + '屢' => '屢', + '樓' => '樓', + '淚' => '淚', + '漏' => '漏', + '累' => '累', + '縷' => '縷', + '陋' => '陋', + '勒' => '勒', + '肋' => '肋', + '凜' => '凜', + '凌' => '凌', + '稜' => '稜', + '綾' => '綾', + '菱' => '菱', + '陵' => '陵', + '讀' => '讀', + '拏' => '拏', + '樂' => '樂', + '諾' => '諾', + '丹' => '丹', + '寧' => '寧', + '怒' => '怒', + '率' => '率', + '異' => '異', + '北' => '北', + '磻' => '磻', + '便' => '便', + '復' => '復', + '不' => '不', + '泌' => '泌', + '數' => '數', + '索' => '索', + '參' => '參', + '塞' => '塞', + '省' => '省', + '葉' => '葉', + '說' => '說', + '殺' => '殺', + '辰' => '辰', + '沈' => '沈', + '拾' => '拾', + '若' => '若', + '掠' => '掠', + '略' => '略', + '亮' => '亮', + '兩' => '兩', + '凉' => '凉', + '梁' => '梁', + '糧' => '糧', + '良' => '良', + '諒' => '諒', + '量' => '量', + '勵' => '勵', + '呂' => '呂', + '女' => '女', + '廬' => '廬', + '旅' => '旅', + '濾' => '濾', + '礪' => '礪', + '閭' => '閭', + '驪' => '驪', + '麗' => '麗', + '黎' => '黎', + '力' => '力', + '曆' => '曆', + '歷' => '歷', + '轢' => '轢', + '年' => '年', + '憐' => '憐', + '戀' => '戀', + '撚' => '撚', + '漣' => '漣', + '煉' => '煉', + '璉' => '璉', + '秊' => '秊', + '練' => '練', + '聯' => '聯', + '輦' => '輦', + '蓮' => '蓮', + '連' => '連', + '鍊' => '鍊', + '列' => '列', + '劣' => '劣', + '咽' => '咽', + '烈' => '烈', + '裂' => '裂', + '說' => '說', + '廉' => '廉', + '念' => '念', + '捻' => '捻', + '殮' => '殮', + '簾' => '簾', + '獵' => '獵', + '令' => '令', + '囹' => '囹', + '寧' => '寧', + '嶺' => '嶺', + '怜' => '怜', + '玲' => '玲', + '瑩' => '瑩', + '羚' => '羚', + '聆' => '聆', + '鈴' => '鈴', + '零' => '零', + '靈' => '靈', + '領' => '領', + '例' => '例', + '禮' => '禮', + '醴' => '醴', + '隸' => '隸', + '惡' => '惡', + '了' => '了', + '僚' => '僚', + '寮' => '寮', + '尿' => '尿', + '料' => '料', + '樂' => '樂', + '燎' => '燎', + '療' => '療', + '蓼' => '蓼', + '遼' => '遼', + '龍' => '龍', + '暈' => '暈', + '阮' => '阮', + '劉' => '劉', + '杻' => '杻', + '柳' => '柳', + '流' => '流', + '溜' => '溜', + '琉' => '琉', + '留' => '留', + '硫' => '硫', + '紐' => '紐', + '類' => '類', + '六' => '六', + '戮' => '戮', + '陸' => '陸', + '倫' => '倫', + '崙' => '崙', + '淪' => '淪', + '輪' => '輪', + '律' => '律', + '慄' => '慄', + '栗' => '栗', + '率' => '率', + '隆' => '隆', + '利' => '利', + '吏' => '吏', + '履' => '履', + '易' => '易', + '李' => '李', + '梨' => '梨', + '泥' => '泥', + '理' => '理', + '痢' => '痢', + '罹' => '罹', + '裏' => '裏', + '裡' => '裡', + '里' => '里', + '離' => '離', + '匿' => '匿', + '溺' => '溺', + '吝' => '吝', + '燐' => '燐', + '璘' => '璘', + '藺' => '藺', + '隣' => '隣', + '鱗' => '鱗', + '麟' => '麟', + '林' => '林', + '淋' => '淋', + '臨' => '臨', + '立' => '立', + '笠' => '笠', + '粒' => '粒', + '狀' => '狀', + '炙' => '炙', + '識' => '識', + '什' => '什', + '茶' => '茶', + '刺' => '刺', + '切' => '切', + '度' => '度', + '拓' => '拓', + '糖' => '糖', + '宅' => '宅', + '洞' => '洞', + '暴' => '暴', + '輻' => '輻', + '行' => '行', + '降' => '降', + '見' => '見', + '廓' => '廓', + '兀' => '兀', + '嗀' => '嗀', + '塚' => '塚', + '晴' => '晴', + '凞' => '凞', + '猪' => '猪', + '益' => '益', + '礼' => '礼', + '神' => '神', + '祥' => '祥', + '福' => '福', + '靖' => '靖', + '精' => '精', + '羽' => '羽', + '蘒' => '蘒', + '諸' => '諸', + '逸' => '逸', + '都' => '都', + '飯' => '飯', + '飼' => '飼', + '館' => '館', + '鶴' => '鶴', + '郞' => '郞', + '隷' => '隷', + '侮' => '侮', + '僧' => '僧', + '免' => '免', + '勉' => '勉', + '勤' => '勤', + '卑' => '卑', + '喝' => '喝', + '嘆' => '嘆', + '器' => '器', + '塀' => '塀', + '墨' => '墨', + '層' => '層', + '屮' => '屮', + '悔' => '悔', + '慨' => '慨', + '憎' => '憎', + '懲' => '懲', + '敏' => '敏', + '既' => '既', + '暑' => '暑', + '梅' => '梅', + '海' => '海', + '渚' => '渚', + '漢' => '漢', + '煮' => '煮', + '爫' => '爫', + '琢' => '琢', + '碑' => '碑', + '社' => '社', + '祉' => '祉', + '祈' => '祈', + '祐' => '祐', + '祖' => '祖', + '祝' => '祝', + '禍' => '禍', + '禎' => '禎', + '穀' => '穀', + '突' => '突', + '節' => '節', + '練' => '練', + '縉' => '縉', + '繁' => '繁', + '署' => '署', + '者' => '者', + '臭' => '臭', + '艹' => '艹', + '艹' => '艹', + '著' => '著', + '褐' => '褐', + '視' => '視', + '謁' => '謁', + '謹' => '謹', + '賓' => '賓', + '贈' => '贈', + '辶' => '辶', + '逸' => '逸', + '難' => '難', + '響' => '響', + '頻' => '頻', + '恵' => '恵', + '𤋮' => '𤋮', + '舘' => '舘', + '並' => '並', + '况' => '况', + '全' => '全', + '侀' => '侀', + '充' => '充', + '冀' => '冀', + '勇' => '勇', + '勺' => '勺', + '喝' => '喝', + '啕' => '啕', + '喙' => '喙', + '嗢' => '嗢', + '塚' => '塚', + '墳' => '墳', + '奄' => '奄', + '奔' => '奔', + '婢' => '婢', + '嬨' => '嬨', + '廒' => '廒', + '廙' => '廙', + '彩' => '彩', + '徭' => '徭', + '惘' => '惘', + '慎' => '慎', + '愈' => '愈', + '憎' => '憎', + '慠' => '慠', + '懲' => '懲', + '戴' => '戴', + '揄' => '揄', + '搜' => '搜', + '摒' => '摒', + '敖' => '敖', + '晴' => '晴', + '朗' => '朗', + '望' => '望', + '杖' => '杖', + '歹' => '歹', + '殺' => '殺', + '流' => '流', + '滛' => '滛', + '滋' => '滋', + '漢' => '漢', + '瀞' => '瀞', + '煮' => '煮', + '瞧' => '瞧', + '爵' => '爵', + '犯' => '犯', + '猪' => '猪', + '瑱' => '瑱', + '甆' => '甆', + '画' => '画', + '瘝' => '瘝', + '瘟' => '瘟', + '益' => '益', + '盛' => '盛', + '直' => '直', + '睊' => '睊', + '着' => '着', + '磌' => '磌', + '窱' => '窱', + '節' => '節', + '类' => '类', + '絛' => '絛', + '練' => '練', + '缾' => '缾', + '者' => '者', + '荒' => '荒', + '華' => '華', + '蝹' => '蝹', + '襁' => '襁', + '覆' => '覆', + '視' => '視', + '調' => '調', + '諸' => '諸', + '請' => '請', + '謁' => '謁', + '諾' => '諾', + '諭' => '諭', + '謹' => '謹', + '變' => '變', + '贈' => '贈', + '輸' => '輸', + '遲' => '遲', + '醙' => '醙', + '鉶' => '鉶', + '陼' => '陼', + '難' => '難', + '靖' => '靖', + '韛' => '韛', + '響' => '響', + '頋' => '頋', + '頻' => '頻', + '鬒' => '鬒', + '龜' => '龜', + '𢡊' => '𢡊', + '𢡄' => '𢡄', + '𣏕' => '𣏕', + '㮝' => '㮝', + '䀘' => '䀘', + '䀹' => '䀹', + '𥉉' => '𥉉', + '𥳐' => '𥳐', + '𧻓' => '𧻓', + '齃' => '齃', + '龎' => '龎', + 'יִ' => 'יִ', + 'ײַ' => 'ײַ', + 'שׁ' => 'שׁ', + 'שׂ' => 'שׂ', + 'שּׁ' => 'שּׁ', + 'שּׂ' => 'שּׂ', + 'אַ' => 'אַ', + 'אָ' => 'אָ', + 'אּ' => 'אּ', + 'בּ' => 'בּ', + 'גּ' => 'גּ', + 'דּ' => 'דּ', + 'הּ' => 'הּ', + 'וּ' => 'וּ', + 'זּ' => 'זּ', + 'טּ' => 'טּ', + 'יּ' => 'יּ', + 'ךּ' => 'ךּ', + 'כּ' => 'כּ', + 'לּ' => 'לּ', + 'מּ' => 'מּ', + 'נּ' => 'נּ', + 'סּ' => 'סּ', + 'ףּ' => 'ףּ', + 'פּ' => 'פּ', + 'צּ' => 'צּ', + 'קּ' => 'קּ', + 'רּ' => 'רּ', + 'שּ' => 'שּ', + 'תּ' => 'תּ', + 'וֹ' => 'וֹ', + 'בֿ' => 'בֿ', + 'כֿ' => 'כֿ', + 'פֿ' => 'פֿ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', + '𝅗𝅥' => '𝅗𝅥', + '𝅘𝅥' => '𝅘𝅥', + '𝅘𝅥𝅮' => '𝅘𝅥𝅮', + '𝅘𝅥𝅯' => '𝅘𝅥𝅯', + '𝅘𝅥𝅰' => '𝅘𝅥𝅰', + '𝅘𝅥𝅱' => '𝅘𝅥𝅱', + '𝅘𝅥𝅲' => '𝅘𝅥𝅲', + '𝆹𝅥' => '𝆹𝅥', + '𝆺𝅥' => '𝆺𝅥', + '𝆹𝅥𝅮' => '𝆹𝅥𝅮', + '𝆺𝅥𝅮' => '𝆺𝅥𝅮', + '𝆹𝅥𝅯' => '𝆹𝅥𝅯', + '𝆺𝅥𝅯' => '𝆺𝅥𝅯', + '丽' => '丽', + '丸' => '丸', + '乁' => '乁', + '𠄢' => '𠄢', + '你' => '你', + '侮' => '侮', + '侻' => '侻', + '倂' => '倂', + '偺' => '偺', + '備' => '備', + '僧' => '僧', + '像' => '像', + '㒞' => '㒞', + '𠘺' => '𠘺', + '免' => '免', + '兔' => '兔', + '兤' => '兤', + '具' => '具', + '𠔜' => '𠔜', + '㒹' => '㒹', + '內' => '內', + '再' => '再', + '𠕋' => '𠕋', + '冗' => '冗', + '冤' => '冤', + '仌' => '仌', + '冬' => '冬', + '况' => '况', + '𩇟' => '𩇟', + '凵' => '凵', + '刃' => '刃', + '㓟' => '㓟', + '刻' => '刻', + '剆' => '剆', + '割' => '割', + '剷' => '剷', + '㔕' => '㔕', + '勇' => '勇', + '勉' => '勉', + '勤' => '勤', + '勺' => '勺', + '包' => '包', + '匆' => '匆', + '北' => '北', + '卉' => '卉', + '卑' => '卑', + '博' => '博', + '即' => '即', + '卽' => '卽', + '卿' => '卿', + '卿' => '卿', + '卿' => '卿', + '𠨬' => '𠨬', + '灰' => '灰', + '及' => '及', + '叟' => '叟', + '𠭣' => '𠭣', + '叫' => '叫', + '叱' => '叱', + '吆' => '吆', + '咞' => '咞', + '吸' => '吸', + '呈' => '呈', + '周' => '周', + '咢' => '咢', + '哶' => '哶', + '唐' => '唐', + '啓' => '啓', + '啣' => '啣', + '善' => '善', + '善' => '善', + '喙' => '喙', + '喫' => '喫', + '喳' => '喳', + '嗂' => '嗂', + '圖' => '圖', + '嘆' => '嘆', + '圗' => '圗', + '噑' => '噑', + '噴' => '噴', + '切' => '切', + '壮' => '壮', + '城' => '城', + '埴' => '埴', + '堍' => '堍', + '型' => '型', + '堲' => '堲', + '報' => '報', + '墬' => '墬', + '𡓤' => '𡓤', + '売' => '売', + '壷' => '壷', + '夆' => '夆', + '多' => '多', + '夢' => '夢', + '奢' => '奢', + '𡚨' => '𡚨', + '𡛪' => '𡛪', + '姬' => '姬', + '娛' => '娛', + '娧' => '娧', + '姘' => '姘', + '婦' => '婦', + '㛮' => '㛮', + '㛼' => '㛼', + '嬈' => '嬈', + '嬾' => '嬾', + '嬾' => '嬾', + '𡧈' => '𡧈', + '寃' => '寃', + '寘' => '寘', + '寧' => '寧', + '寳' => '寳', + '𡬘' => '𡬘', + '寿' => '寿', + '将' => '将', + '当' => '当', + '尢' => '尢', + '㞁' => '㞁', + '屠' => '屠', + '屮' => '屮', + '峀' => '峀', + '岍' => '岍', + '𡷤' => '𡷤', + '嵃' => '嵃', + '𡷦' => '𡷦', + '嵮' => '嵮', + '嵫' => '嵫', + '嵼' => '嵼', + '巡' => '巡', + '巢' => '巢', + '㠯' => '㠯', + '巽' => '巽', + '帨' => '帨', + '帽' => '帽', + '幩' => '幩', + '㡢' => '㡢', + '𢆃' => '𢆃', + '㡼' => '㡼', + '庰' => '庰', + '庳' => '庳', + '庶' => '庶', + '廊' => '廊', + '𪎒' => '𪎒', + '廾' => '廾', + '𢌱' => '𢌱', + '𢌱' => '𢌱', + '舁' => '舁', + '弢' => '弢', + '弢' => '弢', + '㣇' => '㣇', + '𣊸' => '𣊸', + '𦇚' => '𦇚', + '形' => '形', + '彫' => '彫', + '㣣' => '㣣', + '徚' => '徚', + '忍' => '忍', + '志' => '志', + '忹' => '忹', + '悁' => '悁', + '㤺' => '㤺', + '㤜' => '㤜', + '悔' => '悔', + '𢛔' => '𢛔', + '惇' => '惇', + '慈' => '慈', + '慌' => '慌', + '慎' => '慎', + '慌' => '慌', + '慺' => '慺', + '憎' => '憎', + '憲' => '憲', + '憤' => '憤', + '憯' => '憯', + '懞' => '懞', + '懲' => '懲', + '懶' => '懶', + '成' => '成', + '戛' => '戛', + '扝' => '扝', + '抱' => '抱', + '拔' => '拔', + '捐' => '捐', + '𢬌' => '𢬌', + '挽' => '挽', + '拼' => '拼', + '捨' => '捨', + '掃' => '掃', + '揤' => '揤', + '𢯱' => '𢯱', + '搢' => '搢', + '揅' => '揅', + '掩' => '掩', + '㨮' => '㨮', + '摩' => '摩', + '摾' => '摾', + '撝' => '撝', + '摷' => '摷', + '㩬' => '㩬', + '敏' => '敏', + '敬' => '敬', + '𣀊' => '𣀊', + '旣' => '旣', + '書' => '書', + '晉' => '晉', + '㬙' => '㬙', + '暑' => '暑', + '㬈' => '㬈', + '㫤' => '㫤', + '冒' => '冒', + '冕' => '冕', + '最' => '最', + '暜' => '暜', + '肭' => '肭', + '䏙' => '䏙', + '朗' => '朗', + '望' => '望', + '朡' => '朡', + '杞' => '杞', + '杓' => '杓', + '𣏃' => '𣏃', + '㭉' => '㭉', + '柺' => '柺', + '枅' => '枅', + '桒' => '桒', + '梅' => '梅', + '𣑭' => '𣑭', + '梎' => '梎', + '栟' => '栟', + '椔' => '椔', + '㮝' => '㮝', + '楂' => '楂', + '榣' => '榣', + '槪' => '槪', + '檨' => '檨', + '𣚣' => '𣚣', + '櫛' => '櫛', + '㰘' => '㰘', + '次' => '次', + '𣢧' => '𣢧', + '歔' => '歔', + '㱎' => '㱎', + '歲' => '歲', + '殟' => '殟', + '殺' => '殺', + '殻' => '殻', + '𣪍' => '𣪍', + '𡴋' => '𡴋', + '𣫺' => '𣫺', + '汎' => '汎', + '𣲼' => '𣲼', + '沿' => '沿', + '泍' => '泍', + '汧' => '汧', + '洖' => '洖', + '派' => '派', + '海' => '海', + '流' => '流', + '浩' => '浩', + '浸' => '浸', + '涅' => '涅', + '𣴞' => '𣴞', + '洴' => '洴', + '港' => '港', + '湮' => '湮', + '㴳' => '㴳', + '滋' => '滋', + '滇' => '滇', + '𣻑' => '𣻑', + '淹' => '淹', + '潮' => '潮', + '𣽞' => '𣽞', + '𣾎' => '𣾎', + '濆' => '濆', + '瀹' => '瀹', + '瀞' => '瀞', + '瀛' => '瀛', + '㶖' => '㶖', + '灊' => '灊', + '災' => '災', + '灷' => '灷', + '炭' => '炭', + '𠔥' => '𠔥', + '煅' => '煅', + '𤉣' => '𤉣', + '熜' => '熜', + '𤎫' => '𤎫', + '爨' => '爨', + '爵' => '爵', + '牐' => '牐', + '𤘈' => '𤘈', + '犀' => '犀', + '犕' => '犕', + '𤜵' => '𤜵', + '𤠔' => '𤠔', + '獺' => '獺', + '王' => '王', + '㺬' => '㺬', + '玥' => '玥', + '㺸' => '㺸', + '㺸' => '㺸', + '瑇' => '瑇', + '瑜' => '瑜', + '瑱' => '瑱', + '璅' => '璅', + '瓊' => '瓊', + '㼛' => '㼛', + '甤' => '甤', + '𤰶' => '𤰶', + '甾' => '甾', + '𤲒' => '𤲒', + '異' => '異', + '𢆟' => '𢆟', + '瘐' => '瘐', + '𤾡' => '𤾡', + '𤾸' => '𤾸', + '𥁄' => '𥁄', + '㿼' => '㿼', + '䀈' => '䀈', + '直' => '直', + '𥃳' => '𥃳', + '𥃲' => '𥃲', + '𥄙' => '𥄙', + '𥄳' => '𥄳', + '眞' => '眞', + '真' => '真', + '真' => '真', + '睊' => '睊', + '䀹' => '䀹', + '瞋' => '瞋', + '䁆' => '䁆', + '䂖' => '䂖', + '𥐝' => '𥐝', + '硎' => '硎', + '碌' => '碌', + '磌' => '磌', + '䃣' => '䃣', + '𥘦' => '𥘦', + '祖' => '祖', + '𥚚' => '𥚚', + '𥛅' => '𥛅', + '福' => '福', + '秫' => '秫', + '䄯' => '䄯', + '穀' => '穀', + '穊' => '穊', + '穏' => '穏', + '𥥼' => '𥥼', + '𥪧' => '𥪧', + '𥪧' => '𥪧', + '竮' => '竮', + '䈂' => '䈂', + '𥮫' => '𥮫', + '篆' => '篆', + '築' => '築', + '䈧' => '䈧', + '𥲀' => '𥲀', + '糒' => '糒', + '䊠' => '䊠', + '糨' => '糨', + '糣' => '糣', + '紀' => '紀', + '𥾆' => '𥾆', + '絣' => '絣', + '䌁' => '䌁', + '緇' => '緇', + '縂' => '縂', + '繅' => '繅', + '䌴' => '䌴', + '𦈨' => '𦈨', + '𦉇' => '𦉇', + '䍙' => '䍙', + '𦋙' => '𦋙', + '罺' => '罺', + '𦌾' => '𦌾', + '羕' => '羕', + '翺' => '翺', + '者' => '者', + '𦓚' => '𦓚', + '𦔣' => '𦔣', + '聠' => '聠', + '𦖨' => '𦖨', + '聰' => '聰', + '𣍟' => '𣍟', + '䏕' => '䏕', + '育' => '育', + '脃' => '脃', + '䐋' => '䐋', + '脾' => '脾', + '媵' => '媵', + '𦞧' => '𦞧', + '𦞵' => '𦞵', + '𣎓' => '𣎓', + '𣎜' => '𣎜', + '舁' => '舁', + '舄' => '舄', + '辞' => '辞', + '䑫' => '䑫', + '芑' => '芑', + '芋' => '芋', + '芝' => '芝', + '劳' => '劳', + '花' => '花', + '芳' => '芳', + '芽' => '芽', + '苦' => '苦', + '𦬼' => '𦬼', + '若' => '若', + '茝' => '茝', + '荣' => '荣', + '莭' => '莭', + '茣' => '茣', + '莽' => '莽', + '菧' => '菧', + '著' => '著', + '荓' => '荓', + '菊' => '菊', + '菌' => '菌', + '菜' => '菜', + '𦰶' => '𦰶', + '𦵫' => '𦵫', + '𦳕' => '𦳕', + '䔫' => '䔫', + '蓱' => '蓱', + '蓳' => '蓳', + '蔖' => '蔖', + '𧏊' => '𧏊', + '蕤' => '蕤', + '𦼬' => '𦼬', + '䕝' => '䕝', + '䕡' => '䕡', + '𦾱' => '𦾱', + '𧃒' => '𧃒', + '䕫' => '䕫', + '虐' => '虐', + '虜' => '虜', + '虧' => '虧', + '虩' => '虩', + '蚩' => '蚩', + '蚈' => '蚈', + '蜎' => '蜎', + '蛢' => '蛢', + '蝹' => '蝹', + '蜨' => '蜨', + '蝫' => '蝫', + '螆' => '螆', + '䗗' => '䗗', + '蟡' => '蟡', + '蠁' => '蠁', + '䗹' => '䗹', + '衠' => '衠', + '衣' => '衣', + '𧙧' => '𧙧', + '裗' => '裗', + '裞' => '裞', + '䘵' => '䘵', + '裺' => '裺', + '㒻' => '㒻', + '𧢮' => '𧢮', + '𧥦' => '𧥦', + '䚾' => '䚾', + '䛇' => '䛇', + '誠' => '誠', + '諭' => '諭', + '變' => '變', + '豕' => '豕', + '𧲨' => '𧲨', + '貫' => '貫', + '賁' => '賁', + '贛' => '贛', + '起' => '起', + '𧼯' => '𧼯', + '𠠄' => '𠠄', + '跋' => '跋', + '趼' => '趼', + '跰' => '跰', + '𠣞' => '𠣞', + '軔' => '軔', + '輸' => '輸', + '𨗒' => '𨗒', + '𨗭' => '𨗭', + '邔' => '邔', + '郱' => '郱', + '鄑' => '鄑', + '𨜮' => '𨜮', + '鄛' => '鄛', + '鈸' => '鈸', + '鋗' => '鋗', + '鋘' => '鋘', + '鉼' => '鉼', + '鏹' => '鏹', + '鐕' => '鐕', + '𨯺' => '𨯺', + '開' => '開', + '䦕' => '䦕', + '閷' => '閷', + '𨵷' => '𨵷', + '䧦' => '䧦', + '雃' => '雃', + '嶲' => '嶲', + '霣' => '霣', + '𩅅' => '𩅅', + '𩈚' => '𩈚', + '䩮' => '䩮', + '䩶' => '䩶', + '韠' => '韠', + '𩐊' => '𩐊', + '䪲' => '䪲', + '𩒖' => '𩒖', + '頋' => '頋', + '頋' => '頋', + '頩' => '頩', + '𩖶' => '𩖶', + '飢' => '飢', + '䬳' => '䬳', + '餩' => '餩', + '馧' => '馧', + '駂' => '駂', + '駾' => '駾', + '䯎' => '䯎', + '𩬰' => '𩬰', + '鬒' => '鬒', + '鱀' => '鱀', + '鳽' => '鳽', + '䳎' => '䳎', + '䳭' => '䳭', + '鵧' => '鵧', + '𪃎' => '𪃎', + '䳸' => '䳸', + '𪄅' => '𪄅', + '𪈎' => '𪈎', + '𪊑' => '𪊑', + '麻' => '麻', + '䵖' => '䵖', + '黹' => '黹', + '黾' => '黾', + '鼅' => '鼅', + '鼏' => '鼏', + '鼖' => '鼖', + '鼻' => '鼻', + '𪘀' => '𪘀', +); diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php new file mode 100644 index 0000000..ec90f36 --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php @@ -0,0 +1,876 @@ + 230, + '́' => 230, + '̂' => 230, + '̃' => 230, + '̄' => 230, + '̅' => 230, + '̆' => 230, + '̇' => 230, + '̈' => 230, + '̉' => 230, + '̊' => 230, + '̋' => 230, + '̌' => 230, + '̍' => 230, + '̎' => 230, + '̏' => 230, + '̐' => 230, + '̑' => 230, + '̒' => 230, + '̓' => 230, + '̔' => 230, + '̕' => 232, + '̖' => 220, + '̗' => 220, + '̘' => 220, + '̙' => 220, + '̚' => 232, + '̛' => 216, + '̜' => 220, + '̝' => 220, + '̞' => 220, + '̟' => 220, + '̠' => 220, + '̡' => 202, + '̢' => 202, + '̣' => 220, + '̤' => 220, + '̥' => 220, + '̦' => 220, + '̧' => 202, + '̨' => 202, + '̩' => 220, + '̪' => 220, + '̫' => 220, + '̬' => 220, + '̭' => 220, + '̮' => 220, + '̯' => 220, + '̰' => 220, + '̱' => 220, + '̲' => 220, + '̳' => 220, + '̴' => 1, + '̵' => 1, + '̶' => 1, + '̷' => 1, + '̸' => 1, + '̹' => 220, + '̺' => 220, + '̻' => 220, + '̼' => 220, + '̽' => 230, + '̾' => 230, + '̿' => 230, + '̀' => 230, + '́' => 230, + '͂' => 230, + '̓' => 230, + '̈́' => 230, + 'ͅ' => 240, + '͆' => 230, + '͇' => 220, + '͈' => 220, + '͉' => 220, + '͊' => 230, + '͋' => 230, + '͌' => 230, + '͍' => 220, + '͎' => 220, + '͐' => 230, + '͑' => 230, + '͒' => 230, + '͓' => 220, + '͔' => 220, + '͕' => 220, + '͖' => 220, + '͗' => 230, + '͘' => 232, + '͙' => 220, + '͚' => 220, + '͛' => 230, + '͜' => 233, + '͝' => 234, + '͞' => 234, + '͟' => 233, + '͠' => 234, + '͡' => 234, + '͢' => 233, + 'ͣ' => 230, + 'ͤ' => 230, + 'ͥ' => 230, + 'ͦ' => 230, + 'ͧ' => 230, + 'ͨ' => 230, + 'ͩ' => 230, + 'ͪ' => 230, + 'ͫ' => 230, + 'ͬ' => 230, + 'ͭ' => 230, + 'ͮ' => 230, + 'ͯ' => 230, + '҃' => 230, + '҄' => 230, + '҅' => 230, + '҆' => 230, + '҇' => 230, + '֑' => 220, + '֒' => 230, + '֓' => 230, + '֔' => 230, + '֕' => 230, + '֖' => 220, + '֗' => 230, + '֘' => 230, + '֙' => 230, + '֚' => 222, + '֛' => 220, + '֜' => 230, + '֝' => 230, + '֞' => 230, + '֟' => 230, + '֠' => 230, + '֡' => 230, + '֢' => 220, + '֣' => 220, + '֤' => 220, + '֥' => 220, + '֦' => 220, + '֧' => 220, + '֨' => 230, + '֩' => 230, + '֪' => 220, + '֫' => 230, + '֬' => 230, + '֭' => 222, + '֮' => 228, + '֯' => 230, + 'ְ' => 10, + 'ֱ' => 11, + 'ֲ' => 12, + 'ֳ' => 13, + 'ִ' => 14, + 'ֵ' => 15, + 'ֶ' => 16, + 'ַ' => 17, + 'ָ' => 18, + 'ֹ' => 19, + 'ֺ' => 19, + 'ֻ' => 20, + 'ּ' => 21, + 'ֽ' => 22, + 'ֿ' => 23, + 'ׁ' => 24, + 'ׂ' => 25, + 'ׄ' => 230, + 'ׅ' => 220, + 'ׇ' => 18, + 'ؐ' => 230, + 'ؑ' => 230, + 'ؒ' => 230, + 'ؓ' => 230, + 'ؔ' => 230, + 'ؕ' => 230, + 'ؖ' => 230, + 'ؗ' => 230, + 'ؘ' => 30, + 'ؙ' => 31, + 'ؚ' => 32, + 'ً' => 27, + 'ٌ' => 28, + 'ٍ' => 29, + 'َ' => 30, + 'ُ' => 31, + 'ِ' => 32, + 'ّ' => 33, + 'ْ' => 34, + 'ٓ' => 230, + 'ٔ' => 230, + 'ٕ' => 220, + 'ٖ' => 220, + 'ٗ' => 230, + '٘' => 230, + 'ٙ' => 230, + 'ٚ' => 230, + 'ٛ' => 230, + 'ٜ' => 220, + 'ٝ' => 230, + 'ٞ' => 230, + 'ٟ' => 220, + 'ٰ' => 35, + 'ۖ' => 230, + 'ۗ' => 230, + 'ۘ' => 230, + 'ۙ' => 230, + 'ۚ' => 230, + 'ۛ' => 230, + 'ۜ' => 230, + '۟' => 230, + '۠' => 230, + 'ۡ' => 230, + 'ۢ' => 230, + 'ۣ' => 220, + 'ۤ' => 230, + 'ۧ' => 230, + 'ۨ' => 230, + '۪' => 220, + '۫' => 230, + '۬' => 230, + 'ۭ' => 220, + 'ܑ' => 36, + 'ܰ' => 230, + 'ܱ' => 220, + 'ܲ' => 230, + 'ܳ' => 230, + 'ܴ' => 220, + 'ܵ' => 230, + 'ܶ' => 230, + 'ܷ' => 220, + 'ܸ' => 220, + 'ܹ' => 220, + 'ܺ' => 230, + 'ܻ' => 220, + 'ܼ' => 220, + 'ܽ' => 230, + 'ܾ' => 220, + 'ܿ' => 230, + '݀' => 230, + '݁' => 230, + '݂' => 220, + '݃' => 230, + '݄' => 220, + '݅' => 230, + '݆' => 220, + '݇' => 230, + '݈' => 220, + '݉' => 230, + '݊' => 230, + '߫' => 230, + '߬' => 230, + '߭' => 230, + '߮' => 230, + '߯' => 230, + '߰' => 230, + '߱' => 230, + '߲' => 220, + '߳' => 230, + '߽' => 220, + 'ࠖ' => 230, + 'ࠗ' => 230, + '࠘' => 230, + '࠙' => 230, + 'ࠛ' => 230, + 'ࠜ' => 230, + 'ࠝ' => 230, + 'ࠞ' => 230, + 'ࠟ' => 230, + 'ࠠ' => 230, + 'ࠡ' => 230, + 'ࠢ' => 230, + 'ࠣ' => 230, + 'ࠥ' => 230, + 'ࠦ' => 230, + 'ࠧ' => 230, + 'ࠩ' => 230, + 'ࠪ' => 230, + 'ࠫ' => 230, + 'ࠬ' => 230, + '࠭' => 230, + '࡙' => 220, + '࡚' => 220, + '࡛' => 220, + '࣓' => 220, + 'ࣔ' => 230, + 'ࣕ' => 230, + 'ࣖ' => 230, + 'ࣗ' => 230, + 'ࣘ' => 230, + 'ࣙ' => 230, + 'ࣚ' => 230, + 'ࣛ' => 230, + 'ࣜ' => 230, + 'ࣝ' => 230, + 'ࣞ' => 230, + 'ࣟ' => 230, + '࣠' => 230, + '࣡' => 230, + 'ࣣ' => 220, + 'ࣤ' => 230, + 'ࣥ' => 230, + 'ࣦ' => 220, + 'ࣧ' => 230, + 'ࣨ' => 230, + 'ࣩ' => 220, + '࣪' => 230, + '࣫' => 230, + '࣬' => 230, + '࣭' => 220, + '࣮' => 220, + '࣯' => 220, + 'ࣰ' => 27, + 'ࣱ' => 28, + 'ࣲ' => 29, + 'ࣳ' => 230, + 'ࣴ' => 230, + 'ࣵ' => 230, + 'ࣶ' => 220, + 'ࣷ' => 230, + 'ࣸ' => 230, + 'ࣹ' => 220, + 'ࣺ' => 220, + 'ࣻ' => 230, + 'ࣼ' => 230, + 'ࣽ' => 230, + 'ࣾ' => 230, + 'ࣿ' => 230, + '़' => 7, + '्' => 9, + '॑' => 230, + '॒' => 220, + '॓' => 230, + '॔' => 230, + '়' => 7, + '্' => 9, + '৾' => 230, + '਼' => 7, + '੍' => 9, + '઼' => 7, + '્' => 9, + '଼' => 7, + '୍' => 9, + '்' => 9, + '్' => 9, + 'ౕ' => 84, + 'ౖ' => 91, + '಼' => 7, + '್' => 9, + '഻' => 9, + '഼' => 9, + '്' => 9, + '්' => 9, + 'ุ' => 103, + 'ู' => 103, + 'ฺ' => 9, + '่' => 107, + '้' => 107, + '๊' => 107, + '๋' => 107, + 'ຸ' => 118, + 'ູ' => 118, + '຺' => 9, + '່' => 122, + '້' => 122, + '໊' => 122, + '໋' => 122, + '༘' => 220, + '༙' => 220, + '༵' => 220, + '༷' => 220, + '༹' => 216, + 'ཱ' => 129, + 'ི' => 130, + 'ུ' => 132, + 'ེ' => 130, + 'ཻ' => 130, + 'ོ' => 130, + 'ཽ' => 130, + 'ྀ' => 130, + 'ྂ' => 230, + 'ྃ' => 230, + '྄' => 9, + '྆' => 230, + '྇' => 230, + '࿆' => 220, + '့' => 7, + '္' => 9, + '်' => 9, + 'ႍ' => 220, + '፝' => 230, + '፞' => 230, + '፟' => 230, + '᜔' => 9, + '᜴' => 9, + '្' => 9, + '៝' => 230, + 'ᢩ' => 228, + '᤹' => 222, + '᤺' => 230, + '᤻' => 220, + 'ᨗ' => 230, + 'ᨘ' => 220, + '᩠' => 9, + '᩵' => 230, + '᩶' => 230, + '᩷' => 230, + '᩸' => 230, + '᩹' => 230, + '᩺' => 230, + '᩻' => 230, + '᩼' => 230, + '᩿' => 220, + '᪰' => 230, + '᪱' => 230, + '᪲' => 230, + '᪳' => 230, + '᪴' => 230, + '᪵' => 220, + '᪶' => 220, + '᪷' => 220, + '᪸' => 220, + '᪹' => 220, + '᪺' => 220, + '᪻' => 230, + '᪼' => 230, + '᪽' => 220, + 'ᪿ' => 220, + 'ᫀ' => 220, + '᬴' => 7, + '᭄' => 9, + '᭫' => 230, + '᭬' => 220, + '᭭' => 230, + '᭮' => 230, + '᭯' => 230, + '᭰' => 230, + '᭱' => 230, + '᭲' => 230, + '᭳' => 230, + '᮪' => 9, + '᮫' => 9, + '᯦' => 7, + '᯲' => 9, + '᯳' => 9, + '᰷' => 7, + '᳐' => 230, + '᳑' => 230, + '᳒' => 230, + '᳔' => 1, + '᳕' => 220, + '᳖' => 220, + '᳗' => 220, + '᳘' => 220, + '᳙' => 220, + '᳚' => 230, + '᳛' => 230, + '᳜' => 220, + '᳝' => 220, + '᳞' => 220, + '᳟' => 220, + '᳠' => 230, + '᳢' => 1, + '᳣' => 1, + '᳤' => 1, + '᳥' => 1, + '᳦' => 1, + '᳧' => 1, + '᳨' => 1, + '᳭' => 220, + '᳴' => 230, + '᳸' => 230, + '᳹' => 230, + '᷀' => 230, + '᷁' => 230, + '᷂' => 220, + '᷃' => 230, + '᷄' => 230, + '᷅' => 230, + '᷆' => 230, + '᷇' => 230, + '᷈' => 230, + '᷉' => 230, + '᷊' => 220, + '᷋' => 230, + '᷌' => 230, + '᷍' => 234, + '᷎' => 214, + '᷏' => 220, + '᷐' => 202, + '᷑' => 230, + '᷒' => 230, + 'ᷓ' => 230, + 'ᷔ' => 230, + 'ᷕ' => 230, + 'ᷖ' => 230, + 'ᷗ' => 230, + 'ᷘ' => 230, + 'ᷙ' => 230, + 'ᷚ' => 230, + 'ᷛ' => 230, + 'ᷜ' => 230, + 'ᷝ' => 230, + 'ᷞ' => 230, + 'ᷟ' => 230, + 'ᷠ' => 230, + 'ᷡ' => 230, + 'ᷢ' => 230, + 'ᷣ' => 230, + 'ᷤ' => 230, + 'ᷥ' => 230, + 'ᷦ' => 230, + 'ᷧ' => 230, + 'ᷨ' => 230, + 'ᷩ' => 230, + 'ᷪ' => 230, + 'ᷫ' => 230, + 'ᷬ' => 230, + 'ᷭ' => 230, + 'ᷮ' => 230, + 'ᷯ' => 230, + 'ᷰ' => 230, + 'ᷱ' => 230, + 'ᷲ' => 230, + 'ᷳ' => 230, + 'ᷴ' => 230, + '᷵' => 230, + '᷶' => 232, + '᷷' => 228, + '᷸' => 228, + '᷹' => 220, + '᷻' => 230, + '᷼' => 233, + '᷽' => 220, + '᷾' => 230, + '᷿' => 220, + '⃐' => 230, + '⃑' => 230, + '⃒' => 1, + '⃓' => 1, + '⃔' => 230, + '⃕' => 230, + '⃖' => 230, + '⃗' => 230, + '⃘' => 1, + '⃙' => 1, + '⃚' => 1, + '⃛' => 230, + '⃜' => 230, + '⃡' => 230, + '⃥' => 1, + '⃦' => 1, + '⃧' => 230, + '⃨' => 220, + '⃩' => 230, + '⃪' => 1, + '⃫' => 1, + '⃬' => 220, + '⃭' => 220, + '⃮' => 220, + '⃯' => 220, + '⃰' => 230, + '⳯' => 230, + '⳰' => 230, + '⳱' => 230, + '⵿' => 9, + 'ⷠ' => 230, + 'ⷡ' => 230, + 'ⷢ' => 230, + 'ⷣ' => 230, + 'ⷤ' => 230, + 'ⷥ' => 230, + 'ⷦ' => 230, + 'ⷧ' => 230, + 'ⷨ' => 230, + 'ⷩ' => 230, + 'ⷪ' => 230, + 'ⷫ' => 230, + 'ⷬ' => 230, + 'ⷭ' => 230, + 'ⷮ' => 230, + 'ⷯ' => 230, + 'ⷰ' => 230, + 'ⷱ' => 230, + 'ⷲ' => 230, + 'ⷳ' => 230, + 'ⷴ' => 230, + 'ⷵ' => 230, + 'ⷶ' => 230, + 'ⷷ' => 230, + 'ⷸ' => 230, + 'ⷹ' => 230, + 'ⷺ' => 230, + 'ⷻ' => 230, + 'ⷼ' => 230, + 'ⷽ' => 230, + 'ⷾ' => 230, + 'ⷿ' => 230, + '〪' => 218, + '〫' => 228, + '〬' => 232, + '〭' => 222, + '〮' => 224, + '〯' => 224, + '゙' => 8, + '゚' => 8, + '꙯' => 230, + 'ꙴ' => 230, + 'ꙵ' => 230, + 'ꙶ' => 230, + 'ꙷ' => 230, + 'ꙸ' => 230, + 'ꙹ' => 230, + 'ꙺ' => 230, + 'ꙻ' => 230, + '꙼' => 230, + '꙽' => 230, + 'ꚞ' => 230, + 'ꚟ' => 230, + '꛰' => 230, + '꛱' => 230, + '꠆' => 9, + '꠬' => 9, + '꣄' => 9, + '꣠' => 230, + '꣡' => 230, + '꣢' => 230, + '꣣' => 230, + '꣤' => 230, + '꣥' => 230, + '꣦' => 230, + '꣧' => 230, + '꣨' => 230, + '꣩' => 230, + '꣪' => 230, + '꣫' => 230, + '꣬' => 230, + '꣭' => 230, + '꣮' => 230, + '꣯' => 230, + '꣰' => 230, + '꣱' => 230, + '꤫' => 220, + '꤬' => 220, + '꤭' => 220, + '꥓' => 9, + '꦳' => 7, + '꧀' => 9, + 'ꪰ' => 230, + 'ꪲ' => 230, + 'ꪳ' => 230, + 'ꪴ' => 220, + 'ꪷ' => 230, + 'ꪸ' => 230, + 'ꪾ' => 230, + '꪿' => 230, + '꫁' => 230, + '꫶' => 9, + '꯭' => 9, + 'ﬞ' => 26, + '︠' => 230, + '︡' => 230, + '︢' => 230, + '︣' => 230, + '︤' => 230, + '︥' => 230, + '︦' => 230, + '︧' => 220, + '︨' => 220, + '︩' => 220, + '︪' => 220, + '︫' => 220, + '︬' => 220, + '︭' => 220, + '︮' => 230, + '︯' => 230, + '𐇽' => 220, + '𐋠' => 220, + '𐍶' => 230, + '𐍷' => 230, + '𐍸' => 230, + '𐍹' => 230, + '𐍺' => 230, + '𐨍' => 220, + '𐨏' => 230, + '𐨸' => 230, + '𐨹' => 1, + '𐨺' => 220, + '𐨿' => 9, + '𐫥' => 230, + '𐫦' => 220, + '𐴤' => 230, + '𐴥' => 230, + '𐴦' => 230, + '𐴧' => 230, + '𐺫' => 230, + '𐺬' => 230, + '𐽆' => 220, + '𐽇' => 220, + '𐽈' => 230, + '𐽉' => 230, + '𐽊' => 230, + '𐽋' => 220, + '𐽌' => 230, + '𐽍' => 220, + '𐽎' => 220, + '𐽏' => 220, + '𐽐' => 220, + '𑁆' => 9, + '𑁿' => 9, + '𑂹' => 9, + '𑂺' => 7, + '𑄀' => 230, + '𑄁' => 230, + '𑄂' => 230, + '𑄳' => 9, + '𑄴' => 9, + '𑅳' => 7, + '𑇀' => 9, + '𑇊' => 7, + '𑈵' => 9, + '𑈶' => 7, + '𑋩' => 7, + '𑋪' => 9, + '𑌻' => 7, + '𑌼' => 7, + '𑍍' => 9, + '𑍦' => 230, + '𑍧' => 230, + '𑍨' => 230, + '𑍩' => 230, + '𑍪' => 230, + '𑍫' => 230, + '𑍬' => 230, + '𑍰' => 230, + '𑍱' => 230, + '𑍲' => 230, + '𑍳' => 230, + '𑍴' => 230, + '𑑂' => 9, + '𑑆' => 7, + '𑑞' => 230, + '𑓂' => 9, + '𑓃' => 7, + '𑖿' => 9, + '𑗀' => 7, + '𑘿' => 9, + '𑚶' => 9, + '𑚷' => 7, + '𑜫' => 9, + '𑠹' => 9, + '𑠺' => 7, + '𑤽' => 9, + '𑤾' => 9, + '𑥃' => 7, + '𑧠' => 9, + '𑨴' => 9, + '𑩇' => 9, + '𑪙' => 9, + '𑰿' => 9, + '𑵂' => 7, + '𑵄' => 9, + '𑵅' => 9, + '𑶗' => 9, + '𖫰' => 1, + '𖫱' => 1, + '𖫲' => 1, + '𖫳' => 1, + '𖫴' => 1, + '𖬰' => 230, + '𖬱' => 230, + '𖬲' => 230, + '𖬳' => 230, + '𖬴' => 230, + '𖬵' => 230, + '𖬶' => 230, + '𖿰' => 6, + '𖿱' => 6, + '𛲞' => 1, + '𝅥' => 216, + '𝅦' => 216, + '𝅧' => 1, + '𝅨' => 1, + '𝅩' => 1, + '𝅭' => 226, + '𝅮' => 216, + '𝅯' => 216, + '𝅰' => 216, + '𝅱' => 216, + '𝅲' => 216, + '𝅻' => 220, + '𝅼' => 220, + '𝅽' => 220, + '𝅾' => 220, + '𝅿' => 220, + '𝆀' => 220, + '𝆁' => 220, + '𝆂' => 220, + '𝆅' => 230, + '𝆆' => 230, + '𝆇' => 230, + '𝆈' => 230, + '𝆉' => 230, + '𝆊' => 220, + '𝆋' => 220, + '𝆪' => 230, + '𝆫' => 230, + '𝆬' => 230, + '𝆭' => 230, + '𝉂' => 230, + '𝉃' => 230, + '𝉄' => 230, + '𞀀' => 230, + '𞀁' => 230, + '𞀂' => 230, + '𞀃' => 230, + '𞀄' => 230, + '𞀅' => 230, + '𞀆' => 230, + '𞀈' => 230, + '𞀉' => 230, + '𞀊' => 230, + '𞀋' => 230, + '𞀌' => 230, + '𞀍' => 230, + '𞀎' => 230, + '𞀏' => 230, + '𞀐' => 230, + '𞀑' => 230, + '𞀒' => 230, + '𞀓' => 230, + '𞀔' => 230, + '𞀕' => 230, + '𞀖' => 230, + '𞀗' => 230, + '𞀘' => 230, + '𞀛' => 230, + '𞀜' => 230, + '𞀝' => 230, + '𞀞' => 230, + '𞀟' => 230, + '𞀠' => 230, + '𞀡' => 230, + '𞀣' => 230, + '𞀤' => 230, + '𞀦' => 230, + '𞀧' => 230, + '𞀨' => 230, + '𞀩' => 230, + '𞀪' => 230, + '𞄰' => 230, + '𞄱' => 230, + '𞄲' => 230, + '𞄳' => 230, + '𞄴' => 230, + '𞄵' => 230, + '𞄶' => 230, + '𞋬' => 230, + '𞋭' => 230, + '𞋮' => 230, + '𞋯' => 230, + '𞣐' => 220, + '𞣑' => 220, + '𞣒' => 220, + '𞣓' => 220, + '𞣔' => 220, + '𞣕' => 220, + '𞣖' => 220, + '𞥄' => 230, + '𞥅' => 230, + '𞥆' => 230, + '𞥇' => 230, + '𞥈' => 230, + '𞥉' => 230, + '𞥊' => 7, +); diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php new file mode 100644 index 0000000..1574902 --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php @@ -0,0 +1,3695 @@ + ' ', + '¨' => ' ̈', + 'ª' => 'a', + '¯' => ' ̄', + '²' => '2', + '³' => '3', + '´' => ' ́', + 'µ' => 'μ', + '¸' => ' ̧', + '¹' => '1', + 'º' => 'o', + '¼' => '1⁄4', + '½' => '1⁄2', + '¾' => '3⁄4', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ŀ' => 'L·', + 'ŀ' => 'l·', + 'ʼn' => 'ʼn', + 'ſ' => 's', + 'DŽ' => 'DŽ', + 'Dž' => 'Dž', + 'dž' => 'dž', + 'LJ' => 'LJ', + 'Lj' => 'Lj', + 'lj' => 'lj', + 'NJ' => 'NJ', + 'Nj' => 'Nj', + 'nj' => 'nj', + 'DZ' => 'DZ', + 'Dz' => 'Dz', + 'dz' => 'dz', + 'ʰ' => 'h', + 'ʱ' => 'ɦ', + 'ʲ' => 'j', + 'ʳ' => 'r', + 'ʴ' => 'ɹ', + 'ʵ' => 'ɻ', + 'ʶ' => 'ʁ', + 'ʷ' => 'w', + 'ʸ' => 'y', + '˘' => ' ̆', + '˙' => ' ̇', + '˚' => ' ̊', + '˛' => ' ̨', + '˜' => ' ̃', + '˝' => ' ̋', + 'ˠ' => 'ɣ', + 'ˡ' => 'l', + 'ˢ' => 's', + 'ˣ' => 'x', + 'ˤ' => 'ʕ', + 'ͺ' => ' ͅ', + '΄' => ' ́', + '΅' => ' ̈́', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϒ' => 'Υ', + 'ϓ' => 'Ύ', + 'ϔ' => 'Ϋ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϲ' => 'ς', + 'ϴ' => 'Θ', + 'ϵ' => 'ε', + 'Ϲ' => 'Σ', + 'և' => 'եւ', + 'ٵ' => 'اٴ', + 'ٶ' => 'وٴ', + 'ٷ' => 'ۇٴ', + 'ٸ' => 'يٴ', + 'ำ' => 'ํา', + 'ຳ' => 'ໍາ', + 'ໜ' => 'ຫນ', + 'ໝ' => 'ຫມ', + '༌' => '་', + 'ཷ' => 'ྲཱྀ', + 'ཹ' => 'ླཱྀ', + 'ჼ' => 'ნ', + 'ᴬ' => 'A', + 'ᴭ' => 'Æ', + 'ᴮ' => 'B', + 'ᴰ' => 'D', + 'ᴱ' => 'E', + 'ᴲ' => 'Ǝ', + 'ᴳ' => 'G', + 'ᴴ' => 'H', + 'ᴵ' => 'I', + 'ᴶ' => 'J', + 'ᴷ' => 'K', + 'ᴸ' => 'L', + 'ᴹ' => 'M', + 'ᴺ' => 'N', + 'ᴼ' => 'O', + 'ᴽ' => 'Ȣ', + 'ᴾ' => 'P', + 'ᴿ' => 'R', + 'ᵀ' => 'T', + 'ᵁ' => 'U', + 'ᵂ' => 'W', + 'ᵃ' => 'a', + 'ᵄ' => 'ɐ', + 'ᵅ' => 'ɑ', + 'ᵆ' => 'ᴂ', + 'ᵇ' => 'b', + 'ᵈ' => 'd', + 'ᵉ' => 'e', + 'ᵊ' => 'ə', + 'ᵋ' => 'ɛ', + 'ᵌ' => 'ɜ', + 'ᵍ' => 'g', + 'ᵏ' => 'k', + 'ᵐ' => 'm', + 'ᵑ' => 'ŋ', + 'ᵒ' => 'o', + 'ᵓ' => 'ɔ', + 'ᵔ' => 'ᴖ', + 'ᵕ' => 'ᴗ', + 'ᵖ' => 'p', + 'ᵗ' => 't', + 'ᵘ' => 'u', + 'ᵙ' => 'ᴝ', + 'ᵚ' => 'ɯ', + 'ᵛ' => 'v', + 'ᵜ' => 'ᴥ', + 'ᵝ' => 'β', + 'ᵞ' => 'γ', + 'ᵟ' => 'δ', + 'ᵠ' => 'φ', + 'ᵡ' => 'χ', + 'ᵢ' => 'i', + 'ᵣ' => 'r', + 'ᵤ' => 'u', + 'ᵥ' => 'v', + 'ᵦ' => 'β', + 'ᵧ' => 'γ', + 'ᵨ' => 'ρ', + 'ᵩ' => 'φ', + 'ᵪ' => 'χ', + 'ᵸ' => 'н', + 'ᶛ' => 'ɒ', + 'ᶜ' => 'c', + 'ᶝ' => 'ɕ', + 'ᶞ' => 'ð', + 'ᶟ' => 'ɜ', + 'ᶠ' => 'f', + 'ᶡ' => 'ɟ', + 'ᶢ' => 'ɡ', + 'ᶣ' => 'ɥ', + 'ᶤ' => 'ɨ', + 'ᶥ' => 'ɩ', + 'ᶦ' => 'ɪ', + 'ᶧ' => 'ᵻ', + 'ᶨ' => 'ʝ', + 'ᶩ' => 'ɭ', + 'ᶪ' => 'ᶅ', + 'ᶫ' => 'ʟ', + 'ᶬ' => 'ɱ', + 'ᶭ' => 'ɰ', + 'ᶮ' => 'ɲ', + 'ᶯ' => 'ɳ', + 'ᶰ' => 'ɴ', + 'ᶱ' => 'ɵ', + 'ᶲ' => 'ɸ', + 'ᶳ' => 'ʂ', + 'ᶴ' => 'ʃ', + 'ᶵ' => 'ƫ', + 'ᶶ' => 'ʉ', + 'ᶷ' => 'ʊ', + 'ᶸ' => 'ᴜ', + 'ᶹ' => 'ʋ', + 'ᶺ' => 'ʌ', + 'ᶻ' => 'z', + 'ᶼ' => 'ʐ', + 'ᶽ' => 'ʑ', + 'ᶾ' => 'ʒ', + 'ᶿ' => 'θ', + 'ẚ' => 'aʾ', + 'ẛ' => 'ṡ', + '᾽' => ' ̓', + '᾿' => ' ̓', + '῀' => ' ͂', + '῁' => ' ̈͂', + '῍' => ' ̓̀', + '῎' => ' ̓́', + '῏' => ' ̓͂', + '῝' => ' ̔̀', + '῞' => ' ̔́', + '῟' => ' ̔͂', + '῭' => ' ̈̀', + '΅' => ' ̈́', + '´' => ' ́', + '῾' => ' ̔', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + '‑' => '‐', + '‗' => ' ̳', + '․' => '.', + '‥' => '..', + '…' => '...', + ' ' => ' ', + '″' => '′′', + '‴' => '′′′', + '‶' => '‵‵', + '‷' => '‵‵‵', + '‼' => '!!', + '‾' => ' ̅', + '⁇' => '??', + '⁈' => '?!', + '⁉' => '!?', + '⁗' => '′′′′', + ' ' => ' ', + '⁰' => '0', + 'ⁱ' => 'i', + '⁴' => '4', + '⁵' => '5', + '⁶' => '6', + '⁷' => '7', + '⁸' => '8', + '⁹' => '9', + '⁺' => '+', + '⁻' => '−', + '⁼' => '=', + '⁽' => '(', + '⁾' => ')', + 'ⁿ' => 'n', + '₀' => '0', + '₁' => '1', + '₂' => '2', + '₃' => '3', + '₄' => '4', + '₅' => '5', + '₆' => '6', + '₇' => '7', + '₈' => '8', + '₉' => '9', + '₊' => '+', + '₋' => '−', + '₌' => '=', + '₍' => '(', + '₎' => ')', + 'ₐ' => 'a', + 'ₑ' => 'e', + 'ₒ' => 'o', + 'ₓ' => 'x', + 'ₔ' => 'ə', + 'ₕ' => 'h', + 'ₖ' => 'k', + 'ₗ' => 'l', + 'ₘ' => 'm', + 'ₙ' => 'n', + 'ₚ' => 'p', + 'ₛ' => 's', + 'ₜ' => 't', + '₨' => 'Rs', + '℀' => 'a/c', + '℁' => 'a/s', + 'ℂ' => 'C', + '℃' => '°C', + '℅' => 'c/o', + '℆' => 'c/u', + 'ℇ' => 'Ɛ', + '℉' => '°F', + 'ℊ' => 'g', + 'ℋ' => 'H', + 'ℌ' => 'H', + 'ℍ' => 'H', + 'ℎ' => 'h', + 'ℏ' => 'ħ', + 'ℐ' => 'I', + 'ℑ' => 'I', + 'ℒ' => 'L', + 'ℓ' => 'l', + 'ℕ' => 'N', + '№' => 'No', + 'ℙ' => 'P', + 'ℚ' => 'Q', + 'ℛ' => 'R', + 'ℜ' => 'R', + 'ℝ' => 'R', + '℠' => 'SM', + '℡' => 'TEL', + '™' => 'TM', + 'ℤ' => 'Z', + 'ℨ' => 'Z', + 'ℬ' => 'B', + 'ℭ' => 'C', + 'ℯ' => 'e', + 'ℰ' => 'E', + 'ℱ' => 'F', + 'ℳ' => 'M', + 'ℴ' => 'o', + 'ℵ' => 'א', + 'ℶ' => 'ב', + 'ℷ' => 'ג', + 'ℸ' => 'ד', + 'ℹ' => 'i', + '℻' => 'FAX', + 'ℼ' => 'π', + 'ℽ' => 'γ', + 'ℾ' => 'Γ', + 'ℿ' => 'Π', + '⅀' => '∑', + 'ⅅ' => 'D', + 'ⅆ' => 'd', + 'ⅇ' => 'e', + 'ⅈ' => 'i', + 'ⅉ' => 'j', + '⅐' => '1⁄7', + '⅑' => '1⁄9', + '⅒' => '1⁄10', + '⅓' => '1⁄3', + '⅔' => '2⁄3', + '⅕' => '1⁄5', + '⅖' => '2⁄5', + '⅗' => '3⁄5', + '⅘' => '4⁄5', + '⅙' => '1⁄6', + '⅚' => '5⁄6', + '⅛' => '1⁄8', + '⅜' => '3⁄8', + '⅝' => '5⁄8', + '⅞' => '7⁄8', + '⅟' => '1⁄', + 'Ⅰ' => 'I', + 'Ⅱ' => 'II', + 'Ⅲ' => 'III', + 'Ⅳ' => 'IV', + 'Ⅴ' => 'V', + 'Ⅵ' => 'VI', + 'Ⅶ' => 'VII', + 'Ⅷ' => 'VIII', + 'Ⅸ' => 'IX', + 'Ⅹ' => 'X', + 'Ⅺ' => 'XI', + 'Ⅻ' => 'XII', + 'Ⅼ' => 'L', + 'Ⅽ' => 'C', + 'Ⅾ' => 'D', + 'Ⅿ' => 'M', + 'ⅰ' => 'i', + 'ⅱ' => 'ii', + 'ⅲ' => 'iii', + 'ⅳ' => 'iv', + 'ⅴ' => 'v', + 'ⅵ' => 'vi', + 'ⅶ' => 'vii', + 'ⅷ' => 'viii', + 'ⅸ' => 'ix', + 'ⅹ' => 'x', + 'ⅺ' => 'xi', + 'ⅻ' => 'xii', + 'ⅼ' => 'l', + 'ⅽ' => 'c', + 'ⅾ' => 'd', + 'ⅿ' => 'm', + '↉' => '0⁄3', + '∬' => '∫∫', + '∭' => '∫∫∫', + '∯' => '∮∮', + '∰' => '∮∮∮', + '①' => '1', + '②' => '2', + '③' => '3', + '④' => '4', + '⑤' => '5', + '⑥' => '6', + '⑦' => '7', + '⑧' => '8', + '⑨' => '9', + '⑩' => '10', + '⑪' => '11', + '⑫' => '12', + '⑬' => '13', + '⑭' => '14', + '⑮' => '15', + '⑯' => '16', + '⑰' => '17', + '⑱' => '18', + '⑲' => '19', + '⑳' => '20', + '⑴' => '(1)', + '⑵' => '(2)', + '⑶' => '(3)', + '⑷' => '(4)', + '⑸' => '(5)', + '⑹' => '(6)', + '⑺' => '(7)', + '⑻' => '(8)', + '⑼' => '(9)', + '⑽' => '(10)', + '⑾' => '(11)', + '⑿' => '(12)', + '⒀' => '(13)', + '⒁' => '(14)', + '⒂' => '(15)', + '⒃' => '(16)', + '⒄' => '(17)', + '⒅' => '(18)', + '⒆' => '(19)', + '⒇' => '(20)', + '⒈' => '1.', + '⒉' => '2.', + '⒊' => '3.', + '⒋' => '4.', + '⒌' => '5.', + '⒍' => '6.', + '⒎' => '7.', + '⒏' => '8.', + '⒐' => '9.', + '⒑' => '10.', + '⒒' => '11.', + '⒓' => '12.', + '⒔' => '13.', + '⒕' => '14.', + '⒖' => '15.', + '⒗' => '16.', + '⒘' => '17.', + '⒙' => '18.', + '⒚' => '19.', + '⒛' => '20.', + '⒜' => '(a)', + '⒝' => '(b)', + '⒞' => '(c)', + '⒟' => '(d)', + '⒠' => '(e)', + '⒡' => '(f)', + '⒢' => '(g)', + '⒣' => '(h)', + '⒤' => '(i)', + '⒥' => '(j)', + '⒦' => '(k)', + '⒧' => '(l)', + '⒨' => '(m)', + '⒩' => '(n)', + '⒪' => '(o)', + '⒫' => '(p)', + '⒬' => '(q)', + '⒭' => '(r)', + '⒮' => '(s)', + '⒯' => '(t)', + '⒰' => '(u)', + '⒱' => '(v)', + '⒲' => '(w)', + '⒳' => '(x)', + '⒴' => '(y)', + '⒵' => '(z)', + 'Ⓐ' => 'A', + 'Ⓑ' => 'B', + 'Ⓒ' => 'C', + 'Ⓓ' => 'D', + 'Ⓔ' => 'E', + 'Ⓕ' => 'F', + 'Ⓖ' => 'G', + 'Ⓗ' => 'H', + 'Ⓘ' => 'I', + 'Ⓙ' => 'J', + 'Ⓚ' => 'K', + 'Ⓛ' => 'L', + 'Ⓜ' => 'M', + 'Ⓝ' => 'N', + 'Ⓞ' => 'O', + 'Ⓟ' => 'P', + 'Ⓠ' => 'Q', + 'Ⓡ' => 'R', + 'Ⓢ' => 'S', + 'Ⓣ' => 'T', + 'Ⓤ' => 'U', + 'Ⓥ' => 'V', + 'Ⓦ' => 'W', + 'Ⓧ' => 'X', + 'Ⓨ' => 'Y', + 'Ⓩ' => 'Z', + 'ⓐ' => 'a', + 'ⓑ' => 'b', + 'ⓒ' => 'c', + 'ⓓ' => 'd', + 'ⓔ' => 'e', + 'ⓕ' => 'f', + 'ⓖ' => 'g', + 'ⓗ' => 'h', + 'ⓘ' => 'i', + 'ⓙ' => 'j', + 'ⓚ' => 'k', + 'ⓛ' => 'l', + 'ⓜ' => 'm', + 'ⓝ' => 'n', + 'ⓞ' => 'o', + 'ⓟ' => 'p', + 'ⓠ' => 'q', + 'ⓡ' => 'r', + 'ⓢ' => 's', + 'ⓣ' => 't', + 'ⓤ' => 'u', + 'ⓥ' => 'v', + 'ⓦ' => 'w', + 'ⓧ' => 'x', + 'ⓨ' => 'y', + 'ⓩ' => 'z', + '⓪' => '0', + '⨌' => '∫∫∫∫', + '⩴' => '::=', + '⩵' => '==', + '⩶' => '===', + 'ⱼ' => 'j', + 'ⱽ' => 'V', + 'ⵯ' => 'ⵡ', + '⺟' => '母', + '⻳' => '龟', + '⼀' => '一', + '⼁' => '丨', + '⼂' => '丶', + '⼃' => '丿', + '⼄' => '乙', + '⼅' => '亅', + '⼆' => '二', + '⼇' => '亠', + '⼈' => '人', + '⼉' => '儿', + '⼊' => '入', + '⼋' => '八', + '⼌' => '冂', + '⼍' => '冖', + '⼎' => '冫', + '⼏' => '几', + '⼐' => '凵', + '⼑' => '刀', + '⼒' => '力', + '⼓' => '勹', + '⼔' => '匕', + '⼕' => '匚', + '⼖' => '匸', + '⼗' => '十', + '⼘' => '卜', + '⼙' => '卩', + '⼚' => '厂', + '⼛' => '厶', + '⼜' => '又', + '⼝' => '口', + '⼞' => '囗', + '⼟' => '土', + '⼠' => '士', + '⼡' => '夂', + '⼢' => '夊', + '⼣' => '夕', + '⼤' => '大', + '⼥' => '女', + '⼦' => '子', + '⼧' => '宀', + '⼨' => '寸', + '⼩' => '小', + '⼪' => '尢', + '⼫' => '尸', + '⼬' => '屮', + '⼭' => '山', + '⼮' => '巛', + '⼯' => '工', + '⼰' => '己', + '⼱' => '巾', + '⼲' => '干', + '⼳' => '幺', + '⼴' => '广', + '⼵' => '廴', + '⼶' => '廾', + '⼷' => '弋', + '⼸' => '弓', + '⼹' => '彐', + '⼺' => '彡', + '⼻' => '彳', + '⼼' => '心', + '⼽' => '戈', + '⼾' => '戶', + '⼿' => '手', + '⽀' => '支', + '⽁' => '攴', + '⽂' => '文', + '⽃' => '斗', + '⽄' => '斤', + '⽅' => '方', + '⽆' => '无', + '⽇' => '日', + '⽈' => '曰', + '⽉' => '月', + '⽊' => '木', + '⽋' => '欠', + '⽌' => '止', + '⽍' => '歹', + '⽎' => '殳', + '⽏' => '毋', + '⽐' => '比', + '⽑' => '毛', + '⽒' => '氏', + '⽓' => '气', + '⽔' => '水', + '⽕' => '火', + '⽖' => '爪', + '⽗' => '父', + '⽘' => '爻', + '⽙' => '爿', + '⽚' => '片', + '⽛' => '牙', + '⽜' => '牛', + '⽝' => '犬', + '⽞' => '玄', + '⽟' => '玉', + '⽠' => '瓜', + '⽡' => '瓦', + '⽢' => '甘', + '⽣' => '生', + '⽤' => '用', + '⽥' => '田', + '⽦' => '疋', + '⽧' => '疒', + '⽨' => '癶', + '⽩' => '白', + '⽪' => '皮', + '⽫' => '皿', + '⽬' => '目', + '⽭' => '矛', + '⽮' => '矢', + '⽯' => '石', + '⽰' => '示', + '⽱' => '禸', + '⽲' => '禾', + '⽳' => '穴', + '⽴' => '立', + '⽵' => '竹', + '⽶' => '米', + '⽷' => '糸', + '⽸' => '缶', + '⽹' => '网', + '⽺' => '羊', + '⽻' => '羽', + '⽼' => '老', + '⽽' => '而', + '⽾' => '耒', + '⽿' => '耳', + '⾀' => '聿', + '⾁' => '肉', + '⾂' => '臣', + '⾃' => '自', + '⾄' => '至', + '⾅' => '臼', + '⾆' => '舌', + '⾇' => '舛', + '⾈' => '舟', + '⾉' => '艮', + '⾊' => '色', + '⾋' => '艸', + '⾌' => '虍', + '⾍' => '虫', + '⾎' => '血', + '⾏' => '行', + '⾐' => '衣', + '⾑' => '襾', + '⾒' => '見', + '⾓' => '角', + '⾔' => '言', + '⾕' => '谷', + '⾖' => '豆', + '⾗' => '豕', + '⾘' => '豸', + '⾙' => '貝', + '⾚' => '赤', + '⾛' => '走', + '⾜' => '足', + '⾝' => '身', + '⾞' => '車', + '⾟' => '辛', + '⾠' => '辰', + '⾡' => '辵', + '⾢' => '邑', + '⾣' => '酉', + '⾤' => '釆', + '⾥' => '里', + '⾦' => '金', + '⾧' => '長', + '⾨' => '門', + '⾩' => '阜', + '⾪' => '隶', + '⾫' => '隹', + '⾬' => '雨', + '⾭' => '靑', + '⾮' => '非', + '⾯' => '面', + '⾰' => '革', + '⾱' => '韋', + '⾲' => '韭', + '⾳' => '音', + '⾴' => '頁', + '⾵' => '風', + '⾶' => '飛', + '⾷' => '食', + '⾸' => '首', + '⾹' => '香', + '⾺' => '馬', + '⾻' => '骨', + '⾼' => '高', + '⾽' => '髟', + '⾾' => '鬥', + '⾿' => '鬯', + '⿀' => '鬲', + '⿁' => '鬼', + '⿂' => '魚', + '⿃' => '鳥', + '⿄' => '鹵', + '⿅' => '鹿', + '⿆' => '麥', + '⿇' => '麻', + '⿈' => '黃', + '⿉' => '黍', + '⿊' => '黑', + '⿋' => '黹', + '⿌' => '黽', + '⿍' => '鼎', + '⿎' => '鼓', + '⿏' => '鼠', + '⿐' => '鼻', + '⿑' => '齊', + '⿒' => '齒', + '⿓' => '龍', + '⿔' => '龜', + '⿕' => '龠', + ' ' => ' ', + '〶' => '〒', + '〸' => '十', + '〹' => '卄', + '〺' => '卅', + '゛' => ' ゙', + '゜' => ' ゚', + 'ゟ' => 'より', + 'ヿ' => 'コト', + 'ㄱ' => 'ᄀ', + 'ㄲ' => 'ᄁ', + 'ㄳ' => 'ᆪ', + 'ㄴ' => 'ᄂ', + 'ㄵ' => 'ᆬ', + 'ㄶ' => 'ᆭ', + 'ㄷ' => 'ᄃ', + 'ㄸ' => 'ᄄ', + 'ㄹ' => 'ᄅ', + 'ㄺ' => 'ᆰ', + 'ㄻ' => 'ᆱ', + 'ㄼ' => 'ᆲ', + 'ㄽ' => 'ᆳ', + 'ㄾ' => 'ᆴ', + 'ㄿ' => 'ᆵ', + 'ㅀ' => 'ᄚ', + 'ㅁ' => 'ᄆ', + 'ㅂ' => 'ᄇ', + 'ㅃ' => 'ᄈ', + 'ㅄ' => 'ᄡ', + 'ㅅ' => 'ᄉ', + 'ㅆ' => 'ᄊ', + 'ㅇ' => 'ᄋ', + 'ㅈ' => 'ᄌ', + 'ㅉ' => 'ᄍ', + 'ㅊ' => 'ᄎ', + 'ㅋ' => 'ᄏ', + 'ㅌ' => 'ᄐ', + 'ㅍ' => 'ᄑ', + 'ㅎ' => 'ᄒ', + 'ㅏ' => 'ᅡ', + 'ㅐ' => 'ᅢ', + 'ㅑ' => 'ᅣ', + 'ㅒ' => 'ᅤ', + 'ㅓ' => 'ᅥ', + 'ㅔ' => 'ᅦ', + 'ㅕ' => 'ᅧ', + 'ㅖ' => 'ᅨ', + 'ㅗ' => 'ᅩ', + 'ㅘ' => 'ᅪ', + 'ㅙ' => 'ᅫ', + 'ㅚ' => 'ᅬ', + 'ㅛ' => 'ᅭ', + 'ㅜ' => 'ᅮ', + 'ㅝ' => 'ᅯ', + 'ㅞ' => 'ᅰ', + 'ㅟ' => 'ᅱ', + 'ㅠ' => 'ᅲ', + 'ㅡ' => 'ᅳ', + 'ㅢ' => 'ᅴ', + 'ㅣ' => 'ᅵ', + 'ㅤ' => 'ᅠ', + 'ㅥ' => 'ᄔ', + 'ㅦ' => 'ᄕ', + 'ㅧ' => 'ᇇ', + 'ㅨ' => 'ᇈ', + 'ㅩ' => 'ᇌ', + 'ㅪ' => 'ᇎ', + 'ㅫ' => 'ᇓ', + 'ㅬ' => 'ᇗ', + 'ㅭ' => 'ᇙ', + 'ㅮ' => 'ᄜ', + 'ㅯ' => 'ᇝ', + 'ㅰ' => 'ᇟ', + 'ㅱ' => 'ᄝ', + 'ㅲ' => 'ᄞ', + 'ㅳ' => 'ᄠ', + 'ㅴ' => 'ᄢ', + 'ㅵ' => 'ᄣ', + 'ㅶ' => 'ᄧ', + 'ㅷ' => 'ᄩ', + 'ㅸ' => 'ᄫ', + 'ㅹ' => 'ᄬ', + 'ㅺ' => 'ᄭ', + 'ㅻ' => 'ᄮ', + 'ㅼ' => 'ᄯ', + 'ㅽ' => 'ᄲ', + 'ㅾ' => 'ᄶ', + 'ㅿ' => 'ᅀ', + 'ㆀ' => 'ᅇ', + 'ㆁ' => 'ᅌ', + 'ㆂ' => 'ᇱ', + 'ㆃ' => 'ᇲ', + 'ㆄ' => 'ᅗ', + 'ㆅ' => 'ᅘ', + 'ㆆ' => 'ᅙ', + 'ㆇ' => 'ᆄ', + 'ㆈ' => 'ᆅ', + 'ㆉ' => 'ᆈ', + 'ㆊ' => 'ᆑ', + 'ㆋ' => 'ᆒ', + 'ㆌ' => 'ᆔ', + 'ㆍ' => 'ᆞ', + 'ㆎ' => 'ᆡ', + '㆒' => '一', + '㆓' => '二', + '㆔' => '三', + '㆕' => '四', + '㆖' => '上', + '㆗' => '中', + '㆘' => '下', + '㆙' => '甲', + '㆚' => '乙', + '㆛' => '丙', + '㆜' => '丁', + '㆝' => '天', + '㆞' => '地', + '㆟' => '人', + '㈀' => '(ᄀ)', + '㈁' => '(ᄂ)', + '㈂' => '(ᄃ)', + '㈃' => '(ᄅ)', + '㈄' => '(ᄆ)', + '㈅' => '(ᄇ)', + '㈆' => '(ᄉ)', + '㈇' => '(ᄋ)', + '㈈' => '(ᄌ)', + '㈉' => '(ᄎ)', + '㈊' => '(ᄏ)', + '㈋' => '(ᄐ)', + '㈌' => '(ᄑ)', + '㈍' => '(ᄒ)', + '㈎' => '(가)', + '㈏' => '(나)', + '㈐' => '(다)', + '㈑' => '(라)', + '㈒' => '(마)', + '㈓' => '(바)', + '㈔' => '(사)', + '㈕' => '(아)', + '㈖' => '(자)', + '㈗' => '(차)', + '㈘' => '(카)', + '㈙' => '(타)', + '㈚' => '(파)', + '㈛' => '(하)', + '㈜' => '(주)', + '㈝' => '(오전)', + '㈞' => '(오후)', + '㈠' => '(一)', + '㈡' => '(二)', + '㈢' => '(三)', + '㈣' => '(四)', + '㈤' => '(五)', + '㈥' => '(六)', + '㈦' => '(七)', + '㈧' => '(八)', + '㈨' => '(九)', + '㈩' => '(十)', + '㈪' => '(月)', + '㈫' => '(火)', + '㈬' => '(水)', + '㈭' => '(木)', + '㈮' => '(金)', + '㈯' => '(土)', + '㈰' => '(日)', + '㈱' => '(株)', + '㈲' => '(有)', + '㈳' => '(社)', + '㈴' => '(名)', + '㈵' => '(特)', + '㈶' => '(財)', + '㈷' => '(祝)', + '㈸' => '(労)', + '㈹' => '(代)', + '㈺' => '(呼)', + '㈻' => '(学)', + '㈼' => '(監)', + '㈽' => '(企)', + '㈾' => '(資)', + '㈿' => '(協)', + '㉀' => '(祭)', + '㉁' => '(休)', + '㉂' => '(自)', + '㉃' => '(至)', + '㉄' => '問', + '㉅' => '幼', + '㉆' => '文', + '㉇' => '箏', + '㉐' => 'PTE', + '㉑' => '21', + '㉒' => '22', + '㉓' => '23', + '㉔' => '24', + '㉕' => '25', + '㉖' => '26', + '㉗' => '27', + '㉘' => '28', + '㉙' => '29', + '㉚' => '30', + '㉛' => '31', + '㉜' => '32', + '㉝' => '33', + '㉞' => '34', + '㉟' => '35', + '㉠' => 'ᄀ', + '㉡' => 'ᄂ', + '㉢' => 'ᄃ', + '㉣' => 'ᄅ', + '㉤' => 'ᄆ', + '㉥' => 'ᄇ', + '㉦' => 'ᄉ', + '㉧' => 'ᄋ', + '㉨' => 'ᄌ', + '㉩' => 'ᄎ', + '㉪' => 'ᄏ', + '㉫' => 'ᄐ', + '㉬' => 'ᄑ', + '㉭' => 'ᄒ', + '㉮' => '가', + '㉯' => '나', + '㉰' => '다', + '㉱' => '라', + '㉲' => '마', + '㉳' => '바', + '㉴' => '사', + '㉵' => '아', + '㉶' => '자', + '㉷' => '차', + '㉸' => '카', + '㉹' => '타', + '㉺' => '파', + '㉻' => '하', + '㉼' => '참고', + '㉽' => '주의', + '㉾' => '우', + '㊀' => '一', + '㊁' => '二', + '㊂' => '三', + '㊃' => '四', + '㊄' => '五', + '㊅' => '六', + '㊆' => '七', + '㊇' => '八', + '㊈' => '九', + '㊉' => '十', + '㊊' => '月', + '㊋' => '火', + '㊌' => '水', + '㊍' => '木', + '㊎' => '金', + '㊏' => '土', + '㊐' => '日', + '㊑' => '株', + '㊒' => '有', + '㊓' => '社', + '㊔' => '名', + '㊕' => '特', + '㊖' => '財', + '㊗' => '祝', + '㊘' => '労', + '㊙' => '秘', + '㊚' => '男', + '㊛' => '女', + '㊜' => '適', + '㊝' => '優', + '㊞' => '印', + '㊟' => '注', + '㊠' => '項', + '㊡' => '休', + '㊢' => '写', + '㊣' => '正', + '㊤' => '上', + '㊥' => '中', + '㊦' => '下', + '㊧' => '左', + '㊨' => '右', + '㊩' => '医', + '㊪' => '宗', + '㊫' => '学', + '㊬' => '監', + '㊭' => '企', + '㊮' => '資', + '㊯' => '協', + '㊰' => '夜', + '㊱' => '36', + '㊲' => '37', + '㊳' => '38', + '㊴' => '39', + '㊵' => '40', + '㊶' => '41', + '㊷' => '42', + '㊸' => '43', + '㊹' => '44', + '㊺' => '45', + '㊻' => '46', + '㊼' => '47', + '㊽' => '48', + '㊾' => '49', + '㊿' => '50', + '㋀' => '1月', + '㋁' => '2月', + '㋂' => '3月', + '㋃' => '4月', + '㋄' => '5月', + '㋅' => '6月', + '㋆' => '7月', + '㋇' => '8月', + '㋈' => '9月', + '㋉' => '10月', + '㋊' => '11月', + '㋋' => '12月', + '㋌' => 'Hg', + '㋍' => 'erg', + '㋎' => 'eV', + '㋏' => 'LTD', + '㋐' => 'ア', + '㋑' => 'イ', + '㋒' => 'ウ', + '㋓' => 'エ', + '㋔' => 'オ', + '㋕' => 'カ', + '㋖' => 'キ', + '㋗' => 'ク', + '㋘' => 'ケ', + '㋙' => 'コ', + '㋚' => 'サ', + '㋛' => 'シ', + '㋜' => 'ス', + '㋝' => 'セ', + '㋞' => 'ソ', + '㋟' => 'タ', + '㋠' => 'チ', + '㋡' => 'ツ', + '㋢' => 'テ', + '㋣' => 'ト', + '㋤' => 'ナ', + '㋥' => 'ニ', + '㋦' => 'ヌ', + '㋧' => 'ネ', + '㋨' => 'ノ', + '㋩' => 'ハ', + '㋪' => 'ヒ', + '㋫' => 'フ', + '㋬' => 'ヘ', + '㋭' => 'ホ', + '㋮' => 'マ', + '㋯' => 'ミ', + '㋰' => 'ム', + '㋱' => 'メ', + '㋲' => 'モ', + '㋳' => 'ヤ', + '㋴' => 'ユ', + '㋵' => 'ヨ', + '㋶' => 'ラ', + '㋷' => 'リ', + '㋸' => 'ル', + '㋹' => 'レ', + '㋺' => 'ロ', + '㋻' => 'ワ', + '㋼' => 'ヰ', + '㋽' => 'ヱ', + '㋾' => 'ヲ', + '㋿' => '令和', + '㌀' => 'アパート', + '㌁' => 'アルファ', + '㌂' => 'アンペア', + '㌃' => 'アール', + '㌄' => 'イニング', + '㌅' => 'インチ', + '㌆' => 'ウォン', + '㌇' => 'エスクード', + '㌈' => 'エーカー', + '㌉' => 'オンス', + '㌊' => 'オーム', + '㌋' => 'カイリ', + '㌌' => 'カラット', + '㌍' => 'カロリー', + '㌎' => 'ガロン', + '㌏' => 'ガンマ', + '㌐' => 'ギガ', + '㌑' => 'ギニー', + '㌒' => 'キュリー', + '㌓' => 'ギルダー', + '㌔' => 'キロ', + '㌕' => 'キログラム', + '㌖' => 'キロメートル', + '㌗' => 'キロワット', + '㌘' => 'グラム', + '㌙' => 'グラムトン', + '㌚' => 'クルゼイロ', + '㌛' => 'クローネ', + '㌜' => 'ケース', + '㌝' => 'コルナ', + '㌞' => 'コーポ', + '㌟' => 'サイクル', + '㌠' => 'サンチーム', + '㌡' => 'シリング', + '㌢' => 'センチ', + '㌣' => 'セント', + '㌤' => 'ダース', + '㌥' => 'デシ', + '㌦' => 'ドル', + '㌧' => 'トン', + '㌨' => 'ナノ', + '㌩' => 'ノット', + '㌪' => 'ハイツ', + '㌫' => 'パーセント', + '㌬' => 'パーツ', + '㌭' => 'バーレル', + '㌮' => 'ピアストル', + '㌯' => 'ピクル', + '㌰' => 'ピコ', + '㌱' => 'ビル', + '㌲' => 'ファラッド', + '㌳' => 'フィート', + '㌴' => 'ブッシェル', + '㌵' => 'フラン', + '㌶' => 'ヘクタール', + '㌷' => 'ペソ', + '㌸' => 'ペニヒ', + '㌹' => 'ヘルツ', + '㌺' => 'ペンス', + '㌻' => 'ページ', + '㌼' => 'ベータ', + '㌽' => 'ポイント', + '㌾' => 'ボルト', + '㌿' => 'ホン', + '㍀' => 'ポンド', + '㍁' => 'ホール', + '㍂' => 'ホーン', + '㍃' => 'マイクロ', + '㍄' => 'マイル', + '㍅' => 'マッハ', + '㍆' => 'マルク', + '㍇' => 'マンション', + '㍈' => 'ミクロン', + '㍉' => 'ミリ', + '㍊' => 'ミリバール', + '㍋' => 'メガ', + '㍌' => 'メガトン', + '㍍' => 'メートル', + '㍎' => 'ヤード', + '㍏' => 'ヤール', + '㍐' => 'ユアン', + '㍑' => 'リットル', + '㍒' => 'リラ', + '㍓' => 'ルピー', + '㍔' => 'ルーブル', + '㍕' => 'レム', + '㍖' => 'レントゲン', + '㍗' => 'ワット', + '㍘' => '0点', + '㍙' => '1点', + '㍚' => '2点', + '㍛' => '3点', + '㍜' => '4点', + '㍝' => '5点', + '㍞' => '6点', + '㍟' => '7点', + '㍠' => '8点', + '㍡' => '9点', + '㍢' => '10点', + '㍣' => '11点', + '㍤' => '12点', + '㍥' => '13点', + '㍦' => '14点', + '㍧' => '15点', + '㍨' => '16点', + '㍩' => '17点', + '㍪' => '18点', + '㍫' => '19点', + '㍬' => '20点', + '㍭' => '21点', + '㍮' => '22点', + '㍯' => '23点', + '㍰' => '24点', + '㍱' => 'hPa', + '㍲' => 'da', + '㍳' => 'AU', + '㍴' => 'bar', + '㍵' => 'oV', + '㍶' => 'pc', + '㍷' => 'dm', + '㍸' => 'dm2', + '㍹' => 'dm3', + '㍺' => 'IU', + '㍻' => '平成', + '㍼' => '昭和', + '㍽' => '大正', + '㍾' => '明治', + '㍿' => '株式会社', + '㎀' => 'pA', + '㎁' => 'nA', + '㎂' => 'μA', + '㎃' => 'mA', + '㎄' => 'kA', + '㎅' => 'KB', + '㎆' => 'MB', + '㎇' => 'GB', + '㎈' => 'cal', + '㎉' => 'kcal', + '㎊' => 'pF', + '㎋' => 'nF', + '㎌' => 'μF', + '㎍' => 'μg', + '㎎' => 'mg', + '㎏' => 'kg', + '㎐' => 'Hz', + '㎑' => 'kHz', + '㎒' => 'MHz', + '㎓' => 'GHz', + '㎔' => 'THz', + '㎕' => 'μl', + '㎖' => 'ml', + '㎗' => 'dl', + '㎘' => 'kl', + '㎙' => 'fm', + '㎚' => 'nm', + '㎛' => 'μm', + '㎜' => 'mm', + '㎝' => 'cm', + '㎞' => 'km', + '㎟' => 'mm2', + '㎠' => 'cm2', + '㎡' => 'm2', + '㎢' => 'km2', + '㎣' => 'mm3', + '㎤' => 'cm3', + '㎥' => 'm3', + '㎦' => 'km3', + '㎧' => 'm∕s', + '㎨' => 'm∕s2', + '㎩' => 'Pa', + '㎪' => 'kPa', + '㎫' => 'MPa', + '㎬' => 'GPa', + '㎭' => 'rad', + '㎮' => 'rad∕s', + '㎯' => 'rad∕s2', + '㎰' => 'ps', + '㎱' => 'ns', + '㎲' => 'μs', + '㎳' => 'ms', + '㎴' => 'pV', + '㎵' => 'nV', + '㎶' => 'μV', + '㎷' => 'mV', + '㎸' => 'kV', + '㎹' => 'MV', + '㎺' => 'pW', + '㎻' => 'nW', + '㎼' => 'μW', + '㎽' => 'mW', + '㎾' => 'kW', + '㎿' => 'MW', + '㏀' => 'kΩ', + '㏁' => 'MΩ', + '㏂' => 'a.m.', + '㏃' => 'Bq', + '㏄' => 'cc', + '㏅' => 'cd', + '㏆' => 'C∕kg', + '㏇' => 'Co.', + '㏈' => 'dB', + '㏉' => 'Gy', + '㏊' => 'ha', + '㏋' => 'HP', + '㏌' => 'in', + '㏍' => 'KK', + '㏎' => 'KM', + '㏏' => 'kt', + '㏐' => 'lm', + '㏑' => 'ln', + '㏒' => 'log', + '㏓' => 'lx', + '㏔' => 'mb', + '㏕' => 'mil', + '㏖' => 'mol', + '㏗' => 'PH', + '㏘' => 'p.m.', + '㏙' => 'PPM', + '㏚' => 'PR', + '㏛' => 'sr', + '㏜' => 'Sv', + '㏝' => 'Wb', + '㏞' => 'V∕m', + '㏟' => 'A∕m', + '㏠' => '1日', + '㏡' => '2日', + '㏢' => '3日', + '㏣' => '4日', + '㏤' => '5日', + '㏥' => '6日', + '㏦' => '7日', + '㏧' => '8日', + '㏨' => '9日', + '㏩' => '10日', + '㏪' => '11日', + '㏫' => '12日', + '㏬' => '13日', + '㏭' => '14日', + '㏮' => '15日', + '㏯' => '16日', + '㏰' => '17日', + '㏱' => '18日', + '㏲' => '19日', + '㏳' => '20日', + '㏴' => '21日', + '㏵' => '22日', + '㏶' => '23日', + '㏷' => '24日', + '㏸' => '25日', + '㏹' => '26日', + '㏺' => '27日', + '㏻' => '28日', + '㏼' => '29日', + '㏽' => '30日', + '㏾' => '31日', + '㏿' => 'gal', + 'ꚜ' => 'ъ', + 'ꚝ' => 'ь', + 'ꝰ' => 'ꝯ', + 'ꟸ' => 'Ħ', + 'ꟹ' => 'œ', + 'ꭜ' => 'ꜧ', + 'ꭝ' => 'ꬷ', + 'ꭞ' => 'ɫ', + 'ꭟ' => 'ꭒ', + 'ꭩ' => 'ʍ', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', + 'ﬠ' => 'ע', + 'ﬡ' => 'א', + 'ﬢ' => 'ד', + 'ﬣ' => 'ה', + 'ﬤ' => 'כ', + 'ﬥ' => 'ל', + 'ﬦ' => 'ם', + 'ﬧ' => 'ר', + 'ﬨ' => 'ת', + '﬩' => '+', + 'ﭏ' => 'אל', + 'ﭐ' => 'ٱ', + 'ﭑ' => 'ٱ', + 'ﭒ' => 'ٻ', + 'ﭓ' => 'ٻ', + 'ﭔ' => 'ٻ', + 'ﭕ' => 'ٻ', + 'ﭖ' => 'پ', + 'ﭗ' => 'پ', + 'ﭘ' => 'پ', + 'ﭙ' => 'پ', + 'ﭚ' => 'ڀ', + 'ﭛ' => 'ڀ', + 'ﭜ' => 'ڀ', + 'ﭝ' => 'ڀ', + 'ﭞ' => 'ٺ', + 'ﭟ' => 'ٺ', + 'ﭠ' => 'ٺ', + 'ﭡ' => 'ٺ', + 'ﭢ' => 'ٿ', + 'ﭣ' => 'ٿ', + 'ﭤ' => 'ٿ', + 'ﭥ' => 'ٿ', + 'ﭦ' => 'ٹ', + 'ﭧ' => 'ٹ', + 'ﭨ' => 'ٹ', + 'ﭩ' => 'ٹ', + 'ﭪ' => 'ڤ', + 'ﭫ' => 'ڤ', + 'ﭬ' => 'ڤ', + 'ﭭ' => 'ڤ', + 'ﭮ' => 'ڦ', + 'ﭯ' => 'ڦ', + 'ﭰ' => 'ڦ', + 'ﭱ' => 'ڦ', + 'ﭲ' => 'ڄ', + 'ﭳ' => 'ڄ', + 'ﭴ' => 'ڄ', + 'ﭵ' => 'ڄ', + 'ﭶ' => 'ڃ', + 'ﭷ' => 'ڃ', + 'ﭸ' => 'ڃ', + 'ﭹ' => 'ڃ', + 'ﭺ' => 'چ', + 'ﭻ' => 'چ', + 'ﭼ' => 'چ', + 'ﭽ' => 'چ', + 'ﭾ' => 'ڇ', + 'ﭿ' => 'ڇ', + 'ﮀ' => 'ڇ', + 'ﮁ' => 'ڇ', + 'ﮂ' => 'ڍ', + 'ﮃ' => 'ڍ', + 'ﮄ' => 'ڌ', + 'ﮅ' => 'ڌ', + 'ﮆ' => 'ڎ', + 'ﮇ' => 'ڎ', + 'ﮈ' => 'ڈ', + 'ﮉ' => 'ڈ', + 'ﮊ' => 'ژ', + 'ﮋ' => 'ژ', + 'ﮌ' => 'ڑ', + 'ﮍ' => 'ڑ', + 'ﮎ' => 'ک', + 'ﮏ' => 'ک', + 'ﮐ' => 'ک', + 'ﮑ' => 'ک', + 'ﮒ' => 'گ', + 'ﮓ' => 'گ', + 'ﮔ' => 'گ', + 'ﮕ' => 'گ', + 'ﮖ' => 'ڳ', + 'ﮗ' => 'ڳ', + 'ﮘ' => 'ڳ', + 'ﮙ' => 'ڳ', + 'ﮚ' => 'ڱ', + 'ﮛ' => 'ڱ', + 'ﮜ' => 'ڱ', + 'ﮝ' => 'ڱ', + 'ﮞ' => 'ں', + 'ﮟ' => 'ں', + 'ﮠ' => 'ڻ', + 'ﮡ' => 'ڻ', + 'ﮢ' => 'ڻ', + 'ﮣ' => 'ڻ', + 'ﮤ' => 'ۀ', + 'ﮥ' => 'ۀ', + 'ﮦ' => 'ہ', + 'ﮧ' => 'ہ', + 'ﮨ' => 'ہ', + 'ﮩ' => 'ہ', + 'ﮪ' => 'ھ', + 'ﮫ' => 'ھ', + 'ﮬ' => 'ھ', + 'ﮭ' => 'ھ', + 'ﮮ' => 'ے', + 'ﮯ' => 'ے', + 'ﮰ' => 'ۓ', + 'ﮱ' => 'ۓ', + 'ﯓ' => 'ڭ', + 'ﯔ' => 'ڭ', + 'ﯕ' => 'ڭ', + 'ﯖ' => 'ڭ', + 'ﯗ' => 'ۇ', + 'ﯘ' => 'ۇ', + 'ﯙ' => 'ۆ', + 'ﯚ' => 'ۆ', + 'ﯛ' => 'ۈ', + 'ﯜ' => 'ۈ', + 'ﯝ' => 'ۇٴ', + 'ﯞ' => 'ۋ', + 'ﯟ' => 'ۋ', + 'ﯠ' => 'ۅ', + 'ﯡ' => 'ۅ', + 'ﯢ' => 'ۉ', + 'ﯣ' => 'ۉ', + 'ﯤ' => 'ې', + 'ﯥ' => 'ې', + 'ﯦ' => 'ې', + 'ﯧ' => 'ې', + 'ﯨ' => 'ى', + 'ﯩ' => 'ى', + 'ﯪ' => 'ئا', + 'ﯫ' => 'ئا', + 'ﯬ' => 'ئە', + 'ﯭ' => 'ئە', + 'ﯮ' => 'ئو', + 'ﯯ' => 'ئو', + 'ﯰ' => 'ئۇ', + 'ﯱ' => 'ئۇ', + 'ﯲ' => 'ئۆ', + 'ﯳ' => 'ئۆ', + 'ﯴ' => 'ئۈ', + 'ﯵ' => 'ئۈ', + 'ﯶ' => 'ئې', + 'ﯷ' => 'ئې', + 'ﯸ' => 'ئې', + 'ﯹ' => 'ئى', + 'ﯺ' => 'ئى', + 'ﯻ' => 'ئى', + 'ﯼ' => 'ی', + 'ﯽ' => 'ی', + 'ﯾ' => 'ی', + 'ﯿ' => 'ی', + 'ﰀ' => 'ئج', + 'ﰁ' => 'ئح', + 'ﰂ' => 'ئم', + 'ﰃ' => 'ئى', + 'ﰄ' => 'ئي', + 'ﰅ' => 'بج', + 'ﰆ' => 'بح', + 'ﰇ' => 'بخ', + 'ﰈ' => 'بم', + 'ﰉ' => 'بى', + 'ﰊ' => 'بي', + 'ﰋ' => 'تج', + 'ﰌ' => 'تح', + 'ﰍ' => 'تخ', + 'ﰎ' => 'تم', + 'ﰏ' => 'تى', + 'ﰐ' => 'تي', + 'ﰑ' => 'ثج', + 'ﰒ' => 'ثم', + 'ﰓ' => 'ثى', + 'ﰔ' => 'ثي', + 'ﰕ' => 'جح', + 'ﰖ' => 'جم', + 'ﰗ' => 'حج', + 'ﰘ' => 'حم', + 'ﰙ' => 'خج', + 'ﰚ' => 'خح', + 'ﰛ' => 'خم', + 'ﰜ' => 'سج', + 'ﰝ' => 'سح', + 'ﰞ' => 'سخ', + 'ﰟ' => 'سم', + 'ﰠ' => 'صح', + 'ﰡ' => 'صم', + 'ﰢ' => 'ضج', + 'ﰣ' => 'ضح', + 'ﰤ' => 'ضخ', + 'ﰥ' => 'ضم', + 'ﰦ' => 'طح', + 'ﰧ' => 'طم', + 'ﰨ' => 'ظم', + 'ﰩ' => 'عج', + 'ﰪ' => 'عم', + 'ﰫ' => 'غج', + 'ﰬ' => 'غم', + 'ﰭ' => 'فج', + 'ﰮ' => 'فح', + 'ﰯ' => 'فخ', + 'ﰰ' => 'فم', + 'ﰱ' => 'فى', + 'ﰲ' => 'في', + 'ﰳ' => 'قح', + 'ﰴ' => 'قم', + 'ﰵ' => 'قى', + 'ﰶ' => 'قي', + 'ﰷ' => 'كا', + 'ﰸ' => 'كج', + 'ﰹ' => 'كح', + 'ﰺ' => 'كخ', + 'ﰻ' => 'كل', + 'ﰼ' => 'كم', + 'ﰽ' => 'كى', + 'ﰾ' => 'كي', + 'ﰿ' => 'لج', + 'ﱀ' => 'لح', + 'ﱁ' => 'لخ', + 'ﱂ' => 'لم', + 'ﱃ' => 'لى', + 'ﱄ' => 'لي', + 'ﱅ' => 'مج', + 'ﱆ' => 'مح', + 'ﱇ' => 'مخ', + 'ﱈ' => 'مم', + 'ﱉ' => 'مى', + 'ﱊ' => 'مي', + 'ﱋ' => 'نج', + 'ﱌ' => 'نح', + 'ﱍ' => 'نخ', + 'ﱎ' => 'نم', + 'ﱏ' => 'نى', + 'ﱐ' => 'ني', + 'ﱑ' => 'هج', + 'ﱒ' => 'هم', + 'ﱓ' => 'هى', + 'ﱔ' => 'هي', + 'ﱕ' => 'يج', + 'ﱖ' => 'يح', + 'ﱗ' => 'يخ', + 'ﱘ' => 'يم', + 'ﱙ' => 'يى', + 'ﱚ' => 'يي', + 'ﱛ' => 'ذٰ', + 'ﱜ' => 'رٰ', + 'ﱝ' => 'ىٰ', + 'ﱞ' => ' ٌّ', + 'ﱟ' => ' ٍّ', + 'ﱠ' => ' َّ', + 'ﱡ' => ' ُّ', + 'ﱢ' => ' ِّ', + 'ﱣ' => ' ّٰ', + 'ﱤ' => 'ئر', + 'ﱥ' => 'ئز', + 'ﱦ' => 'ئم', + 'ﱧ' => 'ئن', + 'ﱨ' => 'ئى', + 'ﱩ' => 'ئي', + 'ﱪ' => 'بر', + 'ﱫ' => 'بز', + 'ﱬ' => 'بم', + 'ﱭ' => 'بن', + 'ﱮ' => 'بى', + 'ﱯ' => 'بي', + 'ﱰ' => 'تر', + 'ﱱ' => 'تز', + 'ﱲ' => 'تم', + 'ﱳ' => 'تن', + 'ﱴ' => 'تى', + 'ﱵ' => 'تي', + 'ﱶ' => 'ثر', + 'ﱷ' => 'ثز', + 'ﱸ' => 'ثم', + 'ﱹ' => 'ثن', + 'ﱺ' => 'ثى', + 'ﱻ' => 'ثي', + 'ﱼ' => 'فى', + 'ﱽ' => 'في', + 'ﱾ' => 'قى', + 'ﱿ' => 'قي', + 'ﲀ' => 'كا', + 'ﲁ' => 'كل', + 'ﲂ' => 'كم', + 'ﲃ' => 'كى', + 'ﲄ' => 'كي', + 'ﲅ' => 'لم', + 'ﲆ' => 'لى', + 'ﲇ' => 'لي', + 'ﲈ' => 'ما', + 'ﲉ' => 'مم', + 'ﲊ' => 'نر', + 'ﲋ' => 'نز', + 'ﲌ' => 'نم', + 'ﲍ' => 'نن', + 'ﲎ' => 'نى', + 'ﲏ' => 'ني', + 'ﲐ' => 'ىٰ', + 'ﲑ' => 'ير', + 'ﲒ' => 'يز', + 'ﲓ' => 'يم', + 'ﲔ' => 'ين', + 'ﲕ' => 'يى', + 'ﲖ' => 'يي', + 'ﲗ' => 'ئج', + 'ﲘ' => 'ئح', + 'ﲙ' => 'ئخ', + 'ﲚ' => 'ئم', + 'ﲛ' => 'ئه', + 'ﲜ' => 'بج', + 'ﲝ' => 'بح', + 'ﲞ' => 'بخ', + 'ﲟ' => 'بم', + 'ﲠ' => 'به', + 'ﲡ' => 'تج', + 'ﲢ' => 'تح', + 'ﲣ' => 'تخ', + 'ﲤ' => 'تم', + 'ﲥ' => 'ته', + 'ﲦ' => 'ثم', + 'ﲧ' => 'جح', + 'ﲨ' => 'جم', + 'ﲩ' => 'حج', + 'ﲪ' => 'حم', + 'ﲫ' => 'خج', + 'ﲬ' => 'خم', + 'ﲭ' => 'سج', + 'ﲮ' => 'سح', + 'ﲯ' => 'سخ', + 'ﲰ' => 'سم', + 'ﲱ' => 'صح', + 'ﲲ' => 'صخ', + 'ﲳ' => 'صم', + 'ﲴ' => 'ضج', + 'ﲵ' => 'ضح', + 'ﲶ' => 'ضخ', + 'ﲷ' => 'ضم', + 'ﲸ' => 'طح', + 'ﲹ' => 'ظم', + 'ﲺ' => 'عج', + 'ﲻ' => 'عم', + 'ﲼ' => 'غج', + 'ﲽ' => 'غم', + 'ﲾ' => 'فج', + 'ﲿ' => 'فح', + 'ﳀ' => 'فخ', + 'ﳁ' => 'فم', + 'ﳂ' => 'قح', + 'ﳃ' => 'قم', + 'ﳄ' => 'كج', + 'ﳅ' => 'كح', + 'ﳆ' => 'كخ', + 'ﳇ' => 'كل', + 'ﳈ' => 'كم', + 'ﳉ' => 'لج', + 'ﳊ' => 'لح', + 'ﳋ' => 'لخ', + 'ﳌ' => 'لم', + 'ﳍ' => 'له', + 'ﳎ' => 'مج', + 'ﳏ' => 'مح', + 'ﳐ' => 'مخ', + 'ﳑ' => 'مم', + 'ﳒ' => 'نج', + 'ﳓ' => 'نح', + 'ﳔ' => 'نخ', + 'ﳕ' => 'نم', + 'ﳖ' => 'نه', + 'ﳗ' => 'هج', + 'ﳘ' => 'هم', + 'ﳙ' => 'هٰ', + 'ﳚ' => 'يج', + 'ﳛ' => 'يح', + 'ﳜ' => 'يخ', + 'ﳝ' => 'يم', + 'ﳞ' => 'يه', + 'ﳟ' => 'ئم', + 'ﳠ' => 'ئه', + 'ﳡ' => 'بم', + 'ﳢ' => 'به', + 'ﳣ' => 'تم', + 'ﳤ' => 'ته', + 'ﳥ' => 'ثم', + 'ﳦ' => 'ثه', + 'ﳧ' => 'سم', + 'ﳨ' => 'سه', + 'ﳩ' => 'شم', + 'ﳪ' => 'شه', + 'ﳫ' => 'كل', + 'ﳬ' => 'كم', + 'ﳭ' => 'لم', + 'ﳮ' => 'نم', + 'ﳯ' => 'نه', + 'ﳰ' => 'يم', + 'ﳱ' => 'يه', + 'ﳲ' => 'ـَّ', + 'ﳳ' => 'ـُّ', + 'ﳴ' => 'ـِّ', + 'ﳵ' => 'طى', + 'ﳶ' => 'طي', + 'ﳷ' => 'عى', + 'ﳸ' => 'عي', + 'ﳹ' => 'غى', + 'ﳺ' => 'غي', + 'ﳻ' => 'سى', + 'ﳼ' => 'سي', + 'ﳽ' => 'شى', + 'ﳾ' => 'شي', + 'ﳿ' => 'حى', + 'ﴀ' => 'حي', + 'ﴁ' => 'جى', + 'ﴂ' => 'جي', + 'ﴃ' => 'خى', + 'ﴄ' => 'خي', + 'ﴅ' => 'صى', + 'ﴆ' => 'صي', + 'ﴇ' => 'ضى', + 'ﴈ' => 'ضي', + 'ﴉ' => 'شج', + 'ﴊ' => 'شح', + 'ﴋ' => 'شخ', + 'ﴌ' => 'شم', + 'ﴍ' => 'شر', + 'ﴎ' => 'سر', + 'ﴏ' => 'صر', + 'ﴐ' => 'ضر', + 'ﴑ' => 'طى', + 'ﴒ' => 'طي', + 'ﴓ' => 'عى', + 'ﴔ' => 'عي', + 'ﴕ' => 'غى', + 'ﴖ' => 'غي', + 'ﴗ' => 'سى', + 'ﴘ' => 'سي', + 'ﴙ' => 'شى', + 'ﴚ' => 'شي', + 'ﴛ' => 'حى', + 'ﴜ' => 'حي', + 'ﴝ' => 'جى', + 'ﴞ' => 'جي', + 'ﴟ' => 'خى', + 'ﴠ' => 'خي', + 'ﴡ' => 'صى', + 'ﴢ' => 'صي', + 'ﴣ' => 'ضى', + 'ﴤ' => 'ضي', + 'ﴥ' => 'شج', + 'ﴦ' => 'شح', + 'ﴧ' => 'شخ', + 'ﴨ' => 'شم', + 'ﴩ' => 'شر', + 'ﴪ' => 'سر', + 'ﴫ' => 'صر', + 'ﴬ' => 'ضر', + 'ﴭ' => 'شج', + 'ﴮ' => 'شح', + 'ﴯ' => 'شخ', + 'ﴰ' => 'شم', + 'ﴱ' => 'سه', + 'ﴲ' => 'شه', + 'ﴳ' => 'طم', + 'ﴴ' => 'سج', + 'ﴵ' => 'سح', + 'ﴶ' => 'سخ', + 'ﴷ' => 'شج', + 'ﴸ' => 'شح', + 'ﴹ' => 'شخ', + 'ﴺ' => 'طم', + 'ﴻ' => 'ظم', + 'ﴼ' => 'اً', + 'ﴽ' => 'اً', + 'ﵐ' => 'تجم', + 'ﵑ' => 'تحج', + 'ﵒ' => 'تحج', + 'ﵓ' => 'تحم', + 'ﵔ' => 'تخم', + 'ﵕ' => 'تمج', + 'ﵖ' => 'تمح', + 'ﵗ' => 'تمخ', + 'ﵘ' => 'جمح', + 'ﵙ' => 'جمح', + 'ﵚ' => 'حمي', + 'ﵛ' => 'حمى', + 'ﵜ' => 'سحج', + 'ﵝ' => 'سجح', + 'ﵞ' => 'سجى', + 'ﵟ' => 'سمح', + 'ﵠ' => 'سمح', + 'ﵡ' => 'سمج', + 'ﵢ' => 'سمم', + 'ﵣ' => 'سمم', + 'ﵤ' => 'صحح', + 'ﵥ' => 'صحح', + 'ﵦ' => 'صمم', + 'ﵧ' => 'شحم', + 'ﵨ' => 'شحم', + 'ﵩ' => 'شجي', + 'ﵪ' => 'شمخ', + 'ﵫ' => 'شمخ', + 'ﵬ' => 'شمم', + 'ﵭ' => 'شمم', + 'ﵮ' => 'ضحى', + 'ﵯ' => 'ضخم', + 'ﵰ' => 'ضخم', + 'ﵱ' => 'طمح', + 'ﵲ' => 'طمح', + 'ﵳ' => 'طمم', + 'ﵴ' => 'طمي', + 'ﵵ' => 'عجم', + 'ﵶ' => 'عمم', + 'ﵷ' => 'عمم', + 'ﵸ' => 'عمى', + 'ﵹ' => 'غمم', + 'ﵺ' => 'غمي', + 'ﵻ' => 'غمى', + 'ﵼ' => 'فخم', + 'ﵽ' => 'فخم', + 'ﵾ' => 'قمح', + 'ﵿ' => 'قمم', + 'ﶀ' => 'لحم', + 'ﶁ' => 'لحي', + 'ﶂ' => 'لحى', + 'ﶃ' => 'لجج', + 'ﶄ' => 'لجج', + 'ﶅ' => 'لخم', + 'ﶆ' => 'لخم', + 'ﶇ' => 'لمح', + 'ﶈ' => 'لمح', + 'ﶉ' => 'محج', + 'ﶊ' => 'محم', + 'ﶋ' => 'محي', + 'ﶌ' => 'مجح', + 'ﶍ' => 'مجم', + 'ﶎ' => 'مخج', + 'ﶏ' => 'مخم', + 'ﶒ' => 'مجخ', + 'ﶓ' => 'همج', + 'ﶔ' => 'همم', + 'ﶕ' => 'نحم', + 'ﶖ' => 'نحى', + 'ﶗ' => 'نجم', + 'ﶘ' => 'نجم', + 'ﶙ' => 'نجى', + 'ﶚ' => 'نمي', + 'ﶛ' => 'نمى', + 'ﶜ' => 'يمم', + 'ﶝ' => 'يمم', + 'ﶞ' => 'بخي', + 'ﶟ' => 'تجي', + 'ﶠ' => 'تجى', + 'ﶡ' => 'تخي', + 'ﶢ' => 'تخى', + 'ﶣ' => 'تمي', + 'ﶤ' => 'تمى', + 'ﶥ' => 'جمي', + 'ﶦ' => 'جحى', + 'ﶧ' => 'جمى', + 'ﶨ' => 'سخى', + 'ﶩ' => 'صحي', + 'ﶪ' => 'شحي', + 'ﶫ' => 'ضحي', + 'ﶬ' => 'لجي', + 'ﶭ' => 'لمي', + 'ﶮ' => 'يحي', + 'ﶯ' => 'يجي', + 'ﶰ' => 'يمي', + 'ﶱ' => 'ممي', + 'ﶲ' => 'قمي', + 'ﶳ' => 'نحي', + 'ﶴ' => 'قمح', + 'ﶵ' => 'لحم', + 'ﶶ' => 'عمي', + 'ﶷ' => 'كمي', + 'ﶸ' => 'نجح', + 'ﶹ' => 'مخي', + 'ﶺ' => 'لجم', + 'ﶻ' => 'كمم', + 'ﶼ' => 'لجم', + 'ﶽ' => 'نجح', + 'ﶾ' => 'جحي', + 'ﶿ' => 'حجي', + 'ﷀ' => 'مجي', + 'ﷁ' => 'فمي', + 'ﷂ' => 'بحي', + 'ﷃ' => 'كمم', + 'ﷄ' => 'عجم', + 'ﷅ' => 'صمم', + 'ﷆ' => 'سخي', + 'ﷇ' => 'نجي', + 'ﷰ' => 'صلے', + 'ﷱ' => 'قلے', + 'ﷲ' => 'الله', + 'ﷳ' => 'اكبر', + 'ﷴ' => 'محمد', + 'ﷵ' => 'صلعم', + 'ﷶ' => 'رسول', + 'ﷷ' => 'عليه', + 'ﷸ' => 'وسلم', + 'ﷹ' => 'صلى', + 'ﷺ' => 'صلى الله عليه وسلم', + 'ﷻ' => 'جل جلاله', + '﷼' => 'ریال', + '︐' => ',', + '︑' => '、', + '︒' => '。', + '︓' => ':', + '︔' => ';', + '︕' => '!', + '︖' => '?', + '︗' => '〖', + '︘' => '〗', + '︙' => '...', + '︰' => '..', + '︱' => '—', + '︲' => '–', + '︳' => '_', + '︴' => '_', + '︵' => '(', + '︶' => ')', + '︷' => '{', + '︸' => '}', + '︹' => '〔', + '︺' => '〕', + '︻' => '【', + '︼' => '】', + '︽' => '《', + '︾' => '》', + '︿' => '〈', + '﹀' => '〉', + '﹁' => '「', + '﹂' => '」', + '﹃' => '『', + '﹄' => '』', + '﹇' => '[', + '﹈' => ']', + '﹉' => ' ̅', + '﹊' => ' ̅', + '﹋' => ' ̅', + '﹌' => ' ̅', + '﹍' => '_', + '﹎' => '_', + '﹏' => '_', + '﹐' => ',', + '﹑' => '、', + '﹒' => '.', + '﹔' => ';', + '﹕' => ':', + '﹖' => '?', + '﹗' => '!', + '﹘' => '—', + '﹙' => '(', + '﹚' => ')', + '﹛' => '{', + '﹜' => '}', + '﹝' => '〔', + '﹞' => '〕', + '﹟' => '#', + '﹠' => '&', + '﹡' => '*', + '﹢' => '+', + '﹣' => '-', + '﹤' => '<', + '﹥' => '>', + '﹦' => '=', + '﹨' => '\\', + '﹩' => '$', + '﹪' => '%', + '﹫' => '@', + 'ﹰ' => ' ً', + 'ﹱ' => 'ـً', + 'ﹲ' => ' ٌ', + 'ﹴ' => ' ٍ', + 'ﹶ' => ' َ', + 'ﹷ' => 'ـَ', + 'ﹸ' => ' ُ', + 'ﹹ' => 'ـُ', + 'ﹺ' => ' ِ', + 'ﹻ' => 'ـِ', + 'ﹼ' => ' ّ', + 'ﹽ' => 'ـّ', + 'ﹾ' => ' ْ', + 'ﹿ' => 'ـْ', + 'ﺀ' => 'ء', + 'ﺁ' => 'آ', + 'ﺂ' => 'آ', + 'ﺃ' => 'أ', + 'ﺄ' => 'أ', + 'ﺅ' => 'ؤ', + 'ﺆ' => 'ؤ', + 'ﺇ' => 'إ', + 'ﺈ' => 'إ', + 'ﺉ' => 'ئ', + 'ﺊ' => 'ئ', + 'ﺋ' => 'ئ', + 'ﺌ' => 'ئ', + 'ﺍ' => 'ا', + 'ﺎ' => 'ا', + 'ﺏ' => 'ب', + 'ﺐ' => 'ب', + 'ﺑ' => 'ب', + 'ﺒ' => 'ب', + 'ﺓ' => 'ة', + 'ﺔ' => 'ة', + 'ﺕ' => 'ت', + 'ﺖ' => 'ت', + 'ﺗ' => 'ت', + 'ﺘ' => 'ت', + 'ﺙ' => 'ث', + 'ﺚ' => 'ث', + 'ﺛ' => 'ث', + 'ﺜ' => 'ث', + 'ﺝ' => 'ج', + 'ﺞ' => 'ج', + 'ﺟ' => 'ج', + 'ﺠ' => 'ج', + 'ﺡ' => 'ح', + 'ﺢ' => 'ح', + 'ﺣ' => 'ح', + 'ﺤ' => 'ح', + 'ﺥ' => 'خ', + 'ﺦ' => 'خ', + 'ﺧ' => 'خ', + 'ﺨ' => 'خ', + 'ﺩ' => 'د', + 'ﺪ' => 'د', + 'ﺫ' => 'ذ', + 'ﺬ' => 'ذ', + 'ﺭ' => 'ر', + 'ﺮ' => 'ر', + 'ﺯ' => 'ز', + 'ﺰ' => 'ز', + 'ﺱ' => 'س', + 'ﺲ' => 'س', + 'ﺳ' => 'س', + 'ﺴ' => 'س', + 'ﺵ' => 'ش', + 'ﺶ' => 'ش', + 'ﺷ' => 'ش', + 'ﺸ' => 'ش', + 'ﺹ' => 'ص', + 'ﺺ' => 'ص', + 'ﺻ' => 'ص', + 'ﺼ' => 'ص', + 'ﺽ' => 'ض', + 'ﺾ' => 'ض', + 'ﺿ' => 'ض', + 'ﻀ' => 'ض', + 'ﻁ' => 'ط', + 'ﻂ' => 'ط', + 'ﻃ' => 'ط', + 'ﻄ' => 'ط', + 'ﻅ' => 'ظ', + 'ﻆ' => 'ظ', + 'ﻇ' => 'ظ', + 'ﻈ' => 'ظ', + 'ﻉ' => 'ع', + 'ﻊ' => 'ع', + 'ﻋ' => 'ع', + 'ﻌ' => 'ع', + 'ﻍ' => 'غ', + 'ﻎ' => 'غ', + 'ﻏ' => 'غ', + 'ﻐ' => 'غ', + 'ﻑ' => 'ف', + 'ﻒ' => 'ف', + 'ﻓ' => 'ف', + 'ﻔ' => 'ف', + 'ﻕ' => 'ق', + 'ﻖ' => 'ق', + 'ﻗ' => 'ق', + 'ﻘ' => 'ق', + 'ﻙ' => 'ك', + 'ﻚ' => 'ك', + 'ﻛ' => 'ك', + 'ﻜ' => 'ك', + 'ﻝ' => 'ل', + 'ﻞ' => 'ل', + 'ﻟ' => 'ل', + 'ﻠ' => 'ل', + 'ﻡ' => 'م', + 'ﻢ' => 'م', + 'ﻣ' => 'م', + 'ﻤ' => 'م', + 'ﻥ' => 'ن', + 'ﻦ' => 'ن', + 'ﻧ' => 'ن', + 'ﻨ' => 'ن', + 'ﻩ' => 'ه', + 'ﻪ' => 'ه', + 'ﻫ' => 'ه', + 'ﻬ' => 'ه', + 'ﻭ' => 'و', + 'ﻮ' => 'و', + 'ﻯ' => 'ى', + 'ﻰ' => 'ى', + 'ﻱ' => 'ي', + 'ﻲ' => 'ي', + 'ﻳ' => 'ي', + 'ﻴ' => 'ي', + 'ﻵ' => 'لآ', + 'ﻶ' => 'لآ', + 'ﻷ' => 'لأ', + 'ﻸ' => 'لأ', + 'ﻹ' => 'لإ', + 'ﻺ' => 'لإ', + 'ﻻ' => 'لا', + 'ﻼ' => 'لا', + '!' => '!', + '"' => '"', + '#' => '#', + '$' => '$', + '%' => '%', + '&' => '&', + ''' => '\'', + '(' => '(', + ')' => ')', + '*' => '*', + '+' => '+', + ',' => ',', + '-' => '-', + '.' => '.', + '/' => '/', + '0' => '0', + '1' => '1', + '2' => '2', + '3' => '3', + '4' => '4', + '5' => '5', + '6' => '6', + '7' => '7', + '8' => '8', + '9' => '9', + ':' => ':', + ';' => ';', + '<' => '<', + '=' => '=', + '>' => '>', + '?' => '?', + '@' => '@', + 'A' => 'A', + 'B' => 'B', + 'C' => 'C', + 'D' => 'D', + 'E' => 'E', + 'F' => 'F', + 'G' => 'G', + 'H' => 'H', + 'I' => 'I', + 'J' => 'J', + 'K' => 'K', + 'L' => 'L', + 'M' => 'M', + 'N' => 'N', + 'O' => 'O', + 'P' => 'P', + 'Q' => 'Q', + 'R' => 'R', + 'S' => 'S', + 'T' => 'T', + 'U' => 'U', + 'V' => 'V', + 'W' => 'W', + 'X' => 'X', + 'Y' => 'Y', + 'Z' => 'Z', + '[' => '[', + '\' => '\\', + ']' => ']', + '^' => '^', + '_' => '_', + '`' => '`', + 'a' => 'a', + 'b' => 'b', + 'c' => 'c', + 'd' => 'd', + 'e' => 'e', + 'f' => 'f', + 'g' => 'g', + 'h' => 'h', + 'i' => 'i', + 'j' => 'j', + 'k' => 'k', + 'l' => 'l', + 'm' => 'm', + 'n' => 'n', + 'o' => 'o', + 'p' => 'p', + 'q' => 'q', + 'r' => 'r', + 's' => 's', + 't' => 't', + 'u' => 'u', + 'v' => 'v', + 'w' => 'w', + 'x' => 'x', + 'y' => 'y', + 'z' => 'z', + '{' => '{', + '|' => '|', + '}' => '}', + '~' => '~', + '⦅' => '⦅', + '⦆' => '⦆', + '。' => '。', + '「' => '「', + '」' => '」', + '、' => '、', + '・' => '・', + 'ヲ' => 'ヲ', + 'ァ' => 'ァ', + 'ィ' => 'ィ', + 'ゥ' => 'ゥ', + 'ェ' => 'ェ', + 'ォ' => 'ォ', + 'ャ' => 'ャ', + 'ュ' => 'ュ', + 'ョ' => 'ョ', + 'ッ' => 'ッ', + 'ー' => 'ー', + 'ア' => 'ア', + 'イ' => 'イ', + 'ウ' => 'ウ', + 'エ' => 'エ', + 'オ' => 'オ', + 'カ' => 'カ', + 'キ' => 'キ', + 'ク' => 'ク', + 'ケ' => 'ケ', + 'コ' => 'コ', + 'サ' => 'サ', + 'シ' => 'シ', + 'ス' => 'ス', + 'セ' => 'セ', + 'ソ' => 'ソ', + 'タ' => 'タ', + 'チ' => 'チ', + 'ツ' => 'ツ', + 'テ' => 'テ', + 'ト' => 'ト', + 'ナ' => 'ナ', + 'ニ' => 'ニ', + 'ヌ' => 'ヌ', + 'ネ' => 'ネ', + 'ノ' => 'ノ', + 'ハ' => 'ハ', + 'ヒ' => 'ヒ', + 'フ' => 'フ', + 'ヘ' => 'ヘ', + 'ホ' => 'ホ', + 'マ' => 'マ', + 'ミ' => 'ミ', + 'ム' => 'ム', + 'メ' => 'メ', + 'モ' => 'モ', + 'ヤ' => 'ヤ', + 'ユ' => 'ユ', + 'ヨ' => 'ヨ', + 'ラ' => 'ラ', + 'リ' => 'リ', + 'ル' => 'ル', + 'レ' => 'レ', + 'ロ' => 'ロ', + 'ワ' => 'ワ', + 'ン' => 'ン', + '゙' => '゙', + '゚' => '゚', + 'ᅠ' => 'ᅠ', + 'ᄀ' => 'ᄀ', + 'ᄁ' => 'ᄁ', + 'ᆪ' => 'ᆪ', + 'ᄂ' => 'ᄂ', + 'ᆬ' => 'ᆬ', + 'ᆭ' => 'ᆭ', + 'ᄃ' => 'ᄃ', + 'ᄄ' => 'ᄄ', + 'ᄅ' => 'ᄅ', + 'ᆰ' => 'ᆰ', + 'ᆱ' => 'ᆱ', + 'ᆲ' => 'ᆲ', + 'ᆳ' => 'ᆳ', + 'ᆴ' => 'ᆴ', + 'ᆵ' => 'ᆵ', + 'ᄚ' => 'ᄚ', + 'ᄆ' => 'ᄆ', + 'ᄇ' => 'ᄇ', + 'ᄈ' => 'ᄈ', + 'ᄡ' => 'ᄡ', + 'ᄉ' => 'ᄉ', + 'ᄊ' => 'ᄊ', + 'ᄋ' => 'ᄋ', + 'ᄌ' => 'ᄌ', + 'ᄍ' => 'ᄍ', + 'ᄎ' => 'ᄎ', + 'ᄏ' => 'ᄏ', + 'ᄐ' => 'ᄐ', + 'ᄑ' => 'ᄑ', + 'ᄒ' => 'ᄒ', + 'ᅡ' => 'ᅡ', + 'ᅢ' => 'ᅢ', + 'ᅣ' => 'ᅣ', + 'ᅤ' => 'ᅤ', + 'ᅥ' => 'ᅥ', + 'ᅦ' => 'ᅦ', + 'ᅧ' => 'ᅧ', + 'ᅨ' => 'ᅨ', + 'ᅩ' => 'ᅩ', + 'ᅪ' => 'ᅪ', + 'ᅫ' => 'ᅫ', + 'ᅬ' => 'ᅬ', + 'ᅭ' => 'ᅭ', + 'ᅮ' => 'ᅮ', + 'ᅯ' => 'ᅯ', + 'ᅰ' => 'ᅰ', + 'ᅱ' => 'ᅱ', + 'ᅲ' => 'ᅲ', + 'ᅳ' => 'ᅳ', + 'ᅴ' => 'ᅴ', + 'ᅵ' => 'ᅵ', + '¢' => '¢', + '£' => '£', + '¬' => '¬', + ' ̄' => ' ̄', + '¦' => '¦', + '¥' => '¥', + '₩' => '₩', + '│' => '│', + '←' => '←', + '↑' => '↑', + '→' => '→', + '↓' => '↓', + '■' => '■', + '○' => '○', + '𝐀' => 'A', + '𝐁' => 'B', + '𝐂' => 'C', + '𝐃' => 'D', + '𝐄' => 'E', + '𝐅' => 'F', + '𝐆' => 'G', + '𝐇' => 'H', + '𝐈' => 'I', + '𝐉' => 'J', + '𝐊' => 'K', + '𝐋' => 'L', + '𝐌' => 'M', + '𝐍' => 'N', + '𝐎' => 'O', + '𝐏' => 'P', + '𝐐' => 'Q', + '𝐑' => 'R', + '𝐒' => 'S', + '𝐓' => 'T', + '𝐔' => 'U', + '𝐕' => 'V', + '𝐖' => 'W', + '𝐗' => 'X', + '𝐘' => 'Y', + '𝐙' => 'Z', + '𝐚' => 'a', + '𝐛' => 'b', + '𝐜' => 'c', + '𝐝' => 'd', + '𝐞' => 'e', + '𝐟' => 'f', + '𝐠' => 'g', + '𝐡' => 'h', + '𝐢' => 'i', + '𝐣' => 'j', + '𝐤' => 'k', + '𝐥' => 'l', + '𝐦' => 'm', + '𝐧' => 'n', + '𝐨' => 'o', + '𝐩' => 'p', + '𝐪' => 'q', + '𝐫' => 'r', + '𝐬' => 's', + '𝐭' => 't', + '𝐮' => 'u', + '𝐯' => 'v', + '𝐰' => 'w', + '𝐱' => 'x', + '𝐲' => 'y', + '𝐳' => 'z', + '𝐴' => 'A', + '𝐵' => 'B', + '𝐶' => 'C', + '𝐷' => 'D', + '𝐸' => 'E', + '𝐹' => 'F', + '𝐺' => 'G', + '𝐻' => 'H', + '𝐼' => 'I', + '𝐽' => 'J', + '𝐾' => 'K', + '𝐿' => 'L', + '𝑀' => 'M', + '𝑁' => 'N', + '𝑂' => 'O', + '𝑃' => 'P', + '𝑄' => 'Q', + '𝑅' => 'R', + '𝑆' => 'S', + '𝑇' => 'T', + '𝑈' => 'U', + '𝑉' => 'V', + '𝑊' => 'W', + '𝑋' => 'X', + '𝑌' => 'Y', + '𝑍' => 'Z', + '𝑎' => 'a', + '𝑏' => 'b', + '𝑐' => 'c', + '𝑑' => 'd', + '𝑒' => 'e', + '𝑓' => 'f', + '𝑔' => 'g', + '𝑖' => 'i', + '𝑗' => 'j', + '𝑘' => 'k', + '𝑙' => 'l', + '𝑚' => 'm', + '𝑛' => 'n', + '𝑜' => 'o', + '𝑝' => 'p', + '𝑞' => 'q', + '𝑟' => 'r', + '𝑠' => 's', + '𝑡' => 't', + '𝑢' => 'u', + '𝑣' => 'v', + '𝑤' => 'w', + '𝑥' => 'x', + '𝑦' => 'y', + '𝑧' => 'z', + '𝑨' => 'A', + '𝑩' => 'B', + '𝑪' => 'C', + '𝑫' => 'D', + '𝑬' => 'E', + '𝑭' => 'F', + '𝑮' => 'G', + '𝑯' => 'H', + '𝑰' => 'I', + '𝑱' => 'J', + '𝑲' => 'K', + '𝑳' => 'L', + '𝑴' => 'M', + '𝑵' => 'N', + '𝑶' => 'O', + '𝑷' => 'P', + '𝑸' => 'Q', + '𝑹' => 'R', + '𝑺' => 'S', + '𝑻' => 'T', + '𝑼' => 'U', + '𝑽' => 'V', + '𝑾' => 'W', + '𝑿' => 'X', + '𝒀' => 'Y', + '𝒁' => 'Z', + '𝒂' => 'a', + '𝒃' => 'b', + '𝒄' => 'c', + '𝒅' => 'd', + '𝒆' => 'e', + '𝒇' => 'f', + '𝒈' => 'g', + '𝒉' => 'h', + '𝒊' => 'i', + '𝒋' => 'j', + '𝒌' => 'k', + '𝒍' => 'l', + '𝒎' => 'm', + '𝒏' => 'n', + '𝒐' => 'o', + '𝒑' => 'p', + '𝒒' => 'q', + '𝒓' => 'r', + '𝒔' => 's', + '𝒕' => 't', + '𝒖' => 'u', + '𝒗' => 'v', + '𝒘' => 'w', + '𝒙' => 'x', + '𝒚' => 'y', + '𝒛' => 'z', + '𝒜' => 'A', + '𝒞' => 'C', + '𝒟' => 'D', + '𝒢' => 'G', + '𝒥' => 'J', + '𝒦' => 'K', + '𝒩' => 'N', + '𝒪' => 'O', + '𝒫' => 'P', + '𝒬' => 'Q', + '𝒮' => 'S', + '𝒯' => 'T', + '𝒰' => 'U', + '𝒱' => 'V', + '𝒲' => 'W', + '𝒳' => 'X', + '𝒴' => 'Y', + '𝒵' => 'Z', + '𝒶' => 'a', + '𝒷' => 'b', + '𝒸' => 'c', + '𝒹' => 'd', + '𝒻' => 'f', + '𝒽' => 'h', + '𝒾' => 'i', + '𝒿' => 'j', + '𝓀' => 'k', + '𝓁' => 'l', + '𝓂' => 'm', + '𝓃' => 'n', + '𝓅' => 'p', + '𝓆' => 'q', + '𝓇' => 'r', + '𝓈' => 's', + '𝓉' => 't', + '𝓊' => 'u', + '𝓋' => 'v', + '𝓌' => 'w', + '𝓍' => 'x', + '𝓎' => 'y', + '𝓏' => 'z', + '𝓐' => 'A', + '𝓑' => 'B', + '𝓒' => 'C', + '𝓓' => 'D', + '𝓔' => 'E', + '𝓕' => 'F', + '𝓖' => 'G', + '𝓗' => 'H', + '𝓘' => 'I', + '𝓙' => 'J', + '𝓚' => 'K', + '𝓛' => 'L', + '𝓜' => 'M', + '𝓝' => 'N', + '𝓞' => 'O', + '𝓟' => 'P', + '𝓠' => 'Q', + '𝓡' => 'R', + '𝓢' => 'S', + '𝓣' => 'T', + '𝓤' => 'U', + '𝓥' => 'V', + '𝓦' => 'W', + '𝓧' => 'X', + '𝓨' => 'Y', + '𝓩' => 'Z', + '𝓪' => 'a', + '𝓫' => 'b', + '𝓬' => 'c', + '𝓭' => 'd', + '𝓮' => 'e', + '𝓯' => 'f', + '𝓰' => 'g', + '𝓱' => 'h', + '𝓲' => 'i', + '𝓳' => 'j', + '𝓴' => 'k', + '𝓵' => 'l', + '𝓶' => 'm', + '𝓷' => 'n', + '𝓸' => 'o', + '𝓹' => 'p', + '𝓺' => 'q', + '𝓻' => 'r', + '𝓼' => 's', + '𝓽' => 't', + '𝓾' => 'u', + '𝓿' => 'v', + '𝔀' => 'w', + '𝔁' => 'x', + '𝔂' => 'y', + '𝔃' => 'z', + '𝔄' => 'A', + '𝔅' => 'B', + '𝔇' => 'D', + '𝔈' => 'E', + '𝔉' => 'F', + '𝔊' => 'G', + '𝔍' => 'J', + '𝔎' => 'K', + '𝔏' => 'L', + '𝔐' => 'M', + '𝔑' => 'N', + '𝔒' => 'O', + '𝔓' => 'P', + '𝔔' => 'Q', + '𝔖' => 'S', + '𝔗' => 'T', + '𝔘' => 'U', + '𝔙' => 'V', + '𝔚' => 'W', + '𝔛' => 'X', + '𝔜' => 'Y', + '𝔞' => 'a', + '𝔟' => 'b', + '𝔠' => 'c', + '𝔡' => 'd', + '𝔢' => 'e', + '𝔣' => 'f', + '𝔤' => 'g', + '𝔥' => 'h', + '𝔦' => 'i', + '𝔧' => 'j', + '𝔨' => 'k', + '𝔩' => 'l', + '𝔪' => 'm', + '𝔫' => 'n', + '𝔬' => 'o', + '𝔭' => 'p', + '𝔮' => 'q', + '𝔯' => 'r', + '𝔰' => 's', + '𝔱' => 't', + '𝔲' => 'u', + '𝔳' => 'v', + '𝔴' => 'w', + '𝔵' => 'x', + '𝔶' => 'y', + '𝔷' => 'z', + '𝔸' => 'A', + '𝔹' => 'B', + '𝔻' => 'D', + '𝔼' => 'E', + '𝔽' => 'F', + '𝔾' => 'G', + '𝕀' => 'I', + '𝕁' => 'J', + '𝕂' => 'K', + '𝕃' => 'L', + '𝕄' => 'M', + '𝕆' => 'O', + '𝕊' => 'S', + '𝕋' => 'T', + '𝕌' => 'U', + '𝕍' => 'V', + '𝕎' => 'W', + '𝕏' => 'X', + '𝕐' => 'Y', + '𝕒' => 'a', + '𝕓' => 'b', + '𝕔' => 'c', + '𝕕' => 'd', + '𝕖' => 'e', + '𝕗' => 'f', + '𝕘' => 'g', + '𝕙' => 'h', + '𝕚' => 'i', + '𝕛' => 'j', + '𝕜' => 'k', + '𝕝' => 'l', + '𝕞' => 'm', + '𝕟' => 'n', + '𝕠' => 'o', + '𝕡' => 'p', + '𝕢' => 'q', + '𝕣' => 'r', + '𝕤' => 's', + '𝕥' => 't', + '𝕦' => 'u', + '𝕧' => 'v', + '𝕨' => 'w', + '𝕩' => 'x', + '𝕪' => 'y', + '𝕫' => 'z', + '𝕬' => 'A', + '𝕭' => 'B', + '𝕮' => 'C', + '𝕯' => 'D', + '𝕰' => 'E', + '𝕱' => 'F', + '𝕲' => 'G', + '𝕳' => 'H', + '𝕴' => 'I', + '𝕵' => 'J', + '𝕶' => 'K', + '𝕷' => 'L', + '𝕸' => 'M', + '𝕹' => 'N', + '𝕺' => 'O', + '𝕻' => 'P', + '𝕼' => 'Q', + '𝕽' => 'R', + '𝕾' => 'S', + '𝕿' => 'T', + '𝖀' => 'U', + '𝖁' => 'V', + '𝖂' => 'W', + '𝖃' => 'X', + '𝖄' => 'Y', + '𝖅' => 'Z', + '𝖆' => 'a', + '𝖇' => 'b', + '𝖈' => 'c', + '𝖉' => 'd', + '𝖊' => 'e', + '𝖋' => 'f', + '𝖌' => 'g', + '𝖍' => 'h', + '𝖎' => 'i', + '𝖏' => 'j', + '𝖐' => 'k', + '𝖑' => 'l', + '𝖒' => 'm', + '𝖓' => 'n', + '𝖔' => 'o', + '𝖕' => 'p', + '𝖖' => 'q', + '𝖗' => 'r', + '𝖘' => 's', + '𝖙' => 't', + '𝖚' => 'u', + '𝖛' => 'v', + '𝖜' => 'w', + '𝖝' => 'x', + '𝖞' => 'y', + '𝖟' => 'z', + '𝖠' => 'A', + '𝖡' => 'B', + '𝖢' => 'C', + '𝖣' => 'D', + '𝖤' => 'E', + '𝖥' => 'F', + '𝖦' => 'G', + '𝖧' => 'H', + '𝖨' => 'I', + '𝖩' => 'J', + '𝖪' => 'K', + '𝖫' => 'L', + '𝖬' => 'M', + '𝖭' => 'N', + '𝖮' => 'O', + '𝖯' => 'P', + '𝖰' => 'Q', + '𝖱' => 'R', + '𝖲' => 'S', + '𝖳' => 'T', + '𝖴' => 'U', + '𝖵' => 'V', + '𝖶' => 'W', + '𝖷' => 'X', + '𝖸' => 'Y', + '𝖹' => 'Z', + '𝖺' => 'a', + '𝖻' => 'b', + '𝖼' => 'c', + '𝖽' => 'd', + '𝖾' => 'e', + '𝖿' => 'f', + '𝗀' => 'g', + '𝗁' => 'h', + '𝗂' => 'i', + '𝗃' => 'j', + '𝗄' => 'k', + '𝗅' => 'l', + '𝗆' => 'm', + '𝗇' => 'n', + '𝗈' => 'o', + '𝗉' => 'p', + '𝗊' => 'q', + '𝗋' => 'r', + '𝗌' => 's', + '𝗍' => 't', + '𝗎' => 'u', + '𝗏' => 'v', + '𝗐' => 'w', + '𝗑' => 'x', + '𝗒' => 'y', + '𝗓' => 'z', + '𝗔' => 'A', + '𝗕' => 'B', + '𝗖' => 'C', + '𝗗' => 'D', + '𝗘' => 'E', + '𝗙' => 'F', + '𝗚' => 'G', + '𝗛' => 'H', + '𝗜' => 'I', + '𝗝' => 'J', + '𝗞' => 'K', + '𝗟' => 'L', + '𝗠' => 'M', + '𝗡' => 'N', + '𝗢' => 'O', + '𝗣' => 'P', + '𝗤' => 'Q', + '𝗥' => 'R', + '𝗦' => 'S', + '𝗧' => 'T', + '𝗨' => 'U', + '𝗩' => 'V', + '𝗪' => 'W', + '𝗫' => 'X', + '𝗬' => 'Y', + '𝗭' => 'Z', + '𝗮' => 'a', + '𝗯' => 'b', + '𝗰' => 'c', + '𝗱' => 'd', + '𝗲' => 'e', + '𝗳' => 'f', + '𝗴' => 'g', + '𝗵' => 'h', + '𝗶' => 'i', + '𝗷' => 'j', + '𝗸' => 'k', + '𝗹' => 'l', + '𝗺' => 'm', + '𝗻' => 'n', + '𝗼' => 'o', + '𝗽' => 'p', + '𝗾' => 'q', + '𝗿' => 'r', + '𝘀' => 's', + '𝘁' => 't', + '𝘂' => 'u', + '𝘃' => 'v', + '𝘄' => 'w', + '𝘅' => 'x', + '𝘆' => 'y', + '𝘇' => 'z', + '𝘈' => 'A', + '𝘉' => 'B', + '𝘊' => 'C', + '𝘋' => 'D', + '𝘌' => 'E', + '𝘍' => 'F', + '𝘎' => 'G', + '𝘏' => 'H', + '𝘐' => 'I', + '𝘑' => 'J', + '𝘒' => 'K', + '𝘓' => 'L', + '𝘔' => 'M', + '𝘕' => 'N', + '𝘖' => 'O', + '𝘗' => 'P', + '𝘘' => 'Q', + '𝘙' => 'R', + '𝘚' => 'S', + '𝘛' => 'T', + '𝘜' => 'U', + '𝘝' => 'V', + '𝘞' => 'W', + '𝘟' => 'X', + '𝘠' => 'Y', + '𝘡' => 'Z', + '𝘢' => 'a', + '𝘣' => 'b', + '𝘤' => 'c', + '𝘥' => 'd', + '𝘦' => 'e', + '𝘧' => 'f', + '𝘨' => 'g', + '𝘩' => 'h', + '𝘪' => 'i', + '𝘫' => 'j', + '𝘬' => 'k', + '𝘭' => 'l', + '𝘮' => 'm', + '𝘯' => 'n', + '𝘰' => 'o', + '𝘱' => 'p', + '𝘲' => 'q', + '𝘳' => 'r', + '𝘴' => 's', + '𝘵' => 't', + '𝘶' => 'u', + '𝘷' => 'v', + '𝘸' => 'w', + '𝘹' => 'x', + '𝘺' => 'y', + '𝘻' => 'z', + '𝘼' => 'A', + '𝘽' => 'B', + '𝘾' => 'C', + '𝘿' => 'D', + '𝙀' => 'E', + '𝙁' => 'F', + '𝙂' => 'G', + '𝙃' => 'H', + '𝙄' => 'I', + '𝙅' => 'J', + '𝙆' => 'K', + '𝙇' => 'L', + '𝙈' => 'M', + '𝙉' => 'N', + '𝙊' => 'O', + '𝙋' => 'P', + '𝙌' => 'Q', + '𝙍' => 'R', + '𝙎' => 'S', + '𝙏' => 'T', + '𝙐' => 'U', + '𝙑' => 'V', + '𝙒' => 'W', + '𝙓' => 'X', + '𝙔' => 'Y', + '𝙕' => 'Z', + '𝙖' => 'a', + '𝙗' => 'b', + '𝙘' => 'c', + '𝙙' => 'd', + '𝙚' => 'e', + '𝙛' => 'f', + '𝙜' => 'g', + '𝙝' => 'h', + '𝙞' => 'i', + '𝙟' => 'j', + '𝙠' => 'k', + '𝙡' => 'l', + '𝙢' => 'm', + '𝙣' => 'n', + '𝙤' => 'o', + '𝙥' => 'p', + '𝙦' => 'q', + '𝙧' => 'r', + '𝙨' => 's', + '𝙩' => 't', + '𝙪' => 'u', + '𝙫' => 'v', + '𝙬' => 'w', + '𝙭' => 'x', + '𝙮' => 'y', + '𝙯' => 'z', + '𝙰' => 'A', + '𝙱' => 'B', + '𝙲' => 'C', + '𝙳' => 'D', + '𝙴' => 'E', + '𝙵' => 'F', + '𝙶' => 'G', + '𝙷' => 'H', + '𝙸' => 'I', + '𝙹' => 'J', + '𝙺' => 'K', + '𝙻' => 'L', + '𝙼' => 'M', + '𝙽' => 'N', + '𝙾' => 'O', + '𝙿' => 'P', + '𝚀' => 'Q', + '𝚁' => 'R', + '𝚂' => 'S', + '𝚃' => 'T', + '𝚄' => 'U', + '𝚅' => 'V', + '𝚆' => 'W', + '𝚇' => 'X', + '𝚈' => 'Y', + '𝚉' => 'Z', + '𝚊' => 'a', + '𝚋' => 'b', + '𝚌' => 'c', + '𝚍' => 'd', + '𝚎' => 'e', + '𝚏' => 'f', + '𝚐' => 'g', + '𝚑' => 'h', + '𝚒' => 'i', + '𝚓' => 'j', + '𝚔' => 'k', + '𝚕' => 'l', + '𝚖' => 'm', + '𝚗' => 'n', + '𝚘' => 'o', + '𝚙' => 'p', + '𝚚' => 'q', + '𝚛' => 'r', + '𝚜' => 's', + '𝚝' => 't', + '𝚞' => 'u', + '𝚟' => 'v', + '𝚠' => 'w', + '𝚡' => 'x', + '𝚢' => 'y', + '𝚣' => 'z', + '𝚤' => 'ı', + '𝚥' => 'ȷ', + '𝚨' => 'Α', + '𝚩' => 'Β', + '𝚪' => 'Γ', + '𝚫' => 'Δ', + '𝚬' => 'Ε', + '𝚭' => 'Ζ', + '𝚮' => 'Η', + '𝚯' => 'Θ', + '𝚰' => 'Ι', + '𝚱' => 'Κ', + '𝚲' => 'Λ', + '𝚳' => 'Μ', + '𝚴' => 'Ν', + '𝚵' => 'Ξ', + '𝚶' => 'Ο', + '𝚷' => 'Π', + '𝚸' => 'Ρ', + '𝚹' => 'Θ', + '𝚺' => 'Σ', + '𝚻' => 'Τ', + '𝚼' => 'Υ', + '𝚽' => 'Φ', + '𝚾' => 'Χ', + '𝚿' => 'Ψ', + '𝛀' => 'Ω', + '𝛁' => '∇', + '𝛂' => 'α', + '𝛃' => 'β', + '𝛄' => 'γ', + '𝛅' => 'δ', + '𝛆' => 'ε', + '𝛇' => 'ζ', + '𝛈' => 'η', + '𝛉' => 'θ', + '𝛊' => 'ι', + '𝛋' => 'κ', + '𝛌' => 'λ', + '𝛍' => 'μ', + '𝛎' => 'ν', + '𝛏' => 'ξ', + '𝛐' => 'ο', + '𝛑' => 'π', + '𝛒' => 'ρ', + '𝛓' => 'ς', + '𝛔' => 'σ', + '𝛕' => 'τ', + '𝛖' => 'υ', + '𝛗' => 'φ', + '𝛘' => 'χ', + '𝛙' => 'ψ', + '𝛚' => 'ω', + '𝛛' => '∂', + '𝛜' => 'ε', + '𝛝' => 'θ', + '𝛞' => 'κ', + '𝛟' => 'φ', + '𝛠' => 'ρ', + '𝛡' => 'π', + '𝛢' => 'Α', + '𝛣' => 'Β', + '𝛤' => 'Γ', + '𝛥' => 'Δ', + '𝛦' => 'Ε', + '𝛧' => 'Ζ', + '𝛨' => 'Η', + '𝛩' => 'Θ', + '𝛪' => 'Ι', + '𝛫' => 'Κ', + '𝛬' => 'Λ', + '𝛭' => 'Μ', + '𝛮' => 'Ν', + '𝛯' => 'Ξ', + '𝛰' => 'Ο', + '𝛱' => 'Π', + '𝛲' => 'Ρ', + '𝛳' => 'Θ', + '𝛴' => 'Σ', + '𝛵' => 'Τ', + '𝛶' => 'Υ', + '𝛷' => 'Φ', + '𝛸' => 'Χ', + '𝛹' => 'Ψ', + '𝛺' => 'Ω', + '𝛻' => '∇', + '𝛼' => 'α', + '𝛽' => 'β', + '𝛾' => 'γ', + '𝛿' => 'δ', + '𝜀' => 'ε', + '𝜁' => 'ζ', + '𝜂' => 'η', + '𝜃' => 'θ', + '𝜄' => 'ι', + '𝜅' => 'κ', + '𝜆' => 'λ', + '𝜇' => 'μ', + '𝜈' => 'ν', + '𝜉' => 'ξ', + '𝜊' => 'ο', + '𝜋' => 'π', + '𝜌' => 'ρ', + '𝜍' => 'ς', + '𝜎' => 'σ', + '𝜏' => 'τ', + '𝜐' => 'υ', + '𝜑' => 'φ', + '𝜒' => 'χ', + '𝜓' => 'ψ', + '𝜔' => 'ω', + '𝜕' => '∂', + '𝜖' => 'ε', + '𝜗' => 'θ', + '𝜘' => 'κ', + '𝜙' => 'φ', + '𝜚' => 'ρ', + '𝜛' => 'π', + '𝜜' => 'Α', + '𝜝' => 'Β', + '𝜞' => 'Γ', + '𝜟' => 'Δ', + '𝜠' => 'Ε', + '𝜡' => 'Ζ', + '𝜢' => 'Η', + '𝜣' => 'Θ', + '𝜤' => 'Ι', + '𝜥' => 'Κ', + '𝜦' => 'Λ', + '𝜧' => 'Μ', + '𝜨' => 'Ν', + '𝜩' => 'Ξ', + '𝜪' => 'Ο', + '𝜫' => 'Π', + '𝜬' => 'Ρ', + '𝜭' => 'Θ', + '𝜮' => 'Σ', + '𝜯' => 'Τ', + '𝜰' => 'Υ', + '𝜱' => 'Φ', + '𝜲' => 'Χ', + '𝜳' => 'Ψ', + '𝜴' => 'Ω', + '𝜵' => '∇', + '𝜶' => 'α', + '𝜷' => 'β', + '𝜸' => 'γ', + '𝜹' => 'δ', + '𝜺' => 'ε', + '𝜻' => 'ζ', + '𝜼' => 'η', + '𝜽' => 'θ', + '𝜾' => 'ι', + '𝜿' => 'κ', + '𝝀' => 'λ', + '𝝁' => 'μ', + '𝝂' => 'ν', + '𝝃' => 'ξ', + '𝝄' => 'ο', + '𝝅' => 'π', + '𝝆' => 'ρ', + '𝝇' => 'ς', + '𝝈' => 'σ', + '𝝉' => 'τ', + '𝝊' => 'υ', + '𝝋' => 'φ', + '𝝌' => 'χ', + '𝝍' => 'ψ', + '𝝎' => 'ω', + '𝝏' => '∂', + '𝝐' => 'ε', + '𝝑' => 'θ', + '𝝒' => 'κ', + '𝝓' => 'φ', + '𝝔' => 'ρ', + '𝝕' => 'π', + '𝝖' => 'Α', + '𝝗' => 'Β', + '𝝘' => 'Γ', + '𝝙' => 'Δ', + '𝝚' => 'Ε', + '𝝛' => 'Ζ', + '𝝜' => 'Η', + '𝝝' => 'Θ', + '𝝞' => 'Ι', + '𝝟' => 'Κ', + '𝝠' => 'Λ', + '𝝡' => 'Μ', + '𝝢' => 'Ν', + '𝝣' => 'Ξ', + '𝝤' => 'Ο', + '𝝥' => 'Π', + '𝝦' => 'Ρ', + '𝝧' => 'Θ', + '𝝨' => 'Σ', + '𝝩' => 'Τ', + '𝝪' => 'Υ', + '𝝫' => 'Φ', + '𝝬' => 'Χ', + '𝝭' => 'Ψ', + '𝝮' => 'Ω', + '𝝯' => '∇', + '𝝰' => 'α', + '𝝱' => 'β', + '𝝲' => 'γ', + '𝝳' => 'δ', + '𝝴' => 'ε', + '𝝵' => 'ζ', + '𝝶' => 'η', + '𝝷' => 'θ', + '𝝸' => 'ι', + '𝝹' => 'κ', + '𝝺' => 'λ', + '𝝻' => 'μ', + '𝝼' => 'ν', + '𝝽' => 'ξ', + '𝝾' => 'ο', + '𝝿' => 'π', + '𝞀' => 'ρ', + '𝞁' => 'ς', + '𝞂' => 'σ', + '𝞃' => 'τ', + '𝞄' => 'υ', + '𝞅' => 'φ', + '𝞆' => 'χ', + '𝞇' => 'ψ', + '𝞈' => 'ω', + '𝞉' => '∂', + '𝞊' => 'ε', + '𝞋' => 'θ', + '𝞌' => 'κ', + '𝞍' => 'φ', + '𝞎' => 'ρ', + '𝞏' => 'π', + '𝞐' => 'Α', + '𝞑' => 'Β', + '𝞒' => 'Γ', + '𝞓' => 'Δ', + '𝞔' => 'Ε', + '𝞕' => 'Ζ', + '𝞖' => 'Η', + '𝞗' => 'Θ', + '𝞘' => 'Ι', + '𝞙' => 'Κ', + '𝞚' => 'Λ', + '𝞛' => 'Μ', + '𝞜' => 'Ν', + '𝞝' => 'Ξ', + '𝞞' => 'Ο', + '𝞟' => 'Π', + '𝞠' => 'Ρ', + '𝞡' => 'Θ', + '𝞢' => 'Σ', + '𝞣' => 'Τ', + '𝞤' => 'Υ', + '𝞥' => 'Φ', + '𝞦' => 'Χ', + '𝞧' => 'Ψ', + '𝞨' => 'Ω', + '𝞩' => '∇', + '𝞪' => 'α', + '𝞫' => 'β', + '𝞬' => 'γ', + '𝞭' => 'δ', + '𝞮' => 'ε', + '𝞯' => 'ζ', + '𝞰' => 'η', + '𝞱' => 'θ', + '𝞲' => 'ι', + '𝞳' => 'κ', + '𝞴' => 'λ', + '𝞵' => 'μ', + '𝞶' => 'ν', + '𝞷' => 'ξ', + '𝞸' => 'ο', + '𝞹' => 'π', + '𝞺' => 'ρ', + '𝞻' => 'ς', + '𝞼' => 'σ', + '𝞽' => 'τ', + '𝞾' => 'υ', + '𝞿' => 'φ', + '𝟀' => 'χ', + '𝟁' => 'ψ', + '𝟂' => 'ω', + '𝟃' => '∂', + '𝟄' => 'ε', + '𝟅' => 'θ', + '𝟆' => 'κ', + '𝟇' => 'φ', + '𝟈' => 'ρ', + '𝟉' => 'π', + '𝟊' => 'Ϝ', + '𝟋' => 'ϝ', + '𝟎' => '0', + '𝟏' => '1', + '𝟐' => '2', + '𝟑' => '3', + '𝟒' => '4', + '𝟓' => '5', + '𝟔' => '6', + '𝟕' => '7', + '𝟖' => '8', + '𝟗' => '9', + '𝟘' => '0', + '𝟙' => '1', + '𝟚' => '2', + '𝟛' => '3', + '𝟜' => '4', + '𝟝' => '5', + '𝟞' => '6', + '𝟟' => '7', + '𝟠' => '8', + '𝟡' => '9', + '𝟢' => '0', + '𝟣' => '1', + '𝟤' => '2', + '𝟥' => '3', + '𝟦' => '4', + '𝟧' => '5', + '𝟨' => '6', + '𝟩' => '7', + '𝟪' => '8', + '𝟫' => '9', + '𝟬' => '0', + '𝟭' => '1', + '𝟮' => '2', + '𝟯' => '3', + '𝟰' => '4', + '𝟱' => '5', + '𝟲' => '6', + '𝟳' => '7', + '𝟴' => '8', + '𝟵' => '9', + '𝟶' => '0', + '𝟷' => '1', + '𝟸' => '2', + '𝟹' => '3', + '𝟺' => '4', + '𝟻' => '5', + '𝟼' => '6', + '𝟽' => '7', + '𝟾' => '8', + '𝟿' => '9', + '𞸀' => 'ا', + '𞸁' => 'ب', + '𞸂' => 'ج', + '𞸃' => 'د', + '𞸅' => 'و', + '𞸆' => 'ز', + '𞸇' => 'ح', + '𞸈' => 'ط', + '𞸉' => 'ي', + '𞸊' => 'ك', + '𞸋' => 'ل', + '𞸌' => 'م', + '𞸍' => 'ن', + '𞸎' => 'س', + '𞸏' => 'ع', + '𞸐' => 'ف', + '𞸑' => 'ص', + '𞸒' => 'ق', + '𞸓' => 'ر', + '𞸔' => 'ش', + '𞸕' => 'ت', + '𞸖' => 'ث', + '𞸗' => 'خ', + '𞸘' => 'ذ', + '𞸙' => 'ض', + '𞸚' => 'ظ', + '𞸛' => 'غ', + '𞸜' => 'ٮ', + '𞸝' => 'ں', + '𞸞' => 'ڡ', + '𞸟' => 'ٯ', + '𞸡' => 'ب', + '𞸢' => 'ج', + '𞸤' => 'ه', + '𞸧' => 'ح', + '𞸩' => 'ي', + '𞸪' => 'ك', + '𞸫' => 'ل', + '𞸬' => 'م', + '𞸭' => 'ن', + '𞸮' => 'س', + '𞸯' => 'ع', + '𞸰' => 'ف', + '𞸱' => 'ص', + '𞸲' => 'ق', + '𞸴' => 'ش', + '𞸵' => 'ت', + '𞸶' => 'ث', + '𞸷' => 'خ', + '𞸹' => 'ض', + '𞸻' => 'غ', + '𞹂' => 'ج', + '𞹇' => 'ح', + '𞹉' => 'ي', + '𞹋' => 'ل', + '𞹍' => 'ن', + '𞹎' => 'س', + '𞹏' => 'ع', + '𞹑' => 'ص', + '𞹒' => 'ق', + '𞹔' => 'ش', + '𞹗' => 'خ', + '𞹙' => 'ض', + '𞹛' => 'غ', + '𞹝' => 'ں', + '𞹟' => 'ٯ', + '𞹡' => 'ب', + '𞹢' => 'ج', + '𞹤' => 'ه', + '𞹧' => 'ح', + '𞹨' => 'ط', + '𞹩' => 'ي', + '𞹪' => 'ك', + '𞹬' => 'م', + '𞹭' => 'ن', + '𞹮' => 'س', + '𞹯' => 'ع', + '𞹰' => 'ف', + '𞹱' => 'ص', + '𞹲' => 'ق', + '𞹴' => 'ش', + '𞹵' => 'ت', + '𞹶' => 'ث', + '𞹷' => 'خ', + '𞹹' => 'ض', + '𞹺' => 'ظ', + '𞹻' => 'غ', + '𞹼' => 'ٮ', + '𞹾' => 'ڡ', + '𞺀' => 'ا', + '𞺁' => 'ب', + '𞺂' => 'ج', + '𞺃' => 'د', + '𞺄' => 'ه', + '𞺅' => 'و', + '𞺆' => 'ز', + '𞺇' => 'ح', + '𞺈' => 'ط', + '𞺉' => 'ي', + '𞺋' => 'ل', + '𞺌' => 'م', + '𞺍' => 'ن', + '𞺎' => 'س', + '𞺏' => 'ع', + '𞺐' => 'ف', + '𞺑' => 'ص', + '𞺒' => 'ق', + '𞺓' => 'ر', + '𞺔' => 'ش', + '𞺕' => 'ت', + '𞺖' => 'ث', + '𞺗' => 'خ', + '𞺘' => 'ذ', + '𞺙' => 'ض', + '𞺚' => 'ظ', + '𞺛' => 'غ', + '𞺡' => 'ب', + '𞺢' => 'ج', + '𞺣' => 'د', + '𞺥' => 'و', + '𞺦' => 'ز', + '𞺧' => 'ح', + '𞺨' => 'ط', + '𞺩' => 'ي', + '𞺫' => 'ل', + '𞺬' => 'م', + '𞺭' => 'ن', + '𞺮' => 'س', + '𞺯' => 'ع', + '𞺰' => 'ف', + '𞺱' => 'ص', + '𞺲' => 'ق', + '𞺳' => 'ر', + '𞺴' => 'ش', + '𞺵' => 'ت', + '𞺶' => 'ث', + '𞺷' => 'خ', + '𞺸' => 'ذ', + '𞺹' => 'ض', + '𞺺' => 'ظ', + '𞺻' => 'غ', + '🄀' => '0.', + '🄁' => '0,', + '🄂' => '1,', + '🄃' => '2,', + '🄄' => '3,', + '🄅' => '4,', + '🄆' => '5,', + '🄇' => '6,', + '🄈' => '7,', + '🄉' => '8,', + '🄊' => '9,', + '🄐' => '(A)', + '🄑' => '(B)', + '🄒' => '(C)', + '🄓' => '(D)', + '🄔' => '(E)', + '🄕' => '(F)', + '🄖' => '(G)', + '🄗' => '(H)', + '🄘' => '(I)', + '🄙' => '(J)', + '🄚' => '(K)', + '🄛' => '(L)', + '🄜' => '(M)', + '🄝' => '(N)', + '🄞' => '(O)', + '🄟' => '(P)', + '🄠' => '(Q)', + '🄡' => '(R)', + '🄢' => '(S)', + '🄣' => '(T)', + '🄤' => '(U)', + '🄥' => '(V)', + '🄦' => '(W)', + '🄧' => '(X)', + '🄨' => '(Y)', + '🄩' => '(Z)', + '🄪' => '〔S〕', + '🄫' => 'C', + '🄬' => 'R', + '🄭' => 'CD', + '🄮' => 'WZ', + '🄰' => 'A', + '🄱' => 'B', + '🄲' => 'C', + '🄳' => 'D', + '🄴' => 'E', + '🄵' => 'F', + '🄶' => 'G', + '🄷' => 'H', + '🄸' => 'I', + '🄹' => 'J', + '🄺' => 'K', + '🄻' => 'L', + '🄼' => 'M', + '🄽' => 'N', + '🄾' => 'O', + '🄿' => 'P', + '🅀' => 'Q', + '🅁' => 'R', + '🅂' => 'S', + '🅃' => 'T', + '🅄' => 'U', + '🅅' => 'V', + '🅆' => 'W', + '🅇' => 'X', + '🅈' => 'Y', + '🅉' => 'Z', + '🅊' => 'HV', + '🅋' => 'MV', + '🅌' => 'SD', + '🅍' => 'SS', + '🅎' => 'PPV', + '🅏' => 'WC', + '🅪' => 'MC', + '🅫' => 'MD', + '🅬' => 'MR', + '🆐' => 'DJ', + '🈀' => 'ほか', + '🈁' => 'ココ', + '🈂' => 'サ', + '🈐' => '手', + '🈑' => '字', + '🈒' => '双', + '🈓' => 'デ', + '🈔' => '二', + '🈕' => '多', + '🈖' => '解', + '🈗' => '天', + '🈘' => '交', + '🈙' => '映', + '🈚' => '無', + '🈛' => '料', + '🈜' => '前', + '🈝' => '後', + '🈞' => '再', + '🈟' => '新', + '🈠' => '初', + '🈡' => '終', + '🈢' => '生', + '🈣' => '販', + '🈤' => '声', + '🈥' => '吹', + '🈦' => '演', + '🈧' => '投', + '🈨' => '捕', + '🈩' => '一', + '🈪' => '三', + '🈫' => '遊', + '🈬' => '左', + '🈭' => '中', + '🈮' => '右', + '🈯' => '指', + '🈰' => '走', + '🈱' => '打', + '🈲' => '禁', + '🈳' => '空', + '🈴' => '合', + '🈵' => '満', + '🈶' => '有', + '🈷' => '月', + '🈸' => '申', + '🈹' => '割', + '🈺' => '営', + '🈻' => '配', + '🉀' => '〔本〕', + '🉁' => '〔三〕', + '🉂' => '〔二〕', + '🉃' => '〔安〕', + '🉄' => '〔点〕', + '🉅' => '〔打〕', + '🉆' => '〔盗〕', + '🉇' => '〔勝〕', + '🉈' => '〔敗〕', + '🉐' => '得', + '🉑' => '可', + '🯰' => '0', + '🯱' => '1', + '🯲' => '2', + '🯳' => '3', + '🯴' => '4', + '🯵' => '5', + '🯶' => '6', + '🯷' => '7', + '🯸' => '8', + '🯹' => '9', +); diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap.php new file mode 100644 index 0000000..3608e5c --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); } +} diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php new file mode 100644 index 0000000..e36d1a9 --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); } +} diff --git a/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/composer.json b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/composer.json new file mode 100644 index 0000000..1b93573 --- /dev/null +++ b/transfer-protocol/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/polyfill-intl-normalizer", + "type": "library", + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +}