diff --git a/README.md b/README.md
index 0265916..7c06e01 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,33 @@
-
# π BCP47Tag
## πͺ **Donβt panic. Your tag is valid.**
-### Validate, Normalize & Canonicalize BCP 47 Language Tags. That would be `en`, `en-US`, etc ...
+### Validate, Normalize & Canonicalize BCP 47 Language Tags (`en`, `en-US`, `zh-Hant-CN`, etc.)


-
+

+

-**BCP47Tag** is a lightweight, robust PHP library for parsing, validating, normalizing, and resolving [BCP 47](https://tools.ietf.org/html/bcp47) language tags β the standard that powers `en-US`, `fr-CA`, `zh-Hant-CN`, `i-klingon` (π Qaplaβ!), and more.
-
----
-
-## β
**Why use BCP47Tag?**
+**BCP47Tag** is a robust PHP library for working with BCP 47 language tags:
-- βοΈ **RFC 5646 / BCP 47 compliant** structure
+- βοΈ Validates against the real IANA Language Subtag Registry
+- βοΈ ABNF-compliant (RFCβ―5646)
- βοΈ Supports language, script, region, variant, grandfathered tags
- βοΈ Auto-normalizes casing & separators (`en_us` β `en-US`)
-- βοΈ **Resolves partial language-only tags** (`en` β `en-US`) when you require a canonical tag
-- βοΈ Validates against the **official IANA Language Subtag Registry**
+- βοΈ Automatically expands collapsed ranges from the registry
+- βοΈ Resolves partial language tags (e.g., `en` β `en-US`) using custom canonical matching, with scoring
+- βοΈ Error handling via clear exception types
+- βοΈ Lightweight `LanguageTag` VO for validated tags
+- βοΈ Works perfectly with `ext-intl`βno surprises upon feeding ICU
- βοΈ Easy fallback mechanism
-- βοΈ Zero hidden magic β clear, explicit resolution
- οΈπ«§ Supports grandfathered tags so old, they still remember when Unicode 2.0 was hot
- π Accepts `i-klingon` and `i-enochian` for your occult projects
- π€ `ABNF` so clean, linguists shed a single tear
-
---
## β Why not just use `ext-intl`?
-
-Good question β and the answer is: you **should** keep using it!
-`BCP47Tag` isnβt here to replace it β it exists to **make sure your language tags are clean, canonical, and safe *before* you hand them to ICU**.
-
-Because we usually rely on **`ext-intl`** for date formats, currencies, or sorting rules β and it does that well, *if* the tag is valid.
+Good question β and the answer is: you **should** keep using it!
+`ext-intl` (ICU) is brilliant at formatting *if* your tag is clean.
However, it does **not**:
@@ -49,6 +44,7 @@ And thatβs fine for checking user input β but it stops at *structure*. It wo
- β
Use **BCP47Tag** to *validate & normalize*.
- β
Hand the cleaned tag to `ext-intl` or whatever else you have for formatting & display.
- β
Trust youβll never feed ICU any garbage.
+- β
Carry around immutable LanguageTag value object across your code base instead of string
**BCP47Tag**: RFC 5646 + IANA + real normalization + fallback + resolution.
No hustle with regex, `str_replace()` or guesswork.
@@ -70,77 +66,93 @@ use LHcze\BCP47\BCP47Tag;
// Just normalize & validate
$tag = new BCP47Tag('en_us');
-echo $tag->getNormalized(); // en-US
+echo $tag->getNormalized(); // "en-US"
+echo $tag->getICUformat(); // "en_US"
+
+// With canonical matching
+$tag = new BCP47Tag('en', useCanonicalMatchTags: ['de-DE', 'en-US']);
+echo $tag->getNormalized(); // "en-US"
// Use fallback if invalid
-$tag = new BCP47Tag('notreal', fallbackLocale: 'fr-FR');
+$tag = new BCP47Tag('notreal', 'fr-FR');
echo $tag->getNormalized(); // fr-FR
-// Resolve partial to known canonical tag
-$tag = new BCP47Tag(
- 'en',
- knownTags: ['en-US', 'en-GB'],
- requireCanonical: true
-);
-echo $tag->getNormalized(); // en-US
+// Invalid input β exception
+try {
+ new BCP47Tag('invalid!!');
+} catch (BCP47InvalidLocaleException $e) {
+ echo $e->getMessage();
+}
// Feed to ext-intl
$icu = $tag->getICULocale(); // en_US
echo Locale::getDisplayLanguage($icu); // English
-// Inspect parsed parts (language, script, region, variants)
-$parsed = $tag->getParsedTag();
-echo $parsed?->getLanguage(); // en
-echo $parsed?->getRegion(); // US
+// LanguageTag VO
+$langTag = $tag->getLanguageTag();
+echo $langTag->getLanguage(); // "en"
+echo $langTag->getRegion(); // "US"
+echo (string) $langTag; // "en-US"
```
---
-## π **How Resolution Works**
+## π **Features & Flow**
-β
**`knownTags`**
-Provide an explicit list of canonical BCP 47 tags your app accepts.
-If the input is partial (like `en`), the tag will resolve to the first matching known tag (`en-US`). Position in the list is a priority.
+1. **Normalize + parse**
+ Clean casing/formatting and parse into components.
-β
**`requireCanonical`**
-When true, language-only input must resolve to a canonical known tag β or the constructor will throw an `InvalidArgumentException`.
+2. **Validate against IANA**
+ Broken input or fallback triggers explicit exceptions:
+ - `BCP47InvalidLocaleException`
+ - `BCP47InvalidFallbackLocaleException`
-β
**Fallback**
-If the input is invalid and a fallback is provided, it will be used instead.
+3. **Canonical matching (optional)**
+ - Pass an array of `useCanonicalMatchTags`
+ - Each is matched and scored:
+ +100 language match, +10 region, +1 script
+ - Highest score wins.
+ - Same score makes the first one to have it to make a home run
----
+4. **LanguageTag VO**
+ Immutable, validated, `Stringable` & `JsonSerializable`.
-## π **Powered by Official IANA Data**
+---
+## π Supported Tags
BCP47Tag uses a **precompiled static PHP snapshot** of the latest **IANA Language Subtag Registry** to validate languages, scripts, regions, variants, and grandfathered tags.
-
The registry is loaded **once per process**, kept hot in OPcache for maximum speed.
+- β
ISO language, script, region, variants
+- β
Grandfathered/deprecated tags (e.g., `i-klingon`)
+- β
Collapsed registry ranges are auto-expanded
+- β οΈ Extensions & private-use subtags (future)
---
## π§© **Key API**
-| Method | Purpose |
-|-------------------|----------------------------------------------|
-| `getNormalized()` | RFC 5646 standard `xx-XX` format |
-| `getICULocale()` | `xx_XX` format safe for `ext-intl` |
-| `getOriginalInput()` | Raw input string |
-| `getParsedTag()` | Returns the ParsedTag value object for advanced inspection |
-| `__toString()` | Returns the normalized tag |
+| Method | Description |
+|--------|-------------|
+| `__construct(string $input, ?string $fallback, ?array $useCanonicalMatchTags)` | Main entry |
+| `getInputLocale()` | Original input string |
+| `getNormalized()` | RFCβ5646 formatted tag |
+| `getICUformat()` | Underscore variant (`xx_XX`) |
+| `getLanguageTag()` | Returns `LanguageTag` VO |
+| `__toString()` / `jsonSerialize()` | Returns normalized string |
---
## π The Official BCP 47 ABNF
-The syntax your tags must follow is defined by [RFC 5646](https://datatracker.ietf.org/doc/html/rfc5646) in ABNF:
+The syntax tags must follow is defined by [RFC 5646](https://datatracker.ietf.org/doc/html/rfc5646) in ABNF:
```abnf
langtag = language
- ["-" script]
- ["-" region]
- *("-" variant)
- *("-" extension)
- ["-" privateuse]
+ ["-" script]
+ ["-" region]
+ *("-" variant)
+ *("-" extension)
+ ["-" privateuse]
```
Examples:
@@ -153,6 +165,15 @@ Examples:
BCP47Tag respects this ABNF, so your tags match the real spec β no hidden assumptions.
+---
+## β **Why is this useful?**
+
+Use cases include:
+- Validating API `Accept-Language` headers
+- Multi-regional CMS deployments
+- Internationalization pipelines
+- Locale-dependent services where mis-typed tags lead to silent failures
+
---
## βοΈ **Requirements**
@@ -165,34 +186,35 @@ BCP47Tag respects this ABNF, so your tags match the real spec β no hidden assu
## π§ͺ **Tests**
```bash
-vendor/bin/phpunit
+composer qa
```
---
## π **Roadmap**
+- β
IANA Language Subtag Registry integration
- β
Language, script, region, variant validation
-- β
IANA subtag registry integration
-- β
Canonical resolution with known tags
+- β
Lazy singleton registry loader
- β
Static PHP snapshot of the IANA registry for ultra-fast lookups
-- β
Lazy singleton registry loader for low memory overhead
-- βοΈ Extensions & private-use subtags (planned)
-- βοΈ Automatic periodic IANA registry updates (planned)
-- βοΈ CLI tool to refresh the IANA data easily
-- βοΈ Optional Symfony service for container-based caching
+- β
Canonical matching with scoring
+- β
Typed exceptions for flow control
+- βοΈ Extension/subtag support (planned)
+- βοΈ Additional data use from IANA registry (suppress-script subtag, preferred, prefix)
+- βοΈ Auto-registry refresh script
---
-## π **License**
+
+## π License
[MIT](LICENSE)
---
-## π **References**
+## π References
-- [BCP 47 Specification (RFC 5646)](https://tools.ietf.org/html/rfc5646)
+- [RFC 5646 β BCPβ―47 ABNF](https://tools.ietf.org/html/rfc5646)
- [IANA Language Subtag Registry](https://www.iana.org/assignments/language-subtag-registry)
---
diff --git a/bin/fetch_iana_registry.php b/bin/fetch_iana_registry.php
index 5e0f7b8..44a8693 100644
--- a/bin/fetch_iana_registry.php
+++ b/bin/fetch_iana_registry.php
@@ -1,7 +1,23 @@
>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * TODO
+ * Swap array index keys for actual tag/subtag for faster lookups
+ * That would also allow adding a tag/subtag additional data such as preferred-Value, prefix, description, etc.
+ *
+ */
declare(strict_types=1);
+require __DIR__ . '/../src/Utils/expandAlphaRangeFunction.php';;
+
/**
* This script downloads the IANA Language Subtag Registry and converts it to a PHP file
* with a return statement for faster loading in the IanaSubtagRegistry class.
@@ -10,8 +26,9 @@
// URL of the IANA Language Subtag Registry
$registryUrl = 'https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry';
-// Output file path
-$outputFile = __DIR__ . '/../src/Resources/IanaSubtagRegistry.php';
+// Output file paths
+$outputFile = __DIR__ . '/../src/Resources/IanaSubtagRegistryResource.php';
+$enumOutputFile = __DIR__ . '/../src/Enum/GrandfatheredTag.php';
echo "Downloading IANA Language Subtag Registry...\n";
@@ -19,7 +36,11 @@
$ch = curl_init($registryUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
-curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
+curl_setopt(
+ $ch,
+ CURLOPT_USERAGENT,
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
+);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$registryContent = curl_exec($ch);
@@ -32,7 +53,7 @@
exit(1);
}
-echo "Parsing registry data...\n";
+echo sprintf("Parsing registry data... size (Kb): %s\n", round(strlen($registryContent) / 1024, 2));
// Initialize arrays to store different types of subtags
$languages = [];
@@ -44,7 +65,7 @@
// Split the registry into sections by '%%'
$sections = explode('%%', $registryContent);
-// Process each section
+/// Process each section
foreach ($sections as $section) {
// Skip empty sections
if (trim($section) === '') {
@@ -83,35 +104,45 @@
$data[$currentKey] = trim($currentValue);
}
- // Categorize the section based on its Type
- if (isset($data['Type'])) {
- switch ($data['Type']) {
- case 'language':
- if (isset($data['Subtag'])) {
- $languages[] = strtolower($data['Subtag']);
- }
- break;
- case 'script':
- if (isset($data['Subtag'])) {
- $scripts[] = ucfirst(strtolower($data['Subtag']));
- }
- break;
- case 'region':
- if (isset($data['Subtag'])) {
- $regions[] = strtoupper($data['Subtag']);
- }
- break;
- case 'variant':
- if (isset($data['Subtag'])) {
- $variants[] = strtolower($data['Subtag']);
- }
- break;
- case 'grandfathered':
- if (isset($data['Tag'])) {
- $grandfathered[] = strtolower($data['Tag']);
- }
- break;
+ // Check if this section is a valid subtag entry
+ if (!isset($data['Type'])) {
+ continue;
+ }
+
+ $type = $data['Type'];
+
+ // Handle grandfathered tags separately
+ if ($type === 'grandfathered' && isset($data['Tag'])) {
+ $grandfathered[] = strtolower($data['Tag']);
+ continue;
+ }
+
+ // Handle entries with a Subtag
+ if (!isset($data['Subtag'])) {
+ continue;
+ }
+
+ $subtag = $data['Subtag'];
+
+ // If the subtag is a range (e.g., 'Qaaa..Qabx'), expand it ('qaa..qtz' β ['qaa', 'qab', ..., 'qtz'])
+ if (str_contains($subtag, '..')) {
+ [$start, $end] = explode('..', $subtag);
+
+ switch ($type) {
+ case 'language': expandAlphaRangeFunction($languages, $start, $end, fn($s) => strtolower($s)); break;
+ case 'script': expandAlphaRangeFunction($scripts, $start, $end, fn($s) => ucfirst(strtolower($s))); break;
+ case 'region': expandAlphaRangeFunction($regions, $start, $end, fn($s) => strtoupper($s)); break;
}
+
+ continue;
+ }
+
+ // Regular single subtag entry
+ switch ($type) {
+ case 'language': $languages[] = strtolower($subtag); break;
+ case 'script': $scripts[] = ucfirst(strtolower($subtag)); break;
+ case 'region': $regions[] = strtoupper($subtag); break;
+ case 'variant': $variants[] = strtolower($subtag); break;
}
}
@@ -131,11 +162,22 @@
'grandfathered' => array_values(array_unique($grandfathered)),
];
+$data = var_export($data, true);
+if ($data === null) {
+ $data = [
+ 'languages' => [],
+ 'scripts' => [],
+ 'regions' => [],
+ 'variants' => [],
+ 'grandfathered' => [],
+ ];
+}
+
// Generate PHP file content
$phpContent = "=8.1"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/contracts",
- "name": "symfony/contracts"
- },
- "branch-alias": {
- "dev-main": "3.6-dev"
- }
- },
- "autoload": {
- "files": [
- "function.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "A generic function and convention to trigger deprecation notices",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-25T14:21:43+00:00"
- },
- {
- "name": "symfony/intl",
- "version": "v6.4.23",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/intl.git",
- "reference": "a3b12ce29a770d1f26c380dabf56a71bc2a88c84"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/intl/zipball/a3b12ce29a770d1f26c380dabf56a71bc2a88c84",
- "reference": "a3b12ce29a770d1f26c380dabf56a71bc2a88c84",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "require-dev": {
- "symfony/filesystem": "^5.4|^6.0|^7.0",
- "symfony/finder": "^5.4|^6.0|^7.0",
- "symfony/var-exporter": "^5.4|^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Intl\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/",
- "/Resources/data/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- },
- {
- "name": "Eriksen Costa",
- "email": "eriksen.costa@infranology.com.br"
- },
- {
- "name": "Igor Wiedler",
- "email": "igor@wiedler.ch"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides access to the localization data of the ICU library",
- "homepage": "https://symfony.com",
- "keywords": [
- "i18n",
- "icu",
- "internationalization",
- "intl",
- "l10n",
- "localization"
- ],
- "support": {
- "source": "https://github.com/symfony/intl/tree/v6.4.23"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-06-06T07:42:46+00:00"
- },
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.32.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-mbstring",
- "version": "v1.32.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
- "shasum": ""
- },
- "require": {
- "ext-iconv": "*",
- "php": ">=7.2"
- },
- "provide": {
- "ext-mbstring": "*"
- },
- "suggest": {
- "ext-mbstring": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Mbstring\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for the Mbstring extension",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "mbstring",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.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-12-23T08:48:59+00:00"
- },
- {
- "name": "symfony/polyfill-php83",
- "version": "v1.32.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php83.git",
- "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491",
- "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/polyfill",
- "name": "symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php83\\": ""
- },
- "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 backporting some PHP 8.3+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/translation-contracts",
- "version": "v3.6.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/translation-contracts.git",
- "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
- "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "url": "https://github.com/symfony/contracts",
- "name": "symfony/contracts"
- },
- "branch-alias": {
- "dev-main": "3.6-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\Translation\\": ""
- },
- "exclude-from-classmap": [
- "/Test/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to translation",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-09-27T08:32:26+00:00"
- },
- {
- "name": "symfony/validator",
- "version": "v6.4.23",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/validator.git",
- "reference": "6506760ab57e7cda5bde9cdaed736526162284bc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/validator/zipball/6506760ab57e7cda5bde9cdaed736526162284bc",
- "reference": "6506760ab57e7cda5bde9cdaed736526162284bc",
- "shasum": ""
- },
- "require": {
- "php": ">=8.1",
- "symfony/deprecation-contracts": "^2.5|^3",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php83": "^1.27",
- "symfony/translation-contracts": "^2.5|^3"
- },
- "conflict": {
- "doctrine/annotations": "<1.13",
- "doctrine/lexer": "<1.1",
- "symfony/dependency-injection": "<5.4",
- "symfony/expression-language": "<5.4",
- "symfony/http-kernel": "<5.4",
- "symfony/intl": "<5.4",
- "symfony/property-info": "<5.4",
- "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3",
- "symfony/yaml": "<5.4"
- },
- "require-dev": {
- "doctrine/annotations": "^1.13|^2",
- "egulias/email-validator": "^2.1.10|^3|^4",
- "symfony/cache": "^5.4|^6.0|^7.0",
- "symfony/config": "^5.4|^6.0|^7.0",
- "symfony/console": "^5.4|^6.0|^7.0",
- "symfony/dependency-injection": "^5.4|^6.0|^7.0",
- "symfony/expression-language": "^5.4|^6.0|^7.0",
- "symfony/finder": "^5.4|^6.0|^7.0",
- "symfony/http-client": "^5.4|^6.0|^7.0",
- "symfony/http-foundation": "^5.4|^6.0|^7.0",
- "symfony/http-kernel": "^5.4|^6.0|^7.0",
- "symfony/intl": "^5.4|^6.0|^7.0",
- "symfony/mime": "^5.4|^6.0|^7.0",
- "symfony/property-access": "^5.4|^6.0|^7.0",
- "symfony/property-info": "^5.4|^6.0|^7.0",
- "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3",
- "symfony/yaml": "^5.4|^6.0|^7.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Validator\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/",
- "/Resources/bin/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides tools to validate values",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/validator/tree/v6.4.23"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2025-06-26T07:25:45+00:00"
- }
- ],
+ "content-hash": "95a4880dc06075ff14ba2f29f9cb23b5",
+ "packages": [],
"packages-dev": [
{
"name": "clue/ndjson-react",
@@ -1684,37 +1122,85 @@
],
"type": "library",
"autoload": {
- "files": [
- "bootstrap.php"
- ]
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "keywords": [
+ "dev",
+ "static analysis"
+ ],
+ "support": {
+ "docs": "https://phpstan.org/user-guide/getting-started",
+ "forum": "https://github.com/phpstan/phpstan/discussions",
+ "issues": "https://github.com/phpstan/phpstan/issues",
+ "security": "https://github.com/phpstan/phpstan/security/policy",
+ "source": "https://github.com/phpstan/phpstan-src"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ondrejmirtes",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/phpstan",
+ "type": "github"
+ }
+ ],
+ "time": "2025-05-21T20:55:28+00:00"
+ },
+ {
+ "name": "phpstan/phpstan-strict-rules",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpstan-strict-rules.git",
+ "reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
+ "reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0",
+ "phpstan/phpstan": "^2.0.4"
+ },
+ "require-dev": {
+ "php-parallel-lint/php-parallel-lint": "^1.2",
+ "phpstan/phpstan-deprecation-rules": "^2.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpunit/phpunit": "^9.6"
+ },
+ "type": "phpstan-extension",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "rules.neon"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\": "src/"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "description": "PHPStan - PHP Static Analysis Tool",
- "keywords": [
- "dev",
- "static analysis"
- ],
+ "description": "Extra strict and opinionated rules for PHPStan",
"support": {
- "docs": "https://phpstan.org/user-guide/getting-started",
- "forum": "https://github.com/phpstan/phpstan/discussions",
- "issues": "https://github.com/phpstan/phpstan/issues",
- "security": "https://github.com/phpstan/phpstan/security/policy",
- "source": "https://github.com/phpstan/phpstan-src"
+ "issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
+ "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.4"
},
- "funding": [
- {
- "url": "https://github.com/ondrejmirtes",
- "type": "github"
- },
- {
- "url": "https://github.com/phpstan",
- "type": "github"
- }
- ],
- "time": "2025-05-21T20:55:28+00:00"
+ "time": "2025-03-18T11:42:40+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -4200,6 +3686,73 @@
],
"time": "2025-06-24T04:04:43+00:00"
},
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
{
"name": "symfony/event-dispatcher",
"version": "v7.3.0",
@@ -4553,6 +4106,85 @@
],
"time": "2025-04-04T13:12:05+00:00"
},
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.32.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.32.0",
@@ -4712,6 +4344,87 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.32.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.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-12-23T08:48:59+00:00"
+ },
{
"name": "symfony/polyfill-php80",
"version": "v1.32.0",
diff --git a/docs/worklog.md b/docs/worklog.md
index 0ae346f..8e9978d 100644
--- a/docs/worklog.md
+++ b/docs/worklog.md
@@ -259,3 +259,30 @@ These fixes improve the code quality and type safety of the library, making it m
- Code quality checks passed
These optimizations improve performance by eliminating JSON parsing overhead and implementing a lazy loading pattern that loads the registry only once per request. The removal of symfony dependencies makes the library more lightweight and self-contained.
+
+## 10. 2025-07-17: Refactor BCP47Tag library to give better results, understandable interface, exception and performace
+
+1. Refactored BCP47Tag class, changed class construction signature.
+ - Replaced $knownTags and $requireCanonical arguments with $useCanonicalMatchTags array
+ - Refactored the internals during construction of the object to better handle fallback, normalization and validation
+ (including fallback and useCanonicalMatchTags array)
+ - added public interface getLanguageTag(): LanguageTag method so you can work with even easier value object in your
+ code base,
+ - useCanonicalMatchTags is now using scoring system to match the resolved language tag to provided list
+2. ParsedTag value object is now Stringable and JsonSerializable
+3. Introducing LanguageTagβ an immutable value object that can be created only via it's own factory method and extending
+ ParsedTag so it's also stringable and json serializable
+4. BCP47Normalizer now uses auto-generated GrandfatheredTag enum to detect grandfathered tags
+5. Few modifications to BCP47Parser to more readable, throw exceptions, and handle grandfathered tags correctly
+6. Few modifications to IanaSubtagRegistry to throw exceptions, added TODO list what is missing and made code more
+ readable
+7. Resource file is now static php array instead of json file
+8. Resource file compilation how expands range tags into individual tags/subtags, uses utility function
+ expandAlphaRangeFunction()
+9. Made Exception classes with a logical flow in case something goes wrong
+10. Added phpstan/phpstan-strict-rules into composer
+11. Added `composer iana:refresh` to fetch and compile fresh source of data
+12. Some more...
+
+This version if far more ready to work great on production environments for 99.8% of the cases that might be needed :)
+While I still see the joy to work towards the goal to make the 0.2% happy as well (flex)
\ No newline at end of file
diff --git a/qatools/phpmd_ruleset.xml b/qatools/phpmd_ruleset.xml
index 4acd6ae..343939f 100644
--- a/qatools/phpmd_ruleset.xml
+++ b/qatools/phpmd_ruleset.xml
@@ -83,6 +83,7 @@
+
diff --git a/qatools/phpstan.neon b/qatools/phpstan.neon
new file mode 100644
index 0000000..ffb18e1
--- /dev/null
+++ b/qatools/phpstan.neon
@@ -0,0 +1,4 @@
+parameters:
+ level: max
+ paths:
+ - ../src
\ No newline at end of file
diff --git a/resources/iana.json b/resources/iana.json
deleted file mode 100644
index 365e042..0000000
--- a/resources/iana.json
+++ /dev/null
@@ -1,8964 +0,0 @@
-{
- "languages": [
- "aa",
- "aaa",
- "aab",
- "aac",
- "aad",
- "aae",
- "aaf",
- "aag",
- "aah",
- "aai",
- "aak",
- "aal",
- "aam",
- "aan",
- "aao",
- "aap",
- "aaq",
- "aas",
- "aat",
- "aau",
- "aav",
- "aaw",
- "aax",
- "aaz",
- "ab",
- "aba",
- "abb",
- "abc",
- "abd",
- "abe",
- "abf",
- "abg",
- "abh",
- "abi",
- "abj",
- "abl",
- "abm",
- "abn",
- "abo",
- "abp",
- "abq",
- "abr",
- "abs",
- "abt",
- "abu",
- "abv",
- "abw",
- "abx",
- "aby",
- "abz",
- "aca",
- "acb",
- "acd",
- "ace",
- "acf",
- "ach",
- "aci",
- "ack",
- "acl",
- "acm",
- "acn",
- "acp",
- "acq",
- "acr",
- "acs",
- "act",
- "acu",
- "acv",
- "acw",
- "acx",
- "acy",
- "acz",
- "ada",
- "adb",
- "add",
- "ade",
- "adf",
- "adg",
- "adh",
- "adi",
- "adj",
- "adl",
- "adn",
- "ado",
- "adp",
- "adq",
- "adr",
- "ads",
- "adt",
- "adu",
- "adw",
- "adx",
- "ady",
- "adz",
- "ae",
- "aea",
- "aeb",
- "aec",
- "aed",
- "aee",
- "aek",
- "ael",
- "aem",
- "aen",
- "aeq",
- "aer",
- "aes",
- "aeu",
- "aew",
- "aey",
- "aez",
- "af",
- "afa",
- "afb",
- "afd",
- "afe",
- "afg",
- "afh",
- "afi",
- "afk",
- "afn",
- "afo",
- "afp",
- "afs",
- "aft",
- "afu",
- "afz",
- "aga",
- "agb",
- "agc",
- "agd",
- "age",
- "agf",
- "agg",
- "agh",
- "agi",
- "agj",
- "agk",
- "agl",
- "agm",
- "agn",
- "ago",
- "agp",
- "agq",
- "agr",
- "ags",
- "agt",
- "agu",
- "agv",
- "agw",
- "agx",
- "agy",
- "agz",
- "aha",
- "ahb",
- "ahg",
- "ahh",
- "ahi",
- "ahk",
- "ahl",
- "ahm",
- "ahn",
- "aho",
- "ahp",
- "ahr",
- "ahs",
- "aht",
- "aia",
- "aib",
- "aic",
- "aid",
- "aie",
- "aif",
- "aig",
- "aih",
- "aii",
- "aij",
- "aik",
- "ail",
- "aim",
- "ain",
- "aio",
- "aip",
- "aiq",
- "air",
- "ais",
- "ait",
- "aiw",
- "aix",
- "aiy",
- "aja",
- "ajg",
- "aji",
- "ajn",
- "ajp",
- "ajs",
- "ajt",
- "aju",
- "ajw",
- "ajz",
- "ak",
- "akb",
- "akc",
- "akd",
- "ake",
- "akf",
- "akg",
- "akh",
- "aki",
- "akj",
- "akk",
- "akl",
- "akm",
- "ako",
- "akp",
- "akq",
- "akr",
- "aks",
- "akt",
- "aku",
- "akv",
- "akw",
- "akx",
- "aky",
- "akz",
- "ala",
- "alc",
- "ald",
- "ale",
- "alf",
- "alg",
- "alh",
- "ali",
- "alj",
- "alk",
- "all",
- "alm",
- "aln",
- "alo",
- "alp",
- "alq",
- "alr",
- "als",
- "alt",
- "alu",
- "alv",
- "alw",
- "alx",
- "aly",
- "alz",
- "am",
- "ama",
- "amb",
- "amc",
- "ame",
- "amf",
- "amg",
- "ami",
- "amj",
- "amk",
- "aml",
- "amm",
- "amn",
- "amo",
- "amp",
- "amq",
- "amr",
- "ams",
- "amt",
- "amu",
- "amv",
- "amw",
- "amx",
- "amy",
- "amz",
- "an",
- "ana",
- "anb",
- "anc",
- "and",
- "ane",
- "anf",
- "ang",
- "anh",
- "ani",
- "anj",
- "ank",
- "anl",
- "anm",
- "ann",
- "ano",
- "anp",
- "anq",
- "anr",
- "ans",
- "ant",
- "anu",
- "anv",
- "anw",
- "anx",
- "any",
- "anz",
- "aoa",
- "aob",
- "aoc",
- "aod",
- "aoe",
- "aof",
- "aog",
- "aoh",
- "aoi",
- "aoj",
- "aok",
- "aol",
- "aom",
- "aon",
- "aor",
- "aos",
- "aot",
- "aou",
- "aox",
- "aoz",
- "apa",
- "apb",
- "apc",
- "apd",
- "ape",
- "apf",
- "apg",
- "aph",
- "api",
- "apj",
- "apk",
- "apl",
- "apm",
- "apn",
- "apo",
- "app",
- "apq",
- "apr",
- "aps",
- "apt",
- "apu",
- "apv",
- "apw",
- "apx",
- "apy",
- "apz",
- "aqa",
- "aqc",
- "aqd",
- "aqg",
- "aqk",
- "aql",
- "aqm",
- "aqn",
- "aqp",
- "aqr",
- "aqt",
- "aqz",
- "ar",
- "arb",
- "arc",
- "ard",
- "are",
- "arh",
- "ari",
- "arj",
- "ark",
- "arl",
- "arn",
- "aro",
- "arp",
- "arq",
- "arr",
- "ars",
- "art",
- "aru",
- "arv",
- "arw",
- "arx",
- "ary",
- "arz",
- "as",
- "asa",
- "asb",
- "asc",
- "asd",
- "ase",
- "asf",
- "asg",
- "ash",
- "asi",
- "asj",
- "ask",
- "asl",
- "asn",
- "aso",
- "asp",
- "asq",
- "asr",
- "ass",
- "ast",
- "asu",
- "asv",
- "asw",
- "asx",
- "asy",
- "asz",
- "ata",
- "atb",
- "atc",
- "atd",
- "ate",
- "atg",
- "ath",
- "ati",
- "atj",
- "atk",
- "atl",
- "atm",
- "atn",
- "ato",
- "atp",
- "atq",
- "atr",
- "ats",
- "att",
- "atu",
- "atv",
- "atw",
- "atx",
- "aty",
- "atz",
- "aua",
- "aub",
- "auc",
- "aud",
- "aue",
- "auf",
- "aug",
- "auh",
- "aui",
- "auj",
- "auk",
- "aul",
- "aum",
- "aun",
- "auo",
- "aup",
- "auq",
- "aur",
- "aus",
- "aut",
- "auu",
- "auw",
- "aux",
- "auy",
- "auz",
- "av",
- "avb",
- "avd",
- "avi",
- "avk",
- "avl",
- "avm",
- "avn",
- "avo",
- "avs",
- "avt",
- "avu",
- "avv",
- "awa",
- "awb",
- "awc",
- "awd",
- "awe",
- "awg",
- "awh",
- "awi",
- "awk",
- "awm",
- "awn",
- "awo",
- "awr",
- "aws",
- "awt",
- "awu",
- "awv",
- "aww",
- "awx",
- "awy",
- "axb",
- "axe",
- "axg",
- "axk",
- "axl",
- "axm",
- "axx",
- "ay",
- "aya",
- "ayb",
- "ayc",
- "ayd",
- "aye",
- "ayg",
- "ayh",
- "ayi",
- "ayk",
- "ayl",
- "ayn",
- "ayo",
- "ayp",
- "ayq",
- "ayr",
- "ays",
- "ayt",
- "ayu",
- "ayx",
- "ayy",
- "ayz",
- "az",
- "aza",
- "azb",
- "azc",
- "azd",
- "azg",
- "azj",
- "azm",
- "azn",
- "azo",
- "azt",
- "azz",
- "ba",
- "baa",
- "bab",
- "bac",
- "bad",
- "bae",
- "baf",
- "bag",
- "bah",
- "bai",
- "baj",
- "bal",
- "ban",
- "bao",
- "bap",
- "bar",
- "bas",
- "bat",
- "bau",
- "bav",
- "baw",
- "bax",
- "bay",
- "baz",
- "bba",
- "bbb",
- "bbc",
- "bbd",
- "bbe",
- "bbf",
- "bbg",
- "bbh",
- "bbi",
- "bbj",
- "bbk",
- "bbl",
- "bbm",
- "bbn",
- "bbo",
- "bbp",
- "bbq",
- "bbr",
- "bbs",
- "bbt",
- "bbu",
- "bbv",
- "bbw",
- "bbx",
- "bby",
- "bbz",
- "bca",
- "bcb",
- "bcc",
- "bcd",
- "bce",
- "bcf",
- "bcg",
- "bch",
- "bci",
- "bcj",
- "bck",
- "bcl",
- "bcm",
- "bcn",
- "bco",
- "bcp",
- "bcq",
- "bcr",
- "bcs",
- "bct",
- "bcu",
- "bcv",
- "bcw",
- "bcy",
- "bcz",
- "bda",
- "bdb",
- "bdc",
- "bdd",
- "bde",
- "bdf",
- "bdg",
- "bdh",
- "bdi",
- "bdj",
- "bdk",
- "bdl",
- "bdm",
- "bdn",
- "bdo",
- "bdp",
- "bdq",
- "bdr",
- "bds",
- "bdt",
- "bdu",
- "bdv",
- "bdw",
- "bdx",
- "bdy",
- "bdz",
- "be",
- "bea",
- "beb",
- "bec",
- "bed",
- "bee",
- "bef",
- "beg",
- "beh",
- "bei",
- "bej",
- "bek",
- "bem",
- "beo",
- "bep",
- "beq",
- "ber",
- "bes",
- "bet",
- "beu",
- "bev",
- "bew",
- "bex",
- "bey",
- "bez",
- "bfa",
- "bfb",
- "bfc",
- "bfd",
- "bfe",
- "bff",
- "bfg",
- "bfh",
- "bfi",
- "bfj",
- "bfk",
- "bfl",
- "bfm",
- "bfn",
- "bfo",
- "bfp",
- "bfq",
- "bfr",
- "bfs",
- "bft",
- "bfu",
- "bfw",
- "bfx",
- "bfy",
- "bfz",
- "bg",
- "bga",
- "bgb",
- "bgc",
- "bgd",
- "bge",
- "bgf",
- "bgg",
- "bgi",
- "bgj",
- "bgk",
- "bgl",
- "bgm",
- "bgn",
- "bgo",
- "bgp",
- "bgq",
- "bgr",
- "bgs",
- "bgt",
- "bgu",
- "bgv",
- "bgw",
- "bgx",
- "bgy",
- "bgz",
- "bh",
- "bha",
- "bhb",
- "bhc",
- "bhd",
- "bhe",
- "bhf",
- "bhg",
- "bhh",
- "bhi",
- "bhj",
- "bhk",
- "bhl",
- "bhm",
- "bhn",
- "bho",
- "bhp",
- "bhq",
- "bhr",
- "bhs",
- "bht",
- "bhu",
- "bhv",
- "bhw",
- "bhx",
- "bhy",
- "bhz",
- "bi",
- "bia",
- "bib",
- "bic",
- "bid",
- "bie",
- "bif",
- "big",
- "bij",
- "bik",
- "bil",
- "bim",
- "bin",
- "bio",
- "bip",
- "biq",
- "bir",
- "bit",
- "biu",
- "biv",
- "biw",
- "bix",
- "biy",
- "biz",
- "bja",
- "bjb",
- "bjc",
- "bjd",
- "bje",
- "bjf",
- "bjg",
- "bjh",
- "bji",
- "bjj",
- "bjk",
- "bjl",
- "bjm",
- "bjn",
- "bjo",
- "bjp",
- "bjq",
- "bjr",
- "bjs",
- "bjt",
- "bju",
- "bjv",
- "bjw",
- "bjx",
- "bjy",
- "bjz",
- "bka",
- "bkb",
- "bkc",
- "bkd",
- "bkf",
- "bkg",
- "bkh",
- "bki",
- "bkj",
- "bkk",
- "bkl",
- "bkm",
- "bkn",
- "bko",
- "bkp",
- "bkq",
- "bkr",
- "bks",
- "bkt",
- "bku",
- "bkv",
- "bkw",
- "bkx",
- "bky",
- "bkz",
- "bla",
- "blb",
- "blc",
- "bld",
- "ble",
- "blf",
- "blg",
- "blh",
- "bli",
- "blj",
- "blk",
- "bll",
- "blm",
- "bln",
- "blo",
- "blp",
- "blq",
- "blr",
- "bls",
- "blt",
- "blv",
- "blw",
- "blx",
- "bly",
- "blz",
- "bm",
- "bma",
- "bmb",
- "bmc",
- "bmd",
- "bme",
- "bmf",
- "bmg",
- "bmh",
- "bmi",
- "bmj",
- "bmk",
- "bml",
- "bmm",
- "bmn",
- "bmo",
- "bmp",
- "bmq",
- "bmr",
- "bms",
- "bmt",
- "bmu",
- "bmv",
- "bmw",
- "bmx",
- "bmy",
- "bmz",
- "bn",
- "bna",
- "bnb",
- "bnc",
- "bnd",
- "bne",
- "bnf",
- "bng",
- "bni",
- "bnj",
- "bnk",
- "bnl",
- "bnm",
- "bnn",
- "bno",
- "bnp",
- "bnq",
- "bnr",
- "bns",
- "bnt",
- "bnu",
- "bnv",
- "bnw",
- "bnx",
- "bny",
- "bnz",
- "bo",
- "boa",
- "bob",
- "boe",
- "bof",
- "bog",
- "boh",
- "boi",
- "boj",
- "bok",
- "bol",
- "bom",
- "bon",
- "boo",
- "bop",
- "boq",
- "bor",
- "bot",
- "bou",
- "bov",
- "bow",
- "box",
- "boy",
- "boz",
- "bpa",
- "bpb",
- "bpc",
- "bpd",
- "bpe",
- "bpg",
- "bph",
- "bpi",
- "bpj",
- "bpk",
- "bpl",
- "bpm",
- "bpn",
- "bpo",
- "bpp",
- "bpq",
- "bpr",
- "bps",
- "bpt",
- "bpu",
- "bpv",
- "bpw",
- "bpx",
- "bpy",
- "bpz",
- "bqa",
- "bqb",
- "bqc",
- "bqd",
- "bqf",
- "bqg",
- "bqh",
- "bqi",
- "bqj",
- "bqk",
- "bql",
- "bqm",
- "bqn",
- "bqo",
- "bqp",
- "bqq",
- "bqr",
- "bqs",
- "bqt",
- "bqu",
- "bqv",
- "bqw",
- "bqx",
- "bqy",
- "bqz",
- "br",
- "bra",
- "brb",
- "brc",
- "brd",
- "brf",
- "brg",
- "brh",
- "bri",
- "brj",
- "brk",
- "brl",
- "brm",
- "brn",
- "bro",
- "brp",
- "brq",
- "brr",
- "brs",
- "brt",
- "bru",
- "brv",
- "brw",
- "brx",
- "bry",
- "brz",
- "bs",
- "bsa",
- "bsb",
- "bsc",
- "bse",
- "bsf",
- "bsg",
- "bsh",
- "bsi",
- "bsj",
- "bsk",
- "bsl",
- "bsm",
- "bsn",
- "bso",
- "bsp",
- "bsq",
- "bsr",
- "bss",
- "bst",
- "bsu",
- "bsv",
- "bsw",
- "bsx",
- "bsy",
- "bta",
- "btb",
- "btc",
- "btd",
- "bte",
- "btf",
- "btg",
- "bth",
- "bti",
- "btj",
- "btk",
- "btl",
- "btm",
- "btn",
- "bto",
- "btp",
- "btq",
- "btr",
- "bts",
- "btt",
- "btu",
- "btv",
- "btw",
- "btx",
- "bty",
- "btz",
- "bua",
- "bub",
- "buc",
- "bud",
- "bue",
- "buf",
- "bug",
- "buh",
- "bui",
- "buj",
- "buk",
- "bum",
- "bun",
- "buo",
- "bup",
- "buq",
- "bus",
- "but",
- "buu",
- "buv",
- "buw",
- "bux",
- "buy",
- "buz",
- "bva",
- "bvb",
- "bvc",
- "bvd",
- "bve",
- "bvf",
- "bvg",
- "bvh",
- "bvi",
- "bvj",
- "bvk",
- "bvl",
- "bvm",
- "bvn",
- "bvo",
- "bvp",
- "bvq",
- "bvr",
- "bvt",
- "bvu",
- "bvv",
- "bvw",
- "bvx",
- "bvy",
- "bvz",
- "bwa",
- "bwb",
- "bwc",
- "bwd",
- "bwe",
- "bwf",
- "bwg",
- "bwh",
- "bwi",
- "bwj",
- "bwk",
- "bwl",
- "bwm",
- "bwn",
- "bwo",
- "bwp",
- "bwq",
- "bwr",
- "bws",
- "bwt",
- "bwu",
- "bww",
- "bwx",
- "bwy",
- "bwz",
- "bxa",
- "bxb",
- "bxc",
- "bxd",
- "bxe",
- "bxf",
- "bxg",
- "bxh",
- "bxi",
- "bxj",
- "bxk",
- "bxl",
- "bxm",
- "bxn",
- "bxo",
- "bxp",
- "bxq",
- "bxr",
- "bxs",
- "bxu",
- "bxv",
- "bxw",
- "bxx",
- "bxz",
- "bya",
- "byb",
- "byc",
- "byd",
- "bye",
- "byf",
- "byg",
- "byh",
- "byi",
- "byj",
- "byk",
- "byl",
- "bym",
- "byn",
- "byo",
- "byp",
- "byq",
- "byr",
- "bys",
- "byt",
- "byv",
- "byw",
- "byx",
- "byy",
- "byz",
- "bza",
- "bzb",
- "bzc",
- "bzd",
- "bze",
- "bzf",
- "bzg",
- "bzh",
- "bzi",
- "bzj",
- "bzk",
- "bzl",
- "bzm",
- "bzn",
- "bzo",
- "bzp",
- "bzq",
- "bzr",
- "bzs",
- "bzt",
- "bzu",
- "bzv",
- "bzw",
- "bzx",
- "bzy",
- "bzz",
- "ca",
- "caa",
- "cab",
- "cac",
- "cad",
- "cae",
- "caf",
- "cag",
- "cah",
- "cai",
- "caj",
- "cak",
- "cal",
- "cam",
- "can",
- "cao",
- "cap",
- "caq",
- "car",
- "cas",
- "cau",
- "cav",
- "caw",
- "cax",
- "cay",
- "caz",
- "cba",
- "cbb",
- "cbc",
- "cbd",
- "cbe",
- "cbg",
- "cbh",
- "cbi",
- "cbj",
- "cbk",
- "cbl",
- "cbn",
- "cbo",
- "cbq",
- "cbr",
- "cbs",
- "cbt",
- "cbu",
- "cbv",
- "cbw",
- "cby",
- "cca",
- "ccc",
- "ccd",
- "cce",
- "ccg",
- "cch",
- "ccj",
- "ccl",
- "ccm",
- "ccn",
- "cco",
- "ccp",
- "ccq",
- "ccr",
- "ccs",
- "cda",
- "cdc",
- "cdd",
- "cde",
- "cdf",
- "cdg",
- "cdh",
- "cdi",
- "cdj",
- "cdm",
- "cdn",
- "cdo",
- "cdr",
- "cds",
- "cdy",
- "cdz",
- "ce",
- "cea",
- "ceb",
- "ceg",
- "cek",
- "cel",
- "cen",
- "cet",
- "cey",
- "cfa",
- "cfd",
- "cfg",
- "cfm",
- "cga",
- "cgc",
- "cgg",
- "cgk",
- "ch",
- "chb",
- "chc",
- "chd",
- "chf",
- "chg",
- "chh",
- "chj",
- "chk",
- "chl",
- "chm",
- "chn",
- "cho",
- "chp",
- "chq",
- "chr",
- "cht",
- "chw",
- "chx",
- "chy",
- "chz",
- "cia",
- "cib",
- "cic",
- "cid",
- "cie",
- "cih",
- "cik",
- "cim",
- "cin",
- "cip",
- "cir",
- "ciw",
- "ciy",
- "cja",
- "cje",
- "cjh",
- "cji",
- "cjk",
- "cjm",
- "cjn",
- "cjo",
- "cjp",
- "cjr",
- "cjs",
- "cjv",
- "cjy",
- "cka",
- "ckb",
- "ckh",
- "ckl",
- "ckm",
- "ckn",
- "cko",
- "ckq",
- "ckr",
- "cks",
- "ckt",
- "cku",
- "ckv",
- "ckx",
- "cky",
- "ckz",
- "cla",
- "clc",
- "cld",
- "cle",
- "clh",
- "cli",
- "clj",
- "clk",
- "cll",
- "clm",
- "clo",
- "cls",
- "clt",
- "clu",
- "clw",
- "cly",
- "cma",
- "cmc",
- "cme",
- "cmg",
- "cmi",
- "cmk",
- "cml",
- "cmm",
- "cmn",
- "cmo",
- "cmr",
- "cms",
- "cmt",
- "cna",
- "cnb",
- "cnc",
- "cng",
- "cnh",
- "cni",
- "cnk",
- "cnl",
- "cno",
- "cnp",
- "cnq",
- "cnr",
- "cns",
- "cnt",
- "cnu",
- "cnw",
- "cnx",
- "co",
- "coa",
- "cob",
- "coc",
- "cod",
- "coe",
- "cof",
- "cog",
- "coh",
- "coj",
- "cok",
- "col",
- "com",
- "con",
- "coo",
- "cop",
- "coq",
- "cot",
- "cou",
- "cov",
- "cow",
- "cox",
- "coy",
- "coz",
- "cpa",
- "cpb",
- "cpc",
- "cpe",
- "cpf",
- "cpg",
- "cpi",
- "cpn",
- "cpo",
- "cpp",
- "cps",
- "cpu",
- "cpx",
- "cpy",
- "cqd",
- "cqu",
- "cr",
- "cra",
- "crb",
- "crc",
- "crd",
- "crf",
- "crg",
- "crh",
- "cri",
- "crj",
- "crk",
- "crl",
- "crm",
- "crn",
- "cro",
- "crp",
- "crq",
- "crr",
- "crs",
- "crt",
- "crv",
- "crw",
- "crx",
- "cry",
- "crz",
- "cs",
- "csa",
- "csb",
- "csc",
- "csd",
- "cse",
- "csf",
- "csg",
- "csh",
- "csi",
- "csj",
- "csk",
- "csl",
- "csm",
- "csn",
- "cso",
- "csp",
- "csq",
- "csr",
- "css",
- "cst",
- "csu",
- "csv",
- "csw",
- "csx",
- "csy",
- "csz",
- "cta",
- "ctc",
- "ctd",
- "cte",
- "ctg",
- "cth",
- "ctl",
- "ctm",
- "ctn",
- "cto",
- "ctp",
- "cts",
- "ctt",
- "ctu",
- "cty",
- "ctz",
- "cu",
- "cua",
- "cub",
- "cuc",
- "cug",
- "cuh",
- "cui",
- "cuj",
- "cuk",
- "cul",
- "cum",
- "cuo",
- "cup",
- "cuq",
- "cur",
- "cus",
- "cut",
- "cuu",
- "cuv",
- "cuw",
- "cux",
- "cuy",
- "cv",
- "cvg",
- "cvn",
- "cwa",
- "cwb",
- "cwd",
- "cwe",
- "cwg",
- "cwt",
- "cxh",
- "cy",
- "cya",
- "cyb",
- "cyo",
- "czh",
- "czk",
- "czn",
- "czo",
- "czt",
- "da",
- "daa",
- "dac",
- "dad",
- "dae",
- "daf",
- "dag",
- "dah",
- "dai",
- "daj",
- "dak",
- "dal",
- "dam",
- "dao",
- "dap",
- "daq",
- "dar",
- "das",
- "dau",
- "dav",
- "daw",
- "dax",
- "day",
- "daz",
- "dba",
- "dbb",
- "dbd",
- "dbe",
- "dbf",
- "dbg",
- "dbi",
- "dbj",
- "dbl",
- "dbm",
- "dbn",
- "dbo",
- "dbp",
- "dbq",
- "dbr",
- "dbt",
- "dbu",
- "dbv",
- "dbw",
- "dby",
- "dcc",
- "dcr",
- "dda",
- "ddd",
- "dde",
- "ddg",
- "ddi",
- "ddj",
- "ddn",
- "ddo",
- "ddr",
- "dds",
- "ddw",
- "de",
- "dec",
- "ded",
- "dee",
- "def",
- "deg",
- "deh",
- "dei",
- "dek",
- "del",
- "dem",
- "den",
- "dep",
- "deq",
- "der",
- "des",
- "dev",
- "dez",
- "dga",
- "dgb",
- "dgc",
- "dgd",
- "dge",
- "dgg",
- "dgh",
- "dgi",
- "dgk",
- "dgl",
- "dgn",
- "dgo",
- "dgr",
- "dgs",
- "dgt",
- "dgu",
- "dgw",
- "dgx",
- "dgz",
- "dha",
- "dhd",
- "dhg",
- "dhi",
- "dhl",
- "dhm",
- "dhn",
- "dho",
- "dhr",
- "dhs",
- "dhu",
- "dhv",
- "dhw",
- "dhx",
- "dia",
- "dib",
- "dic",
- "did",
- "dif",
- "dig",
- "dih",
- "dii",
- "dij",
- "dik",
- "dil",
- "dim",
- "din",
- "dio",
- "dip",
- "diq",
- "dir",
- "dis",
- "dit",
- "diu",
- "diw",
- "dix",
- "diy",
- "diz",
- "dja",
- "djb",
- "djc",
- "djd",
- "dje",
- "djf",
- "dji",
- "djj",
- "djk",
- "djl",
- "djm",
- "djn",
- "djo",
- "djr",
- "dju",
- "djw",
- "dka",
- "dkg",
- "dkk",
- "dkl",
- "dkr",
- "dks",
- "dkx",
- "dlg",
- "dlk",
- "dlm",
- "dln",
- "dma",
- "dmb",
- "dmc",
- "dmd",
- "dme",
- "dmf",
- "dmg",
- "dmk",
- "dml",
- "dmm",
- "dmn",
- "dmo",
- "dmr",
- "dms",
- "dmu",
- "dmv",
- "dmw",
- "dmx",
- "dmy",
- "dna",
- "dnd",
- "dne",
- "dng",
- "dni",
- "dnj",
- "dnk",
- "dnn",
- "dno",
- "dnr",
- "dnt",
- "dnu",
- "dnv",
- "dnw",
- "dny",
- "doa",
- "dob",
- "doc",
- "doe",
- "dof",
- "doh",
- "doi",
- "dok",
- "dol",
- "don",
- "doo",
- "dop",
- "doq",
- "dor",
- "dos",
- "dot",
- "dov",
- "dow",
- "dox",
- "doy",
- "doz",
- "dpp",
- "dra",
- "drb",
- "drc",
- "drd",
- "dre",
- "drg",
- "drh",
- "dri",
- "drl",
- "drn",
- "dro",
- "drq",
- "drr",
- "drs",
- "drt",
- "dru",
- "drw",
- "dry",
- "dsb",
- "dse",
- "dsh",
- "dsi",
- "dsk",
- "dsl",
- "dsn",
- "dso",
- "dsq",
- "dsz",
- "dta",
- "dtb",
- "dtd",
- "dth",
- "dti",
- "dtk",
- "dtm",
- "dtn",
- "dto",
- "dtp",
- "dtr",
- "dts",
- "dtt",
- "dtu",
- "dty",
- "dua",
- "dub",
- "duc",
- "dud",
- "due",
- "duf",
- "dug",
- "duh",
- "dui",
- "duj",
- "duk",
- "dul",
- "dum",
- "dun",
- "duo",
- "dup",
- "duq",
- "dur",
- "dus",
- "duu",
- "duv",
- "duw",
- "dux",
- "duy",
- "duz",
- "dv",
- "dva",
- "dwa",
- "dwk",
- "dwl",
- "dwr",
- "dws",
- "dwu",
- "dww",
- "dwy",
- "dwz",
- "dya",
- "dyb",
- "dyd",
- "dyg",
- "dyi",
- "dym",
- "dyn",
- "dyo",
- "dyr",
- "dyu",
- "dyy",
- "dz",
- "dza",
- "dzd",
- "dze",
- "dzg",
- "dzl",
- "dzn",
- "eaa",
- "ebc",
- "ebg",
- "ebk",
- "ebo",
- "ebr",
- "ebu",
- "ecr",
- "ecs",
- "ecy",
- "ee",
- "eee",
- "efa",
- "efe",
- "efi",
- "ega",
- "egl",
- "egm",
- "ego",
- "egx",
- "egy",
- "ehs",
- "ehu",
- "eip",
- "eit",
- "eiv",
- "eja",
- "eka",
- "ekc",
- "eke",
- "ekg",
- "eki",
- "ekk",
- "ekl",
- "ekm",
- "eko",
- "ekp",
- "ekr",
- "eky",
- "el",
- "ele",
- "elh",
- "eli",
- "elk",
- "elm",
- "elo",
- "elp",
- "elu",
- "elx",
- "ema",
- "emb",
- "eme",
- "emg",
- "emi",
- "emk",
- "emm",
- "emn",
- "emo",
- "emp",
- "emq",
- "ems",
- "emu",
- "emw",
- "emx",
- "emy",
- "emz",
- "en",
- "ena",
- "enb",
- "enc",
- "end",
- "enf",
- "enh",
- "enl",
- "enm",
- "enn",
- "eno",
- "enq",
- "enr",
- "enu",
- "env",
- "enw",
- "enx",
- "eo",
- "eot",
- "epi",
- "era",
- "erg",
- "erh",
- "eri",
- "erk",
- "ero",
- "err",
- "ers",
- "ert",
- "erw",
- "es",
- "ese",
- "esg",
- "esh",
- "esi",
- "esk",
- "esl",
- "esm",
- "esn",
- "eso",
- "esq",
- "ess",
- "esu",
- "esx",
- "esy",
- "et",
- "etb",
- "etc",
- "eth",
- "etn",
- "eto",
- "etr",
- "ets",
- "ett",
- "etu",
- "etx",
- "etz",
- "eu",
- "eud",
- "euq",
- "eve",
- "evh",
- "evn",
- "ewo",
- "ext",
- "eya",
- "eyo",
- "eza",
- "eze",
- "fa",
- "faa",
- "fab",
- "fad",
- "faf",
- "fag",
- "fah",
- "fai",
- "faj",
- "fak",
- "fal",
- "fam",
- "fan",
- "fap",
- "far",
- "fat",
- "fau",
- "fax",
- "fay",
- "faz",
- "fbl",
- "fcs",
- "fer",
- "ff",
- "ffi",
- "ffm",
- "fgr",
- "fi",
- "fia",
- "fie",
- "fif",
- "fil",
- "fip",
- "fir",
- "fit",
- "fiu",
- "fiw",
- "fj",
- "fkk",
- "fkv",
- "fla",
- "flh",
- "fli",
- "fll",
- "fln",
- "flr",
- "fly",
- "fmp",
- "fmu",
- "fnb",
- "fng",
- "fni",
- "fo",
- "fod",
- "foi",
- "fom",
- "fon",
- "for",
- "fos",
- "fox",
- "fpe",
- "fqs",
- "fr",
- "frc",
- "frd",
- "frk",
- "frm",
- "fro",
- "frp",
- "frq",
- "frr",
- "frs",
- "frt",
- "fse",
- "fsl",
- "fss",
- "fub",
- "fuc",
- "fud",
- "fue",
- "fuf",
- "fuh",
- "fui",
- "fuj",
- "fum",
- "fun",
- "fuq",
- "fur",
- "fut",
- "fuu",
- "fuv",
- "fuy",
- "fvr",
- "fwa",
- "fwe",
- "fy",
- "ga",
- "gaa",
- "gab",
- "gac",
- "gad",
- "gae",
- "gaf",
- "gag",
- "gah",
- "gai",
- "gaj",
- "gak",
- "gal",
- "gam",
- "gan",
- "gao",
- "gap",
- "gaq",
- "gar",
- "gas",
- "gat",
- "gau",
- "gav",
- "gaw",
- "gax",
- "gay",
- "gaz",
- "gba",
- "gbb",
- "gbc",
- "gbd",
- "gbe",
- "gbf",
- "gbg",
- "gbh",
- "gbi",
- "gbj",
- "gbk",
- "gbl",
- "gbm",
- "gbn",
- "gbo",
- "gbp",
- "gbq",
- "gbr",
- "gbs",
- "gbu",
- "gbv",
- "gbw",
- "gbx",
- "gby",
- "gbz",
- "gcc",
- "gcd",
- "gce",
- "gcf",
- "gcl",
- "gcn",
- "gcr",
- "gct",
- "gd",
- "gda",
- "gdb",
- "gdc",
- "gdd",
- "gde",
- "gdf",
- "gdg",
- "gdh",
- "gdi",
- "gdj",
- "gdk",
- "gdl",
- "gdm",
- "gdn",
- "gdo",
- "gdq",
- "gdr",
- "gds",
- "gdt",
- "gdu",
- "gdx",
- "gea",
- "geb",
- "gec",
- "ged",
- "gef",
- "geg",
- "geh",
- "gei",
- "gej",
- "gek",
- "gel",
- "gem",
- "geq",
- "ges",
- "gev",
- "gew",
- "gex",
- "gey",
- "gez",
- "gfk",
- "gft",
- "gfx",
- "gga",
- "ggb",
- "ggd",
- "gge",
- "ggg",
- "ggk",
- "ggl",
- "ggn",
- "ggo",
- "ggr",
- "ggt",
- "ggu",
- "ggw",
- "gha",
- "ghc",
- "ghe",
- "ghh",
- "ghk",
- "ghl",
- "ghn",
- "gho",
- "ghr",
- "ghs",
- "ght",
- "gia",
- "gib",
- "gic",
- "gid",
- "gie",
- "gig",
- "gih",
- "gii",
- "gil",
- "gim",
- "gin",
- "gio",
- "gip",
- "giq",
- "gir",
- "gis",
- "git",
- "giu",
- "giw",
- "gix",
- "giy",
- "giz",
- "gji",
- "gjk",
- "gjm",
- "gjn",
- "gjr",
- "gju",
- "gka",
- "gkd",
- "gke",
- "gkn",
- "gko",
- "gkp",
- "gku",
- "gl",
- "glb",
- "glc",
- "gld",
- "glh",
- "gli",
- "glj",
- "glk",
- "gll",
- "glo",
- "glr",
- "glu",
- "glw",
- "gly",
- "gma",
- "gmb",
- "gmd",
- "gme",
- "gmg",
- "gmh",
- "gml",
- "gmm",
- "gmn",
- "gmq",
- "gmr",
- "gmu",
- "gmv",
- "gmw",
- "gmx",
- "gmy",
- "gmz",
- "gn",
- "gna",
- "gnb",
- "gnc",
- "gnd",
- "gne",
- "gng",
- "gnh",
- "gni",
- "gnj",
- "gnk",
- "gnl",
- "gnm",
- "gnn",
- "gno",
- "gnq",
- "gnr",
- "gnt",
- "gnu",
- "gnw",
- "gnz",
- "goa",
- "gob",
- "goc",
- "god",
- "goe",
- "gof",
- "gog",
- "goh",
- "goi",
- "goj",
- "gok",
- "gol",
- "gom",
- "gon",
- "goo",
- "gop",
- "goq",
- "gor",
- "gos",
- "got",
- "gou",
- "gov",
- "gow",
- "gox",
- "goy",
- "goz",
- "gpa",
- "gpe",
- "gpn",
- "gqa",
- "gqi",
- "gqn",
- "gqr",
- "gqu",
- "gra",
- "grb",
- "grc",
- "grd",
- "grg",
- "grh",
- "gri",
- "grj",
- "grk",
- "grm",
- "gro",
- "grq",
- "grr",
- "grs",
- "grt",
- "gru",
- "grv",
- "grw",
- "grx",
- "gry",
- "grz",
- "gse",
- "gsg",
- "gsl",
- "gsm",
- "gsn",
- "gso",
- "gsp",
- "gss",
- "gsw",
- "gta",
- "gti",
- "gtu",
- "gu",
- "gua",
- "gub",
- "guc",
- "gud",
- "gue",
- "guf",
- "gug",
- "guh",
- "gui",
- "guk",
- "gul",
- "gum",
- "gun",
- "guo",
- "gup",
- "guq",
- "gur",
- "gus",
- "gut",
- "guu",
- "guv",
- "guw",
- "gux",
- "guz",
- "gv",
- "gva",
- "gvc",
- "gve",
- "gvf",
- "gvj",
- "gvl",
- "gvm",
- "gvn",
- "gvo",
- "gvp",
- "gvr",
- "gvs",
- "gvy",
- "gwa",
- "gwb",
- "gwc",
- "gwd",
- "gwe",
- "gwf",
- "gwg",
- "gwi",
- "gwj",
- "gwm",
- "gwn",
- "gwr",
- "gwt",
- "gwu",
- "gww",
- "gwx",
- "gxx",
- "gya",
- "gyb",
- "gyd",
- "gye",
- "gyf",
- "gyg",
- "gyi",
- "gyl",
- "gym",
- "gyn",
- "gyo",
- "gyr",
- "gyy",
- "gyz",
- "gza",
- "gzi",
- "gzn",
- "ha",
- "haa",
- "hab",
- "hac",
- "had",
- "hae",
- "haf",
- "hag",
- "hah",
- "hai",
- "haj",
- "hak",
- "hal",
- "ham",
- "han",
- "hao",
- "hap",
- "haq",
- "har",
- "has",
- "hav",
- "haw",
- "hax",
- "hay",
- "haz",
- "hba",
- "hbb",
- "hbn",
- "hbo",
- "hbu",
- "hca",
- "hch",
- "hdn",
- "hds",
- "hdy",
- "he",
- "hea",
- "hed",
- "heg",
- "heh",
- "hei",
- "hem",
- "hgm",
- "hgw",
- "hhi",
- "hhr",
- "hhy",
- "hi",
- "hia",
- "hib",
- "hid",
- "hif",
- "hig",
- "hih",
- "hii",
- "hij",
- "hik",
- "hil",
- "him",
- "hio",
- "hir",
- "hit",
- "hiw",
- "hix",
- "hji",
- "hka",
- "hke",
- "hkh",
- "hkk",
- "hkn",
- "hks",
- "hla",
- "hlb",
- "hld",
- "hle",
- "hlt",
- "hlu",
- "hma",
- "hmb",
- "hmc",
- "hmd",
- "hme",
- "hmf",
- "hmg",
- "hmh",
- "hmi",
- "hmj",
- "hmk",
- "hml",
- "hmm",
- "hmn",
- "hmp",
- "hmq",
- "hmr",
- "hms",
- "hmt",
- "hmu",
- "hmv",
- "hmw",
- "hmx",
- "hmy",
- "hmz",
- "hna",
- "hnd",
- "hne",
- "hng",
- "hnh",
- "hni",
- "hnj",
- "hnm",
- "hnn",
- "hno",
- "hns",
- "hnu",
- "ho",
- "hoa",
- "hob",
- "hoc",
- "hod",
- "hoe",
- "hoh",
- "hoi",
- "hoj",
- "hok",
- "hol",
- "hom",
- "hoo",
- "hop",
- "hor",
- "hos",
- "hot",
- "hov",
- "how",
- "hoy",
- "hoz",
- "hpo",
- "hps",
- "hr",
- "hra",
- "hrc",
- "hre",
- "hrk",
- "hrm",
- "hro",
- "hrp",
- "hrr",
- "hrt",
- "hru",
- "hrw",
- "hrx",
- "hrz",
- "hsb",
- "hsh",
- "hsl",
- "hsn",
- "hss",
- "ht",
- "hti",
- "hto",
- "hts",
- "htu",
- "htx",
- "hu",
- "hub",
- "huc",
- "hud",
- "hue",
- "huf",
- "hug",
- "huh",
- "hui",
- "huj",
- "huk",
- "hul",
- "hum",
- "huo",
- "hup",
- "huq",
- "hur",
- "hus",
- "hut",
- "huu",
- "huv",
- "huw",
- "hux",
- "huy",
- "huz",
- "hvc",
- "hve",
- "hvk",
- "hvn",
- "hvv",
- "hwa",
- "hwc",
- "hwo",
- "hy",
- "hya",
- "hyw",
- "hyx",
- "hz",
- "ia",
- "iai",
- "ian",
- "iap",
- "iar",
- "iba",
- "ibb",
- "ibd",
- "ibe",
- "ibg",
- "ibh",
- "ibi",
- "ibl",
- "ibm",
- "ibn",
- "ibr",
- "ibu",
- "iby",
- "ica",
- "ich",
- "icl",
- "icr",
- "id",
- "ida",
- "idb",
- "idc",
- "idd",
- "ide",
- "idi",
- "idr",
- "ids",
- "idt",
- "idu",
- "ie",
- "ifa",
- "ifb",
- "ife",
- "iff",
- "ifk",
- "ifm",
- "ifu",
- "ify",
- "ig",
- "igb",
- "ige",
- "igg",
- "igl",
- "igm",
- "ign",
- "igo",
- "igs",
- "igw",
- "ihb",
- "ihi",
- "ihp",
- "ihw",
- "ii",
- "iin",
- "iir",
- "ijc",
- "ije",
- "ijj",
- "ijn",
- "ijo",
- "ijs",
- "ik",
- "ike",
- "ikh",
- "iki",
- "ikk",
- "ikl",
- "iko",
- "ikp",
- "ikr",
- "iks",
- "ikt",
- "ikv",
- "ikw",
- "ikx",
- "ikz",
- "ila",
- "ilb",
- "ilg",
- "ili",
- "ilk",
- "ill",
- "ilm",
- "ilo",
- "ilp",
- "ils",
- "ilu",
- "ilv",
- "ilw",
- "ima",
- "ime",
- "imi",
- "iml",
- "imn",
- "imo",
- "imr",
- "ims",
- "imt",
- "imy",
- "in",
- "inb",
- "inc",
- "ine",
- "ing",
- "inh",
- "inj",
- "inl",
- "inm",
- "inn",
- "ino",
- "inp",
- "ins",
- "int",
- "inz",
- "io",
- "ior",
- "iou",
- "iow",
- "ipi",
- "ipo",
- "iqu",
- "iqw",
- "ira",
- "ire",
- "irh",
- "iri",
- "irk",
- "irn",
- "iro",
- "irr",
- "iru",
- "irx",
- "iry",
- "is",
- "isa",
- "isc",
- "isd",
- "ise",
- "isg",
- "ish",
- "isi",
- "isk",
- "ism",
- "isn",
- "iso",
- "isr",
- "ist",
- "isu",
- "isv",
- "it",
- "itb",
- "itc",
- "itd",
- "ite",
- "iti",
- "itk",
- "itl",
- "itm",
- "ito",
- "itr",
- "its",
- "itt",
- "itv",
- "itw",
- "itx",
- "ity",
- "itz",
- "iu",
- "ium",
- "ivb",
- "ivv",
- "iw",
- "iwk",
- "iwm",
- "iwo",
- "iws",
- "ixc",
- "ixl",
- "iya",
- "iyo",
- "iyx",
- "izh",
- "izi",
- "izm",
- "izr",
- "izz",
- "ja",
- "jaa",
- "jab",
- "jac",
- "jad",
- "jae",
- "jaf",
- "jah",
- "jaj",
- "jak",
- "jal",
- "jam",
- "jan",
- "jao",
- "jaq",
- "jar",
- "jas",
- "jat",
- "jau",
- "jax",
- "jay",
- "jaz",
- "jbe",
- "jbi",
- "jbj",
- "jbk",
- "jbm",
- "jbn",
- "jbo",
- "jbr",
- "jbt",
- "jbu",
- "jbw",
- "jcs",
- "jct",
- "jda",
- "jdg",
- "jdt",
- "jeb",
- "jee",
- "jeg",
- "jeh",
- "jei",
- "jek",
- "jel",
- "jen",
- "jer",
- "jet",
- "jeu",
- "jgb",
- "jge",
- "jgk",
- "jgo",
- "jhi",
- "jhs",
- "ji",
- "jia",
- "jib",
- "jic",
- "jid",
- "jie",
- "jig",
- "jih",
- "jii",
- "jil",
- "jim",
- "jio",
- "jiq",
- "jit",
- "jiu",
- "jiv",
- "jiy",
- "jje",
- "jjr",
- "jka",
- "jkm",
- "jko",
- "jkp",
- "jkr",
- "jks",
- "jku",
- "jle",
- "jls",
- "jma",
- "jmb",
- "jmc",
- "jmd",
- "jmi",
- "jml",
- "jmn",
- "jmr",
- "jms",
- "jmw",
- "jmx",
- "jna",
- "jnd",
- "jng",
- "jni",
- "jnj",
- "jnl",
- "jns",
- "job",
- "jod",
- "jog",
- "jor",
- "jos",
- "jow",
- "jpa",
- "jpr",
- "jpx",
- "jqr",
- "jra",
- "jrb",
- "jrr",
- "jrt",
- "jru",
- "jsl",
- "jua",
- "jub",
- "juc",
- "jud",
- "juh",
- "jui",
- "juk",
- "jul",
- "jum",
- "jun",
- "juo",
- "jup",
- "jur",
- "jus",
- "jut",
- "juu",
- "juw",
- "juy",
- "jv",
- "jvd",
- "jvn",
- "jw",
- "jwi",
- "jya",
- "jye",
- "jyy",
- "ka",
- "kaa",
- "kab",
- "kac",
- "kad",
- "kae",
- "kaf",
- "kag",
- "kah",
- "kai",
- "kaj",
- "kak",
- "kam",
- "kao",
- "kap",
- "kaq",
- "kar",
- "kav",
- "kaw",
- "kax",
- "kay",
- "kba",
- "kbb",
- "kbc",
- "kbd",
- "kbe",
- "kbf",
- "kbg",
- "kbh",
- "kbi",
- "kbj",
- "kbk",
- "kbl",
- "kbm",
- "kbn",
- "kbo",
- "kbp",
- "kbq",
- "kbr",
- "kbs",
- "kbt",
- "kbu",
- "kbv",
- "kbw",
- "kbx",
- "kby",
- "kbz",
- "kca",
- "kcb",
- "kcc",
- "kcd",
- "kce",
- "kcf",
- "kcg",
- "kch",
- "kci",
- "kcj",
- "kck",
- "kcl",
- "kcm",
- "kcn",
- "kco",
- "kcp",
- "kcq",
- "kcr",
- "kcs",
- "kct",
- "kcu",
- "kcv",
- "kcw",
- "kcx",
- "kcy",
- "kcz",
- "kda",
- "kdc",
- "kdd",
- "kde",
- "kdf",
- "kdg",
- "kdh",
- "kdi",
- "kdj",
- "kdk",
- "kdl",
- "kdm",
- "kdn",
- "kdo",
- "kdp",
- "kdq",
- "kdr",
- "kdt",
- "kdu",
- "kdv",
- "kdw",
- "kdx",
- "kdy",
- "kdz",
- "kea",
- "keb",
- "kec",
- "ked",
- "kee",
- "kef",
- "keg",
- "keh",
- "kei",
- "kej",
- "kek",
- "kel",
- "kem",
- "ken",
- "keo",
- "kep",
- "keq",
- "ker",
- "kes",
- "ket",
- "keu",
- "kev",
- "kew",
- "kex",
- "key",
- "kez",
- "kfa",
- "kfb",
- "kfc",
- "kfd",
- "kfe",
- "kff",
- "kfg",
- "kfh",
- "kfi",
- "kfj",
- "kfk",
- "kfl",
- "kfm",
- "kfn",
- "kfo",
- "kfp",
- "kfq",
- "kfr",
- "kfs",
- "kft",
- "kfu",
- "kfv",
- "kfw",
- "kfx",
- "kfy",
- "kfz",
- "kg",
- "kga",
- "kgb",
- "kgc",
- "kgd",
- "kge",
- "kgf",
- "kgg",
- "kgh",
- "kgi",
- "kgj",
- "kgk",
- "kgl",
- "kgm",
- "kgn",
- "kgo",
- "kgp",
- "kgq",
- "kgr",
- "kgs",
- "kgt",
- "kgu",
- "kgv",
- "kgw",
- "kgx",
- "kgy",
- "kha",
- "khb",
- "khc",
- "khd",
- "khe",
- "khf",
- "khg",
- "khh",
- "khi",
- "khj",
- "khk",
- "khl",
- "khn",
- "kho",
- "khp",
- "khq",
- "khr",
- "khs",
- "kht",
- "khu",
- "khv",
- "khw",
- "khx",
- "khy",
- "khz",
- "ki",
- "kia",
- "kib",
- "kic",
- "kid",
- "kie",
- "kif",
- "kig",
- "kih",
- "kii",
- "kij",
- "kil",
- "kim",
- "kio",
- "kip",
- "kiq",
- "kis",
- "kit",
- "kiu",
- "kiv",
- "kiw",
- "kix",
- "kiy",
- "kiz",
- "kj",
- "kja",
- "kjb",
- "kjc",
- "kjd",
- "kje",
- "kjf",
- "kjg",
- "kjh",
- "kji",
- "kjj",
- "kjk",
- "kjl",
- "kjm",
- "kjn",
- "kjo",
- "kjp",
- "kjq",
- "kjr",
- "kjs",
- "kjt",
- "kju",
- "kjv",
- "kjx",
- "kjy",
- "kjz",
- "kk",
- "kka",
- "kkb",
- "kkc",
- "kkd",
- "kke",
- "kkf",
- "kkg",
- "kkh",
- "kki",
- "kkj",
- "kkk",
- "kkl",
- "kkm",
- "kkn",
- "kko",
- "kkp",
- "kkq",
- "kkr",
- "kks",
- "kkt",
- "kku",
- "kkv",
- "kkw",
- "kkx",
- "kky",
- "kkz",
- "kl",
- "kla",
- "klb",
- "klc",
- "kld",
- "kle",
- "klf",
- "klg",
- "klh",
- "kli",
- "klj",
- "klk",
- "kll",
- "klm",
- "kln",
- "klo",
- "klp",
- "klq",
- "klr",
- "kls",
- "klt",
- "klu",
- "klv",
- "klw",
- "klx",
- "kly",
- "klz",
- "km",
- "kma",
- "kmb",
- "kmc",
- "kmd",
- "kme",
- "kmf",
- "kmg",
- "kmh",
- "kmi",
- "kmj",
- "kmk",
- "kml",
- "kmm",
- "kmn",
- "kmo",
- "kmp",
- "kmq",
- "kmr",
- "kms",
- "kmt",
- "kmu",
- "kmv",
- "kmw",
- "kmx",
- "kmy",
- "kmz",
- "kn",
- "kna",
- "knb",
- "knc",
- "knd",
- "kne",
- "knf",
- "kng",
- "kni",
- "knj",
- "knk",
- "knl",
- "knm",
- "knn",
- "kno",
- "knp",
- "knq",
- "knr",
- "kns",
- "knt",
- "knu",
- "knv",
- "knw",
- "knx",
- "kny",
- "knz",
- "ko",
- "koa",
- "koc",
- "kod",
- "koe",
- "kof",
- "kog",
- "koh",
- "koi",
- "koj",
- "kok",
- "kol",
- "koo",
- "kop",
- "koq",
- "kos",
- "kot",
- "kou",
- "kov",
- "kow",
- "kox",
- "koy",
- "koz",
- "kpa",
- "kpb",
- "kpc",
- "kpd",
- "kpe",
- "kpf",
- "kpg",
- "kph",
- "kpi",
- "kpj",
- "kpk",
- "kpl",
- "kpm",
- "kpn",
- "kpo",
- "kpp",
- "kpq",
- "kpr",
- "kps",
- "kpt",
- "kpu",
- "kpv",
- "kpw",
- "kpx",
- "kpy",
- "kpz",
- "kqa",
- "kqb",
- "kqc",
- "kqd",
- "kqe",
- "kqf",
- "kqg",
- "kqh",
- "kqi",
- "kqj",
- "kqk",
- "kql",
- "kqm",
- "kqn",
- "kqo",
- "kqp",
- "kqq",
- "kqr",
- "kqs",
- "kqt",
- "kqu",
- "kqv",
- "kqw",
- "kqx",
- "kqy",
- "kqz",
- "kr",
- "kra",
- "krb",
- "krc",
- "krd",
- "kre",
- "krf",
- "krh",
- "kri",
- "krj",
- "krk",
- "krl",
- "krm",
- "krn",
- "kro",
- "krp",
- "krr",
- "krs",
- "krt",
- "kru",
- "krv",
- "krw",
- "krx",
- "kry",
- "krz",
- "ks",
- "ksa",
- "ksb",
- "ksc",
- "ksd",
- "kse",
- "ksf",
- "ksg",
- "ksh",
- "ksi",
- "ksj",
- "ksk",
- "ksl",
- "ksm",
- "ksn",
- "kso",
- "ksp",
- "ksq",
- "ksr",
- "kss",
- "kst",
- "ksu",
- "ksv",
- "ksw",
- "ksx",
- "ksy",
- "ksz",
- "kta",
- "ktb",
- "ktc",
- "ktd",
- "kte",
- "ktf",
- "ktg",
- "kth",
- "kti",
- "ktj",
- "ktk",
- "ktl",
- "ktm",
- "ktn",
- "kto",
- "ktp",
- "ktq",
- "ktr",
- "kts",
- "ktt",
- "ktu",
- "ktv",
- "ktw",
- "ktx",
- "kty",
- "ktz",
- "ku",
- "kub",
- "kuc",
- "kud",
- "kue",
- "kuf",
- "kug",
- "kuh",
- "kui",
- "kuj",
- "kuk",
- "kul",
- "kum",
- "kun",
- "kuo",
- "kup",
- "kuq",
- "kus",
- "kut",
- "kuu",
- "kuv",
- "kuw",
- "kux",
- "kuy",
- "kuz",
- "kv",
- "kva",
- "kvb",
- "kvc",
- "kvd",
- "kve",
- "kvf",
- "kvg",
- "kvh",
- "kvi",
- "kvj",
- "kvk",
- "kvl",
- "kvm",
- "kvn",
- "kvo",
- "kvp",
- "kvq",
- "kvr",
- "kvs",
- "kvt",
- "kvu",
- "kvv",
- "kvw",
- "kvx",
- "kvy",
- "kvz",
- "kw",
- "kwa",
- "kwb",
- "kwc",
- "kwd",
- "kwe",
- "kwf",
- "kwg",
- "kwh",
- "kwi",
- "kwj",
- "kwk",
- "kwl",
- "kwm",
- "kwn",
- "kwo",
- "kwp",
- "kwq",
- "kwr",
- "kws",
- "kwt",
- "kwu",
- "kwv",
- "kww",
- "kwx",
- "kwy",
- "kwz",
- "kxa",
- "kxb",
- "kxc",
- "kxd",
- "kxe",
- "kxf",
- "kxh",
- "kxi",
- "kxj",
- "kxk",
- "kxl",
- "kxm",
- "kxn",
- "kxo",
- "kxp",
- "kxq",
- "kxr",
- "kxs",
- "kxt",
- "kxu",
- "kxv",
- "kxw",
- "kxx",
- "kxy",
- "kxz",
- "ky",
- "kya",
- "kyb",
- "kyc",
- "kyd",
- "kye",
- "kyf",
- "kyg",
- "kyh",
- "kyi",
- "kyj",
- "kyk",
- "kyl",
- "kym",
- "kyn",
- "kyo",
- "kyp",
- "kyq",
- "kyr",
- "kys",
- "kyt",
- "kyu",
- "kyv",
- "kyw",
- "kyx",
- "kyy",
- "kyz",
- "kza",
- "kzb",
- "kzc",
- "kzd",
- "kze",
- "kzf",
- "kzg",
- "kzh",
- "kzi",
- "kzj",
- "kzk",
- "kzl",
- "kzm",
- "kzn",
- "kzo",
- "kzp",
- "kzq",
- "kzr",
- "kzs",
- "kzt",
- "kzu",
- "kzv",
- "kzw",
- "kzx",
- "kzy",
- "kzz",
- "la",
- "laa",
- "lab",
- "lac",
- "lad",
- "lae",
- "laf",
- "lag",
- "lah",
- "lai",
- "laj",
- "lak",
- "lal",
- "lam",
- "lan",
- "lap",
- "laq",
- "lar",
- "las",
- "lau",
- "law",
- "lax",
- "lay",
- "laz",
- "lb",
- "lba",
- "lbb",
- "lbc",
- "lbe",
- "lbf",
- "lbg",
- "lbi",
- "lbj",
- "lbk",
- "lbl",
- "lbm",
- "lbn",
- "lbo",
- "lbq",
- "lbr",
- "lbs",
- "lbt",
- "lbu",
- "lbv",
- "lbw",
- "lbx",
- "lby",
- "lbz",
- "lcc",
- "lcd",
- "lce",
- "lcf",
- "lch",
- "lcl",
- "lcm",
- "lcp",
- "lcq",
- "lcs",
- "lda",
- "ldb",
- "ldd",
- "ldg",
- "ldh",
- "ldi",
- "ldj",
- "ldk",
- "ldl",
- "ldm",
- "ldn",
- "ldo",
- "ldp",
- "ldq",
- "lea",
- "leb",
- "lec",
- "led",
- "lee",
- "lef",
- "leg",
- "leh",
- "lei",
- "lej",
- "lek",
- "lel",
- "lem",
- "len",
- "leo",
- "lep",
- "leq",
- "ler",
- "les",
- "let",
- "leu",
- "lev",
- "lew",
- "lex",
- "ley",
- "lez",
- "lfa",
- "lfn",
- "lg",
- "lga",
- "lgb",
- "lgg",
- "lgh",
- "lgi",
- "lgk",
- "lgl",
- "lgm",
- "lgn",
- "lgo",
- "lgq",
- "lgr",
- "lgs",
- "lgt",
- "lgu",
- "lgz",
- "lha",
- "lhh",
- "lhi",
- "lhl",
- "lhm",
- "lhn",
- "lhp",
- "lhs",
- "lht",
- "lhu",
- "li",
- "lia",
- "lib",
- "lic",
- "lid",
- "lie",
- "lif",
- "lig",
- "lih",
- "lii",
- "lij",
- "lik",
- "lil",
- "lio",
- "lip",
- "liq",
- "lir",
- "lis",
- "liu",
- "liv",
- "liw",
- "lix",
- "liy",
- "liz",
- "lja",
- "lje",
- "lji",
- "ljl",
- "ljp",
- "ljw",
- "ljx",
- "lka",
- "lkb",
- "lkc",
- "lkd",
- "lke",
- "lkh",
- "lki",
- "lkj",
- "lkl",
- "lkm",
- "lkn",
- "lko",
- "lkr",
- "lks",
- "lkt",
- "lku",
- "lky",
- "lla",
- "llb",
- "llc",
- "lld",
- "lle",
- "llf",
- "llg",
- "llh",
- "lli",
- "llj",
- "llk",
- "lll",
- "llm",
- "lln",
- "llo",
- "llp",
- "llq",
- "lls",
- "llu",
- "llx",
- "lma",
- "lmb",
- "lmc",
- "lmd",
- "lme",
- "lmf",
- "lmg",
- "lmh",
- "lmi",
- "lmj",
- "lmk",
- "lml",
- "lmm",
- "lmn",
- "lmo",
- "lmp",
- "lmq",
- "lmr",
- "lmu",
- "lmv",
- "lmw",
- "lmx",
- "lmy",
- "lmz",
- "ln",
- "lna",
- "lnb",
- "lnd",
- "lng",
- "lnh",
- "lni",
- "lnj",
- "lnl",
- "lnm",
- "lnn",
- "lno",
- "lns",
- "lnu",
- "lnw",
- "lnz",
- "lo",
- "loa",
- "lob",
- "loc",
- "loe",
- "lof",
- "log",
- "loh",
- "loi",
- "loj",
- "lok",
- "lol",
- "lom",
- "lon",
- "loo",
- "lop",
- "loq",
- "lor",
- "los",
- "lot",
- "lou",
- "lov",
- "low",
- "lox",
- "loy",
- "loz",
- "lpa",
- "lpe",
- "lpn",
- "lpo",
- "lpx",
- "lqr",
- "lra",
- "lrc",
- "lre",
- "lrg",
- "lri",
- "lrk",
- "lrl",
- "lrm",
- "lrn",
- "lro",
- "lrr",
- "lrt",
- "lrv",
- "lrz",
- "lsa",
- "lsb",
- "lsc",
- "lsd",
- "lse",
- "lsg",
- "lsh",
- "lsi",
- "lsl",
- "lsm",
- "lsn",
- "lso",
- "lsp",
- "lsr",
- "lss",
- "lst",
- "lsv",
- "lsw",
- "lsy",
- "lt",
- "ltc",
- "ltg",
- "lth",
- "lti",
- "ltn",
- "lto",
- "lts",
- "ltu",
- "lu",
- "lua",
- "luc",
- "lud",
- "lue",
- "luf",
- "luh",
- "lui",
- "luj",
- "luk",
- "lul",
- "lum",
- "lun",
- "luo",
- "lup",
- "luq",
- "lur",
- "lus",
- "lut",
- "luu",
- "luv",
- "luw",
- "luy",
- "luz",
- "lv",
- "lva",
- "lvi",
- "lvk",
- "lvl",
- "lvs",
- "lvu",
- "lwa",
- "lwe",
- "lwg",
- "lwh",
- "lwl",
- "lwm",
- "lwo",
- "lws",
- "lwt",
- "lwu",
- "lww",
- "lxm",
- "lya",
- "lyg",
- "lyn",
- "lzh",
- "lzl",
- "lzn",
- "lzz",
- "maa",
- "mab",
- "mad",
- "mae",
- "maf",
- "mag",
- "mai",
- "maj",
- "mak",
- "mam",
- "man",
- "map",
- "maq",
- "mas",
- "mat",
- "mau",
- "mav",
- "maw",
- "max",
- "maz",
- "mba",
- "mbb",
- "mbc",
- "mbd",
- "mbe",
- "mbf",
- "mbh",
- "mbi",
- "mbj",
- "mbk",
- "mbl",
- "mbm",
- "mbn",
- "mbo",
- "mbp",
- "mbq",
- "mbr",
- "mbs",
- "mbt",
- "mbu",
- "mbv",
- "mbw",
- "mbx",
- "mby",
- "mbz",
- "mca",
- "mcb",
- "mcc",
- "mcd",
- "mce",
- "mcf",
- "mcg",
- "mch",
- "mci",
- "mcj",
- "mck",
- "mcl",
- "mcm",
- "mcn",
- "mco",
- "mcp",
- "mcq",
- "mcr",
- "mcs",
- "mct",
- "mcu",
- "mcv",
- "mcw",
- "mcx",
- "mcy",
- "mcz",
- "mda",
- "mdb",
- "mdc",
- "mdd",
- "mde",
- "mdf",
- "mdg",
- "mdh",
- "mdi",
- "mdj",
- "mdk",
- "mdl",
- "mdm",
- "mdn",
- "mdp",
- "mdq",
- "mdr",
- "mds",
- "mdt",
- "mdu",
- "mdv",
- "mdw",
- "mdx",
- "mdy",
- "mdz",
- "mea",
- "meb",
- "mec",
- "med",
- "mee",
- "mef",
- "meg",
- "meh",
- "mei",
- "mej",
- "mek",
- "mel",
- "mem",
- "men",
- "meo",
- "mep",
- "meq",
- "mer",
- "mes",
- "met",
- "meu",
- "mev",
- "mew",
- "mey",
- "mez",
- "mfa",
- "mfb",
- "mfc",
- "mfd",
- "mfe",
- "mff",
- "mfg",
- "mfh",
- "mfi",
- "mfj",
- "mfk",
- "mfl",
- "mfm",
- "mfn",
- "mfo",
- "mfp",
- "mfq",
- "mfr",
- "mfs",
- "mft",
- "mfu",
- "mfv",
- "mfw",
- "mfx",
- "mfy",
- "mfz",
- "mg",
- "mga",
- "mgb",
- "mgc",
- "mgd",
- "mge",
- "mgf",
- "mgg",
- "mgh",
- "mgi",
- "mgj",
- "mgk",
- "mgl",
- "mgm",
- "mgn",
- "mgo",
- "mgp",
- "mgq",
- "mgr",
- "mgs",
- "mgt",
- "mgu",
- "mgv",
- "mgw",
- "mgx",
- "mgy",
- "mgz",
- "mh",
- "mha",
- "mhb",
- "mhc",
- "mhd",
- "mhe",
- "mhf",
- "mhg",
- "mhh",
- "mhi",
- "mhj",
- "mhk",
- "mhl",
- "mhm",
- "mhn",
- "mho",
- "mhp",
- "mhq",
- "mhr",
- "mhs",
- "mht",
- "mhu",
- "mhw",
- "mhx",
- "mhy",
- "mhz",
- "mi",
- "mia",
- "mib",
- "mic",
- "mid",
- "mie",
- "mif",
- "mig",
- "mih",
- "mii",
- "mij",
- "mik",
- "mil",
- "mim",
- "min",
- "mio",
- "mip",
- "miq",
- "mir",
- "mis",
- "mit",
- "miu",
- "miw",
- "mix",
- "miy",
- "miz",
- "mja",
- "mjb",
- "mjc",
- "mjd",
- "mje",
- "mjg",
- "mjh",
- "mji",
- "mjj",
- "mjk",
- "mjl",
- "mjm",
- "mjn",
- "mjo",
- "mjp",
- "mjq",
- "mjr",
- "mjs",
- "mjt",
- "mju",
- "mjv",
- "mjw",
- "mjx",
- "mjy",
- "mjz",
- "mk",
- "mka",
- "mkb",
- "mkc",
- "mke",
- "mkf",
- "mkg",
- "mkh",
- "mki",
- "mkj",
- "mkk",
- "mkl",
- "mkm",
- "mkn",
- "mko",
- "mkp",
- "mkq",
- "mkr",
- "mks",
- "mkt",
- "mku",
- "mkv",
- "mkw",
- "mkx",
- "mky",
- "mkz",
- "ml",
- "mla",
- "mlb",
- "mlc",
- "mld",
- "mle",
- "mlf",
- "mlh",
- "mli",
- "mlj",
- "mlk",
- "mll",
- "mlm",
- "mln",
- "mlo",
- "mlp",
- "mlq",
- "mlr",
- "mls",
- "mlu",
- "mlv",
- "mlw",
- "mlx",
- "mlz",
- "mma",
- "mmb",
- "mmc",
- "mmd",
- "mme",
- "mmf",
- "mmg",
- "mmh",
- "mmi",
- "mmj",
- "mmk",
- "mml",
- "mmm",
- "mmn",
- "mmo",
- "mmp",
- "mmq",
- "mmr",
- "mmt",
- "mmu",
- "mmv",
- "mmw",
- "mmx",
- "mmy",
- "mmz",
- "mn",
- "mna",
- "mnb",
- "mnc",
- "mnd",
- "mne",
- "mnf",
- "mng",
- "mnh",
- "mni",
- "mnj",
- "mnk",
- "mnl",
- "mnm",
- "mnn",
- "mno",
- "mnp",
- "mnq",
- "mnr",
- "mns",
- "mnt",
- "mnu",
- "mnv",
- "mnw",
- "mnx",
- "mny",
- "mnz",
- "mo",
- "moa",
- "moc",
- "mod",
- "moe",
- "mof",
- "mog",
- "moh",
- "moi",
- "moj",
- "mok",
- "mom",
- "moo",
- "mop",
- "moq",
- "mor",
- "mos",
- "mot",
- "mou",
- "mov",
- "mow",
- "mox",
- "moy",
- "moz",
- "mpa",
- "mpb",
- "mpc",
- "mpd",
- "mpe",
- "mpg",
- "mph",
- "mpi",
- "mpj",
- "mpk",
- "mpl",
- "mpm",
- "mpn",
- "mpo",
- "mpp",
- "mpq",
- "mpr",
- "mps",
- "mpt",
- "mpu",
- "mpv",
- "mpw",
- "mpx",
- "mpy",
- "mpz",
- "mqa",
- "mqb",
- "mqc",
- "mqe",
- "mqf",
- "mqg",
- "mqh",
- "mqi",
- "mqj",
- "mqk",
- "mql",
- "mqm",
- "mqn",
- "mqo",
- "mqp",
- "mqq",
- "mqr",
- "mqs",
- "mqt",
- "mqu",
- "mqv",
- "mqw",
- "mqx",
- "mqy",
- "mqz",
- "mr",
- "mra",
- "mrb",
- "mrc",
- "mrd",
- "mre",
- "mrf",
- "mrg",
- "mrh",
- "mrj",
- "mrk",
- "mrl",
- "mrm",
- "mrn",
- "mro",
- "mrp",
- "mrq",
- "mrr",
- "mrs",
- "mrt",
- "mru",
- "mrv",
- "mrw",
- "mrx",
- "mry",
- "mrz",
- "ms",
- "msb",
- "msc",
- "msd",
- "mse",
- "msf",
- "msg",
- "msh",
- "msi",
- "msj",
- "msk",
- "msl",
- "msm",
- "msn",
- "mso",
- "msp",
- "msq",
- "msr",
- "mss",
- "mst",
- "msu",
- "msv",
- "msw",
- "msx",
- "msy",
- "msz",
- "mt",
- "mta",
- "mtb",
- "mtc",
- "mtd",
- "mte",
- "mtf",
- "mtg",
- "mth",
- "mti",
- "mtj",
- "mtk",
- "mtl",
- "mtm",
- "mtn",
- "mto",
- "mtp",
- "mtq",
- "mtr",
- "mts",
- "mtt",
- "mtu",
- "mtv",
- "mtw",
- "mtx",
- "mty",
- "mua",
- "mub",
- "muc",
- "mud",
- "mue",
- "mug",
- "muh",
- "mui",
- "muj",
- "muk",
- "mul",
- "mum",
- "mun",
- "muo",
- "mup",
- "muq",
- "mur",
- "mus",
- "mut",
- "muu",
- "muv",
- "mux",
- "muy",
- "muz",
- "mva",
- "mvb",
- "mvd",
- "mve",
- "mvf",
- "mvg",
- "mvh",
- "mvi",
- "mvk",
- "mvl",
- "mvm",
- "mvn",
- "mvo",
- "mvp",
- "mvq",
- "mvr",
- "mvs",
- "mvt",
- "mvu",
- "mvv",
- "mvw",
- "mvx",
- "mvy",
- "mvz",
- "mwa",
- "mwb",
- "mwc",
- "mwd",
- "mwe",
- "mwf",
- "mwg",
- "mwh",
- "mwi",
- "mwj",
- "mwk",
- "mwl",
- "mwm",
- "mwn",
- "mwo",
- "mwp",
- "mwq",
- "mwr",
- "mws",
- "mwt",
- "mwu",
- "mwv",
- "mww",
- "mwx",
- "mwy",
- "mwz",
- "mxa",
- "mxb",
- "mxc",
- "mxd",
- "mxe",
- "mxf",
- "mxg",
- "mxh",
- "mxi",
- "mxj",
- "mxk",
- "mxl",
- "mxm",
- "mxn",
- "mxo",
- "mxp",
- "mxq",
- "mxr",
- "mxs",
- "mxt",
- "mxu",
- "mxv",
- "mxw",
- "mxx",
- "mxy",
- "mxz",
- "my",
- "myb",
- "myc",
- "myd",
- "mye",
- "myf",
- "myg",
- "myh",
- "myi",
- "myj",
- "myk",
- "myl",
- "mym",
- "myn",
- "myo",
- "myp",
- "myq",
- "myr",
- "mys",
- "myt",
- "myu",
- "myv",
- "myw",
- "myx",
- "myy",
- "myz",
- "mza",
- "mzb",
- "mzc",
- "mzd",
- "mze",
- "mzg",
- "mzh",
- "mzi",
- "mzj",
- "mzk",
- "mzl",
- "mzm",
- "mzn",
- "mzo",
- "mzp",
- "mzq",
- "mzr",
- "mzs",
- "mzt",
- "mzu",
- "mzv",
- "mzw",
- "mzx",
- "mzy",
- "mzz",
- "na",
- "naa",
- "nab",
- "nac",
- "nad",
- "nae",
- "naf",
- "nag",
- "nah",
- "nai",
- "naj",
- "nak",
- "nal",
- "nam",
- "nan",
- "nao",
- "nap",
- "naq",
- "nar",
- "nas",
- "nat",
- "naw",
- "nax",
- "nay",
- "naz",
- "nb",
- "nba",
- "nbb",
- "nbc",
- "nbd",
- "nbe",
- "nbf",
- "nbg",
- "nbh",
- "nbi",
- "nbj",
- "nbk",
- "nbm",
- "nbn",
- "nbo",
- "nbp",
- "nbq",
- "nbr",
- "nbs",
- "nbt",
- "nbu",
- "nbv",
- "nbw",
- "nbx",
- "nby",
- "nca",
- "ncb",
- "ncc",
- "ncd",
- "nce",
- "ncf",
- "ncg",
- "nch",
- "nci",
- "ncj",
- "nck",
- "ncl",
- "ncm",
- "ncn",
- "nco",
- "ncp",
- "ncq",
- "ncr",
- "ncs",
- "nct",
- "ncu",
- "ncx",
- "ncz",
- "nd",
- "nda",
- "ndb",
- "ndc",
- "ndd",
- "ndf",
- "ndg",
- "ndh",
- "ndi",
- "ndj",
- "ndk",
- "ndl",
- "ndm",
- "ndn",
- "ndp",
- "ndq",
- "ndr",
- "nds",
- "ndt",
- "ndu",
- "ndv",
- "ndw",
- "ndx",
- "ndy",
- "ndz",
- "ne",
- "nea",
- "neb",
- "nec",
- "ned",
- "nee",
- "nef",
- "neg",
- "neh",
- "nei",
- "nej",
- "nek",
- "nem",
- "nen",
- "neo",
- "neq",
- "ner",
- "nes",
- "net",
- "neu",
- "nev",
- "new",
- "nex",
- "ney",
- "nez",
- "nfa",
- "nfd",
- "nfl",
- "nfr",
- "nfu",
- "ng",
- "nga",
- "ngb",
- "ngc",
- "ngd",
- "nge",
- "ngf",
- "ngg",
- "ngh",
- "ngi",
- "ngj",
- "ngk",
- "ngl",
- "ngm",
- "ngn",
- "ngo",
- "ngp",
- "ngq",
- "ngr",
- "ngs",
- "ngt",
- "ngu",
- "ngv",
- "ngw",
- "ngx",
- "ngy",
- "ngz",
- "nha",
- "nhb",
- "nhc",
- "nhd",
- "nhe",
- "nhf",
- "nhg",
- "nhh",
- "nhi",
- "nhk",
- "nhm",
- "nhn",
- "nho",
- "nhp",
- "nhq",
- "nhr",
- "nht",
- "nhu",
- "nhv",
- "nhw",
- "nhx",
- "nhy",
- "nhz",
- "nia",
- "nib",
- "nic",
- "nid",
- "nie",
- "nif",
- "nig",
- "nih",
- "nii",
- "nij",
- "nik",
- "nil",
- "nim",
- "nin",
- "nio",
- "niq",
- "nir",
- "nis",
- "nit",
- "niu",
- "niv",
- "niw",
- "nix",
- "niy",
- "niz",
- "nja",
- "njb",
- "njd",
- "njh",
- "nji",
- "njj",
- "njl",
- "njm",
- "njn",
- "njo",
- "njr",
- "njs",
- "njt",
- "nju",
- "njx",
- "njy",
- "njz",
- "nka",
- "nkb",
- "nkc",
- "nkd",
- "nke",
- "nkf",
- "nkg",
- "nkh",
- "nki",
- "nkj",
- "nkk",
- "nkm",
- "nkn",
- "nko",
- "nkp",
- "nkq",
- "nkr",
- "nks",
- "nkt",
- "nku",
- "nkv",
- "nkw",
- "nkx",
- "nkz",
- "nl",
- "nla",
- "nlc",
- "nle",
- "nlg",
- "nli",
- "nlj",
- "nlk",
- "nll",
- "nlm",
- "nln",
- "nlo",
- "nlq",
- "nlr",
- "nlu",
- "nlv",
- "nlw",
- "nlx",
- "nly",
- "nlz",
- "nma",
- "nmb",
- "nmc",
- "nmd",
- "nme",
- "nmf",
- "nmg",
- "nmh",
- "nmi",
- "nmj",
- "nmk",
- "nml",
- "nmm",
- "nmn",
- "nmo",
- "nmp",
- "nmq",
- "nmr",
- "nms",
- "nmt",
- "nmu",
- "nmv",
- "nmw",
- "nmx",
- "nmy",
- "nmz",
- "nn",
- "nna",
- "nnb",
- "nnc",
- "nnd",
- "nne",
- "nnf",
- "nng",
- "nnh",
- "nni",
- "nnj",
- "nnk",
- "nnl",
- "nnm",
- "nnn",
- "nnp",
- "nnq",
- "nnr",
- "nns",
- "nnt",
- "nnu",
- "nnv",
- "nnw",
- "nnx",
- "nny",
- "nnz",
- "no",
- "noa",
- "noc",
- "nod",
- "noe",
- "nof",
- "nog",
- "noh",
- "noi",
- "noj",
- "nok",
- "nol",
- "nom",
- "non",
- "noo",
- "nop",
- "noq",
- "nos",
- "not",
- "nou",
- "nov",
- "now",
- "noy",
- "noz",
- "npa",
- "npb",
- "npg",
- "nph",
- "npi",
- "npl",
- "npn",
- "npo",
- "nps",
- "npu",
- "npx",
- "npy",
- "nqg",
- "nqk",
- "nql",
- "nqm",
- "nqn",
- "nqo",
- "nqq",
- "nqt",
- "nqy",
- "nr",
- "nra",
- "nrb",
- "nrc",
- "nre",
- "nrf",
- "nrg",
- "nri",
- "nrk",
- "nrl",
- "nrm",
- "nrn",
- "nrp",
- "nrr",
- "nrt",
- "nru",
- "nrx",
- "nrz",
- "nsa",
- "nsb",
- "nsc",
- "nsd",
- "nse",
- "nsf",
- "nsg",
- "nsh",
- "nsi",
- "nsk",
- "nsl",
- "nsm",
- "nsn",
- "nso",
- "nsp",
- "nsq",
- "nsr",
- "nss",
- "nst",
- "nsu",
- "nsv",
- "nsw",
- "nsx",
- "nsy",
- "nsz",
- "ntd",
- "nte",
- "ntg",
- "nti",
- "ntj",
- "ntk",
- "ntm",
- "nto",
- "ntp",
- "ntr",
- "nts",
- "ntu",
- "ntw",
- "ntx",
- "nty",
- "ntz",
- "nua",
- "nub",
- "nuc",
- "nud",
- "nue",
- "nuf",
- "nug",
- "nuh",
- "nui",
- "nuj",
- "nuk",
- "nul",
- "num",
- "nun",
- "nuo",
- "nup",
- "nuq",
- "nur",
- "nus",
- "nut",
- "nuu",
- "nuv",
- "nuw",
- "nux",
- "nuy",
- "nuz",
- "nv",
- "nvh",
- "nvm",
- "nvo",
- "nwa",
- "nwb",
- "nwc",
- "nwe",
- "nwg",
- "nwi",
- "nwm",
- "nwo",
- "nwr",
- "nww",
- "nwx",
- "nwy",
- "nxa",
- "nxd",
- "nxe",
- "nxg",
- "nxi",
- "nxk",
- "nxl",
- "nxm",
- "nxn",
- "nxo",
- "nxq",
- "nxr",
- "nxu",
- "nxx",
- "ny",
- "nyb",
- "nyc",
- "nyd",
- "nye",
- "nyf",
- "nyg",
- "nyh",
- "nyi",
- "nyj",
- "nyk",
- "nyl",
- "nym",
- "nyn",
- "nyo",
- "nyp",
- "nyq",
- "nyr",
- "nys",
- "nyt",
- "nyu",
- "nyv",
- "nyw",
- "nyx",
- "nyy",
- "nza",
- "nzb",
- "nzd",
- "nzi",
- "nzk",
- "nzm",
- "nzr",
- "nzs",
- "nzu",
- "nzy",
- "nzz",
- "oaa",
- "oac",
- "oak",
- "oar",
- "oav",
- "obi",
- "obk",
- "obl",
- "obm",
- "obo",
- "obr",
- "obt",
- "obu",
- "oc",
- "oca",
- "och",
- "ocm",
- "oco",
- "ocu",
- "oda",
- "odk",
- "odt",
- "odu",
- "ofo",
- "ofs",
- "ofu",
- "ogb",
- "ogc",
- "oge",
- "ogg",
- "ogo",
- "ogu",
- "oht",
- "ohu",
- "oia",
- "oie",
- "oin",
- "oj",
- "ojb",
- "ojc",
- "ojg",
- "ojp",
- "ojs",
- "ojv",
- "ojw",
- "oka",
- "okb",
- "okc",
- "okd",
- "oke",
- "okg",
- "okh",
- "oki",
- "okj",
- "okk",
- "okl",
- "okm",
- "okn",
- "oko",
- "okr",
- "oks",
- "oku",
- "okv",
- "okx",
- "okz",
- "ola",
- "old",
- "ole",
- "olk",
- "olm",
- "olo",
- "olr",
- "olt",
- "olu",
- "om",
- "oma",
- "omb",
- "omc",
- "ome",
- "omg",
- "omi",
- "omk",
- "oml",
- "omn",
- "omo",
- "omp",
- "omq",
- "omr",
- "omt",
- "omu",
- "omv",
- "omw",
- "omx",
- "omy",
- "ona",
- "onb",
- "one",
- "ong",
- "oni",
- "onj",
- "onk",
- "onn",
- "ono",
- "onp",
- "onr",
- "ons",
- "ont",
- "onu",
- "onw",
- "onx",
- "ood",
- "oog",
- "oon",
- "oor",
- "oos",
- "opa",
- "opk",
- "opm",
- "opo",
- "opt",
- "opy",
- "or",
- "ora",
- "orc",
- "ore",
- "org",
- "orh",
- "orn",
- "oro",
- "orr",
- "ors",
- "ort",
- "oru",
- "orv",
- "orw",
- "orx",
- "ory",
- "orz",
- "os",
- "osa",
- "osc",
- "osi",
- "osn",
- "oso",
- "osp",
- "ost",
- "osu",
- "osx",
- "ota",
- "otb",
- "otd",
- "ote",
- "oti",
- "otk",
- "otl",
- "otm",
- "otn",
- "oto",
- "otq",
- "otr",
- "ots",
- "ott",
- "otu",
- "otw",
- "otx",
- "oty",
- "otz",
- "oua",
- "oub",
- "oue",
- "oui",
- "oum",
- "oun",
- "ovd",
- "owi",
- "owl",
- "oyb",
- "oyd",
- "oym",
- "oyy",
- "ozm",
- "pa",
- "paa",
- "pab",
- "pac",
- "pad",
- "pae",
- "paf",
- "pag",
- "pah",
- "pai",
- "pak",
- "pal",
- "pam",
- "pao",
- "pap",
- "paq",
- "par",
- "pas",
- "pat",
- "pau",
- "pav",
- "paw",
- "pax",
- "pay",
- "paz",
- "pbb",
- "pbc",
- "pbe",
- "pbf",
- "pbg",
- "pbh",
- "pbi",
- "pbl",
- "pbm",
- "pbn",
- "pbo",
- "pbp",
- "pbr",
- "pbs",
- "pbt",
- "pbu",
- "pbv",
- "pby",
- "pbz",
- "pca",
- "pcb",
- "pcc",
- "pcd",
- "pce",
- "pcf",
- "pcg",
- "pch",
- "pci",
- "pcj",
- "pck",
- "pcl",
- "pcm",
- "pcn",
- "pcp",
- "pcr",
- "pcw",
- "pda",
- "pdc",
- "pdi",
- "pdn",
- "pdo",
- "pdt",
- "pdu",
- "pea",
- "peb",
- "ped",
- "pee",
- "pef",
- "peg",
- "peh",
- "pei",
- "pej",
- "pek",
- "pel",
- "pem",
- "peo",
- "pep",
- "peq",
- "pes",
- "pev",
- "pex",
- "pey",
- "pez",
- "pfa",
- "pfe",
- "pfl",
- "pga",
- "pgd",
- "pgg",
- "pgi",
- "pgk",
- "pgl",
- "pgn",
- "pgs",
- "pgu",
- "pgy",
- "pgz",
- "pha",
- "phd",
- "phg",
- "phh",
- "phi",
- "phj",
- "phk",
- "phl",
- "phm",
- "phn",
- "pho",
- "phq",
- "phr",
- "pht",
- "phu",
- "phv",
- "phw",
- "pi",
- "pia",
- "pib",
- "pic",
- "pid",
- "pie",
- "pif",
- "pig",
- "pih",
- "pii",
- "pij",
- "pil",
- "pim",
- "pin",
- "pio",
- "pip",
- "pir",
- "pis",
- "pit",
- "piu",
- "piv",
- "piw",
- "pix",
- "piy",
- "piz",
- "pjt",
- "pka",
- "pkb",
- "pkc",
- "pkg",
- "pkh",
- "pkn",
- "pko",
- "pkp",
- "pkr",
- "pks",
- "pkt",
- "pku",
- "pl",
- "pla",
- "plb",
- "plc",
- "pld",
- "ple",
- "plf",
- "plg",
- "plh",
- "plj",
- "plk",
- "pll",
- "pln",
- "plo",
- "plp",
- "plq",
- "plr",
- "pls",
- "plt",
- "plu",
- "plv",
- "plw",
- "ply",
- "plz",
- "pma",
- "pmb",
- "pmc",
- "pmd",
- "pme",
- "pmf",
- "pmh",
- "pmi",
- "pmj",
- "pmk",
- "pml",
- "pmm",
- "pmn",
- "pmo",
- "pmq",
- "pmr",
- "pms",
- "pmt",
- "pmu",
- "pmw",
- "pmx",
- "pmy",
- "pmz",
- "pna",
- "pnb",
- "pnc",
- "pnd",
- "pne",
- "png",
- "pnh",
- "pni",
- "pnj",
- "pnk",
- "pnl",
- "pnm",
- "pnn",
- "pno",
- "pnp",
- "pnq",
- "pnr",
- "pns",
- "pnt",
- "pnu",
- "pnv",
- "pnw",
- "pnx",
- "pny",
- "pnz",
- "poc",
- "pod",
- "poe",
- "pof",
- "pog",
- "poh",
- "poi",
- "pok",
- "pom",
- "pon",
- "poo",
- "pop",
- "poq",
- "pos",
- "pot",
- "pov",
- "pow",
- "pox",
- "poy",
- "poz",
- "ppa",
- "ppe",
- "ppi",
- "ppk",
- "ppl",
- "ppm",
- "ppn",
- "ppo",
- "ppp",
- "ppq",
- "ppr",
- "pps",
- "ppt",
- "ppu",
- "pqa",
- "pqe",
- "pqm",
- "pqw",
- "pra",
- "prb",
- "prc",
- "prd",
- "pre",
- "prf",
- "prg",
- "prh",
- "pri",
- "prk",
- "prl",
- "prm",
- "prn",
- "pro",
- "prp",
- "prq",
- "prr",
- "prs",
- "prt",
- "pru",
- "prw",
- "prx",
- "pry",
- "prz",
- "ps",
- "psa",
- "psc",
- "psd",
- "pse",
- "psg",
- "psh",
- "psi",
- "psl",
- "psm",
- "psn",
- "pso",
- "psp",
- "psq",
- "psr",
- "pss",
- "pst",
- "psu",
- "psw",
- "psy",
- "pt",
- "pta",
- "pth",
- "pti",
- "ptn",
- "pto",
- "ptp",
- "ptq",
- "ptr",
- "ptt",
- "ptu",
- "ptv",
- "ptw",
- "pty",
- "pua",
- "pub",
- "puc",
- "pud",
- "pue",
- "puf",
- "pug",
- "pui",
- "puj",
- "puk",
- "pum",
- "puo",
- "pup",
- "puq",
- "pur",
- "put",
- "puu",
- "puw",
- "pux",
- "puy",
- "puz",
- "pwa",
- "pwb",
- "pwg",
- "pwi",
- "pwm",
- "pwn",
- "pwo",
- "pwr",
- "pww",
- "pxm",
- "pye",
- "pym",
- "pyn",
- "pys",
- "pyu",
- "pyx",
- "pyy",
- "pze",
- "pzh",
- "pzn",
- "qaa..qtz",
- "qu",
- "qua",
- "qub",
- "quc",
- "qud",
- "quf",
- "qug",
- "quh",
- "qui",
- "quk",
- "qul",
- "qum",
- "qun",
- "qup",
- "quq",
- "qur",
- "qus",
- "quv",
- "quw",
- "qux",
- "quy",
- "quz",
- "qva",
- "qvc",
- "qve",
- "qvh",
- "qvi",
- "qvj",
- "qvl",
- "qvm",
- "qvn",
- "qvo",
- "qvp",
- "qvs",
- "qvw",
- "qvy",
- "qvz",
- "qwa",
- "qwc",
- "qwe",
- "qwh",
- "qwm",
- "qws",
- "qwt",
- "qxa",
- "qxc",
- "qxh",
- "qxl",
- "qxn",
- "qxo",
- "qxp",
- "qxq",
- "qxr",
- "qxs",
- "qxt",
- "qxu",
- "qxw",
- "qya",
- "qyp",
- "raa",
- "rab",
- "rac",
- "rad",
- "raf",
- "rag",
- "rah",
- "rai",
- "raj",
- "rak",
- "ral",
- "ram",
- "ran",
- "rao",
- "rap",
- "raq",
- "rar",
- "ras",
- "rat",
- "rau",
- "rav",
- "raw",
- "rax",
- "ray",
- "raz",
- "rbb",
- "rbk",
- "rbl",
- "rbp",
- "rcf",
- "rdb",
- "rea",
- "reb",
- "ree",
- "reg",
- "rei",
- "rej",
- "rel",
- "rem",
- "ren",
- "rer",
- "res",
- "ret",
- "rey",
- "rga",
- "rge",
- "rgk",
- "rgn",
- "rgr",
- "rgs",
- "rgu",
- "rhg",
- "rhp",
- "ria",
- "rib",
- "rie",
- "rif",
- "ril",
- "rim",
- "rin",
- "rir",
- "rit",
- "riu",
- "rjg",
- "rji",
- "rjs",
- "rka",
- "rkb",
- "rkh",
- "rki",
- "rkm",
- "rkt",
- "rkw",
- "rm",
- "rma",
- "rmb",
- "rmc",
- "rmd",
- "rme",
- "rmf",
- "rmg",
- "rmh",
- "rmi",
- "rmk",
- "rml",
- "rmm",
- "rmn",
- "rmo",
- "rmp",
- "rmq",
- "rmr",
- "rms",
- "rmt",
- "rmu",
- "rmv",
- "rmw",
- "rmx",
- "rmy",
- "rmz",
- "rn",
- "rna",
- "rnb",
- "rnd",
- "rng",
- "rnl",
- "rnn",
- "rnp",
- "rnr",
- "rnw",
- "ro",
- "roa",
- "rob",
- "roc",
- "rod",
- "roe",
- "rof",
- "rog",
- "rol",
- "rom",
- "roo",
- "rop",
- "ror",
- "rou",
- "row",
- "rpn",
- "rpt",
- "rri",
- "rrm",
- "rro",
- "rrt",
- "rsb",
- "rsi",
- "rsk",
- "rsl",
- "rsm",
- "rsn",
- "rsw",
- "rtc",
- "rth",
- "rtm",
- "rts",
- "rtw",
- "ru",
- "rub",
- "ruc",
- "rue",
- "ruf",
- "rug",
- "ruh",
- "rui",
- "ruk",
- "ruo",
- "rup",
- "ruq",
- "rut",
- "ruu",
- "ruy",
- "ruz",
- "rw",
- "rwa",
- "rwk",
- "rwl",
- "rwm",
- "rwo",
- "rwr",
- "rxd",
- "rxw",
- "ryn",
- "rys",
- "ryu",
- "rzh",
- "sa",
- "saa",
- "sab",
- "sac",
- "sad",
- "sae",
- "saf",
- "sah",
- "sai",
- "saj",
- "sak",
- "sal",
- "sam",
- "sao",
- "sap",
- "saq",
- "sar",
- "sas",
- "sat",
- "sau",
- "sav",
- "saw",
- "sax",
- "say",
- "saz",
- "sba",
- "sbb",
- "sbc",
- "sbd",
- "sbe",
- "sbf",
- "sbg",
- "sbh",
- "sbi",
- "sbj",
- "sbk",
- "sbl",
- "sbm",
- "sbn",
- "sbo",
- "sbp",
- "sbq",
- "sbr",
- "sbs",
- "sbt",
- "sbu",
- "sbv",
- "sbw",
- "sbx",
- "sby",
- "sbz",
- "sc",
- "sca",
- "scb",
- "sce",
- "scf",
- "scg",
- "sch",
- "sci",
- "sck",
- "scl",
- "scn",
- "sco",
- "scp",
- "scq",
- "scs",
- "sct",
- "scu",
- "scv",
- "scw",
- "scx",
- "sd",
- "sda",
- "sdb",
- "sdc",
- "sde",
- "sdf",
- "sdg",
- "sdh",
- "sdj",
- "sdk",
- "sdl",
- "sdm",
- "sdn",
- "sdo",
- "sdp",
- "sdq",
- "sdr",
- "sds",
- "sdt",
- "sdu",
- "sdv",
- "sdx",
- "sdz",
- "se",
- "sea",
- "seb",
- "sec",
- "sed",
- "see",
- "sef",
- "seg",
- "seh",
- "sei",
- "sej",
- "sek",
- "sel",
- "sem",
- "sen",
- "seo",
- "sep",
- "seq",
- "ser",
- "ses",
- "set",
- "seu",
- "sev",
- "sew",
- "sey",
- "sez",
- "sfb",
- "sfe",
- "sfm",
- "sfs",
- "sfw",
- "sg",
- "sga",
- "sgb",
- "sgc",
- "sgd",
- "sge",
- "sgg",
- "sgh",
- "sgi",
- "sgj",
- "sgk",
- "sgl",
- "sgm",
- "sgn",
- "sgo",
- "sgp",
- "sgr",
- "sgs",
- "sgt",
- "sgu",
- "sgw",
- "sgx",
- "sgy",
- "sgz",
- "sh",
- "sha",
- "shb",
- "shc",
- "shd",
- "she",
- "shg",
- "shh",
- "shi",
- "shj",
- "shk",
- "shl",
- "shm",
- "shn",
- "sho",
- "shp",
- "shq",
- "shr",
- "shs",
- "sht",
- "shu",
- "shv",
- "shw",
- "shx",
- "shy",
- "shz",
- "si",
- "sia",
- "sib",
- "sid",
- "sie",
- "sif",
- "sig",
- "sih",
- "sii",
- "sij",
- "sik",
- "sil",
- "sim",
- "sio",
- "sip",
- "siq",
- "sir",
- "sis",
- "sit",
- "siu",
- "siv",
- "siw",
- "six",
- "siy",
- "siz",
- "sja",
- "sjb",
- "sjc",
- "sjd",
- "sje",
- "sjg",
- "sjk",
- "sjl",
- "sjm",
- "sjn",
- "sjo",
- "sjp",
- "sjr",
- "sjs",
- "sjt",
- "sju",
- "sjw",
- "sk",
- "ska",
- "skb",
- "skc",
- "skd",
- "ske",
- "skf",
- "skg",
- "skh",
- "ski",
- "skj",
- "skk",
- "skm",
- "skn",
- "sko",
- "skp",
- "skq",
- "skr",
- "sks",
- "skt",
- "sku",
- "skv",
- "skw",
- "skx",
- "sky",
- "skz",
- "sl",
- "sla",
- "slc",
- "sld",
- "sle",
- "slf",
- "slg",
- "slh",
- "sli",
- "slj",
- "sll",
- "slm",
- "sln",
- "slp",
- "slq",
- "slr",
- "sls",
- "slt",
- "slu",
- "slw",
- "slx",
- "sly",
- "slz",
- "sm",
- "sma",
- "smb",
- "smc",
- "smd",
- "smf",
- "smg",
- "smh",
- "smi",
- "smj",
- "smk",
- "sml",
- "smm",
- "smn",
- "smp",
- "smq",
- "smr",
- "sms",
- "smt",
- "smu",
- "smv",
- "smw",
- "smx",
- "smy",
- "smz",
- "sn",
- "snb",
- "snc",
- "sne",
- "snf",
- "sng",
- "snh",
- "sni",
- "snj",
- "snk",
- "snl",
- "snm",
- "snn",
- "sno",
- "snp",
- "snq",
- "snr",
- "sns",
- "snu",
- "snv",
- "snw",
- "snx",
- "sny",
- "snz",
- "so",
- "soa",
- "sob",
- "soc",
- "sod",
- "soe",
- "sog",
- "soh",
- "soi",
- "soj",
- "sok",
- "sol",
- "son",
- "soo",
- "sop",
- "soq",
- "sor",
- "sos",
- "sou",
- "sov",
- "sow",
- "sox",
- "soy",
- "soz",
- "spb",
- "spc",
- "spd",
- "spe",
- "spg",
- "spi",
- "spk",
- "spl",
- "spm",
- "spn",
- "spo",
- "spp",
- "spq",
- "spr",
- "sps",
- "spt",
- "spu",
- "spv",
- "spx",
- "spy",
- "sq",
- "sqa",
- "sqh",
- "sqj",
- "sqk",
- "sqm",
- "sqn",
- "sqo",
- "sqq",
- "sqr",
- "sqs",
- "sqt",
- "squ",
- "sqx",
- "sr",
- "sra",
- "srb",
- "src",
- "sre",
- "srf",
- "srg",
- "srh",
- "sri",
- "srk",
- "srl",
- "srm",
- "srn",
- "sro",
- "srq",
- "srr",
- "srs",
- "srt",
- "sru",
- "srv",
- "srw",
- "srx",
- "sry",
- "srz",
- "ss",
- "ssa",
- "ssb",
- "ssc",
- "ssd",
- "sse",
- "ssf",
- "ssg",
- "ssh",
- "ssi",
- "ssj",
- "ssk",
- "ssl",
- "ssm",
- "ssn",
- "sso",
- "ssp",
- "ssq",
- "ssr",
- "sss",
- "sst",
- "ssu",
- "ssv",
- "ssx",
- "ssy",
- "ssz",
- "st",
- "sta",
- "stb",
- "std",
- "ste",
- "stf",
- "stg",
- "sth",
- "sti",
- "stj",
- "stk",
- "stl",
- "stm",
- "stn",
- "sto",
- "stp",
- "stq",
- "str",
- "sts",
- "stt",
- "stu",
- "stv",
- "stw",
- "sty",
- "su",
- "sua",
- "sub",
- "suc",
- "sue",
- "sug",
- "sui",
- "suj",
- "suk",
- "sul",
- "sum",
- "suo",
- "suq",
- "sur",
- "sus",
- "sut",
- "suv",
- "suw",
- "sux",
- "suy",
- "suz",
- "sv",
- "sva",
- "svb",
- "svc",
- "sve",
- "svk",
- "svm",
- "svr",
- "svs",
- "svx",
- "sw",
- "swb",
- "swc",
- "swf",
- "swg",
- "swh",
- "swi",
- "swj",
- "swk",
- "swl",
- "swm",
- "swn",
- "swo",
- "swp",
- "swq",
- "swr",
- "sws",
- "swt",
- "swu",
- "swv",
- "sww",
- "swx",
- "swy",
- "sxb",
- "sxc",
- "sxe",
- "sxg",
- "sxk",
- "sxl",
- "sxm",
- "sxn",
- "sxo",
- "sxr",
- "sxs",
- "sxu",
- "sxw",
- "sya",
- "syb",
- "syc",
- "syd",
- "syi",
- "syk",
- "syl",
- "sym",
- "syn",
- "syo",
- "syr",
- "sys",
- "syw",
- "syx",
- "syy",
- "sza",
- "szb",
- "szc",
- "szd",
- "sze",
- "szg",
- "szl",
- "szn",
- "szp",
- "szs",
- "szv",
- "szw",
- "szy",
- "ta",
- "taa",
- "tab",
- "tac",
- "tad",
- "tae",
- "taf",
- "tag",
- "tai",
- "taj",
- "tak",
- "tal",
- "tan",
- "tao",
- "tap",
- "taq",
- "tar",
- "tas",
- "tau",
- "tav",
- "taw",
- "tax",
- "tay",
- "taz",
- "tba",
- "tbb",
- "tbc",
- "tbd",
- "tbe",
- "tbf",
- "tbg",
- "tbh",
- "tbi",
- "tbj",
- "tbk",
- "tbl",
- "tbm",
- "tbn",
- "tbo",
- "tbp",
- "tbq",
- "tbr",
- "tbs",
- "tbt",
- "tbu",
- "tbv",
- "tbw",
- "tbx",
- "tby",
- "tbz",
- "tca",
- "tcb",
- "tcc",
- "tcd",
- "tce",
- "tcf",
- "tcg",
- "tch",
- "tci",
- "tck",
- "tcl",
- "tcm",
- "tcn",
- "tco",
- "tcp",
- "tcq",
- "tcs",
- "tct",
- "tcu",
- "tcw",
- "tcx",
- "tcy",
- "tcz",
- "tda",
- "tdb",
- "tdc",
- "tdd",
- "tde",
- "tdf",
- "tdg",
- "tdh",
- "tdi",
- "tdj",
- "tdk",
- "tdl",
- "tdm",
- "tdn",
- "tdo",
- "tdq",
- "tdr",
- "tds",
- "tdt",
- "tdu",
- "tdv",
- "tdx",
- "tdy",
- "te",
- "tea",
- "teb",
- "tec",
- "ted",
- "tee",
- "tef",
- "teg",
- "teh",
- "tei",
- "tek",
- "tem",
- "ten",
- "teo",
- "tep",
- "teq",
- "ter",
- "tes",
- "tet",
- "teu",
- "tev",
- "tew",
- "tex",
- "tey",
- "tez",
- "tfi",
- "tfn",
- "tfo",
- "tfr",
- "tft",
- "tg",
- "tga",
- "tgb",
- "tgc",
- "tgd",
- "tge",
- "tgf",
- "tgg",
- "tgh",
- "tgi",
- "tgj",
- "tgn",
- "tgo",
- "tgp",
- "tgq",
- "tgr",
- "tgs",
- "tgt",
- "tgu",
- "tgv",
- "tgw",
- "tgx",
- "tgy",
- "tgz",
- "th",
- "thc",
- "thd",
- "the",
- "thf",
- "thh",
- "thi",
- "thk",
- "thl",
- "thm",
- "thn",
- "thp",
- "thq",
- "thr",
- "ths",
- "tht",
- "thu",
- "thv",
- "thw",
- "thx",
- "thy",
- "thz",
- "ti",
- "tia",
- "tic",
- "tid",
- "tie",
- "tif",
- "tig",
- "tih",
- "tii",
- "tij",
- "tik",
- "til",
- "tim",
- "tin",
- "tio",
- "tip",
- "tiq",
- "tis",
- "tit",
- "tiu",
- "tiv",
- "tiw",
- "tix",
- "tiy",
- "tiz",
- "tja",
- "tjg",
- "tji",
- "tjj",
- "tjl",
- "tjm",
- "tjn",
- "tjo",
- "tjp",
- "tjs",
- "tju",
- "tjw",
- "tk",
- "tka",
- "tkb",
- "tkd",
- "tke",
- "tkf",
- "tkg",
- "tkk",
- "tkl",
- "tkm",
- "tkn",
- "tkp",
- "tkq",
- "tkr",
- "tks",
- "tkt",
- "tku",
- "tkv",
- "tkw",
- "tkx",
- "tkz",
- "tl",
- "tla",
- "tlb",
- "tlc",
- "tld",
- "tlf",
- "tlg",
- "tlh",
- "tli",
- "tlj",
- "tlk",
- "tll",
- "tlm",
- "tln",
- "tlo",
- "tlp",
- "tlq",
- "tlr",
- "tls",
- "tlt",
- "tlu",
- "tlv",
- "tlw",
- "tlx",
- "tly",
- "tma",
- "tmb",
- "tmc",
- "tmd",
- "tme",
- "tmf",
- "tmg",
- "tmh",
- "tmi",
- "tmj",
- "tmk",
- "tml",
- "tmm",
- "tmn",
- "tmo",
- "tmp",
- "tmq",
- "tmr",
- "tms",
- "tmt",
- "tmu",
- "tmv",
- "tmw",
- "tmy",
- "tmz",
- "tn",
- "tna",
- "tnb",
- "tnc",
- "tnd",
- "tne",
- "tnf",
- "tng",
- "tnh",
- "tni",
- "tnk",
- "tnl",
- "tnm",
- "tnn",
- "tno",
- "tnp",
- "tnq",
- "tnr",
- "tns",
- "tnt",
- "tnu",
- "tnv",
- "tnw",
- "tnx",
- "tny",
- "tnz",
- "to",
- "tob",
- "toc",
- "tod",
- "toe",
- "tof",
- "tog",
- "toh",
- "toi",
- "toj",
- "tok",
- "tol",
- "tom",
- "too",
- "top",
- "toq",
- "tor",
- "tos",
- "tou",
- "tov",
- "tow",
- "tox",
- "toy",
- "toz",
- "tpa",
- "tpc",
- "tpe",
- "tpf",
- "tpg",
- "tpi",
- "tpj",
- "tpk",
- "tpl",
- "tpm",
- "tpn",
- "tpo",
- "tpp",
- "tpq",
- "tpr",
- "tpt",
- "tpu",
- "tpv",
- "tpw",
- "tpx",
- "tpy",
- "tpz",
- "tqb",
- "tql",
- "tqm",
- "tqn",
- "tqo",
- "tqp",
- "tqq",
- "tqr",
- "tqt",
- "tqu",
- "tqw",
- "tr",
- "tra",
- "trb",
- "trc",
- "trd",
- "tre",
- "trf",
- "trg",
- "trh",
- "tri",
- "trj",
- "trk",
- "trl",
- "trm",
- "trn",
- "tro",
- "trp",
- "trq",
- "trr",
- "trs",
- "trt",
- "tru",
- "trv",
- "trw",
- "trx",
- "try",
- "trz",
- "ts",
- "tsa",
- "tsb",
- "tsc",
- "tsd",
- "tse",
- "tsf",
- "tsg",
- "tsh",
- "tsi",
- "tsj",
- "tsk",
- "tsl",
- "tsm",
- "tsp",
- "tsq",
- "tsr",
- "tss",
- "tst",
- "tsu",
- "tsv",
- "tsw",
- "tsx",
- "tsy",
- "tsz",
- "tt",
- "tta",
- "ttb",
- "ttc",
- "ttd",
- "tte",
- "ttf",
- "ttg",
- "tth",
- "tti",
- "ttj",
- "ttk",
- "ttl",
- "ttm",
- "ttn",
- "tto",
- "ttp",
- "ttq",
- "ttr",
- "tts",
- "ttt",
- "ttu",
- "ttv",
- "ttw",
- "tty",
- "ttz",
- "tua",
- "tub",
- "tuc",
- "tud",
- "tue",
- "tuf",
- "tug",
- "tuh",
- "tui",
- "tuj",
- "tul",
- "tum",
- "tun",
- "tuo",
- "tup",
- "tuq",
- "tus",
- "tut",
- "tuu",
- "tuv",
- "tuw",
- "tux",
- "tuy",
- "tuz",
- "tva",
- "tvd",
- "tve",
- "tvi",
- "tvk",
- "tvl",
- "tvm",
- "tvn",
- "tvo",
- "tvs",
- "tvt",
- "tvu",
- "tvw",
- "tvx",
- "tvy",
- "tw",
- "twa",
- "twb",
- "twc",
- "twd",
- "twe",
- "twf",
- "twg",
- "twh",
- "twl",
- "twm",
- "twn",
- "two",
- "twp",
- "twq",
- "twr",
- "twt",
- "twu",
- "tww",
- "twx",
- "twy",
- "txa",
- "txb",
- "txc",
- "txe",
- "txg",
- "txh",
- "txi",
- "txj",
- "txm",
- "txn",
- "txo",
- "txq",
- "txr",
- "txs",
- "txt",
- "txu",
- "txx",
- "txy",
- "ty",
- "tya",
- "tye",
- "tyh",
- "tyi",
- "tyj",
- "tyl",
- "tyn",
- "typ",
- "tyr",
- "tys",
- "tyt",
- "tyu",
- "tyv",
- "tyx",
- "tyy",
- "tyz",
- "tza",
- "tzh",
- "tzj",
- "tzl",
- "tzm",
- "tzn",
- "tzo",
- "tzx",
- "uam",
- "uan",
- "uar",
- "uba",
- "ubi",
- "ubl",
- "ubr",
- "ubu",
- "uby",
- "uda",
- "ude",
- "udg",
- "udi",
- "udj",
- "udl",
- "udm",
- "udu",
- "ues",
- "ufi",
- "ug",
- "uga",
- "ugb",
- "uge",
- "ugh",
- "ugn",
- "ugo",
- "ugy",
- "uha",
- "uhn",
- "uis",
- "uiv",
- "uji",
- "uk",
- "uka",
- "ukg",
- "ukh",
- "uki",
- "ukk",
- "ukl",
- "ukp",
- "ukq",
- "uks",
- "uku",
- "ukv",
- "ukw",
- "uky",
- "ula",
- "ulb",
- "ulc",
- "ule",
- "ulf",
- "uli",
- "ulk",
- "ull",
- "ulm",
- "uln",
- "ulu",
- "ulw",
- "uly",
- "uma",
- "umb",
- "umc",
- "umd",
- "umg",
- "umi",
- "umm",
- "umn",
- "umo",
- "ump",
- "umr",
- "ums",
- "umu",
- "una",
- "und",
- "une",
- "ung",
- "uni",
- "unk",
- "unm",
- "unn",
- "unp",
- "unr",
- "unu",
- "unx",
- "unz",
- "uok",
- "uon",
- "upi",
- "upv",
- "ur",
- "ura",
- "urb",
- "urc",
- "ure",
- "urf",
- "urg",
- "urh",
- "uri",
- "urj",
- "urk",
- "url",
- "urm",
- "urn",
- "uro",
- "urp",
- "urr",
- "urt",
- "uru",
- "urv",
- "urw",
- "urx",
- "ury",
- "urz",
- "usa",
- "ush",
- "usi",
- "usk",
- "usp",
- "uss",
- "usu",
- "uta",
- "ute",
- "uth",
- "utp",
- "utr",
- "utu",
- "uum",
- "uun",
- "uur",
- "uuu",
- "uve",
- "uvh",
- "uvl",
- "uwa",
- "uya",
- "uz",
- "uzn",
- "uzs",
- "vaa",
- "vae",
- "vaf",
- "vag",
- "vah",
- "vai",
- "vaj",
- "val",
- "vam",
- "van",
- "vao",
- "vap",
- "var",
- "vas",
- "vau",
- "vav",
- "vay",
- "vbb",
- "vbk",
- "ve",
- "vec",
- "ved",
- "vel",
- "vem",
- "veo",
- "vep",
- "ver",
- "vgr",
- "vgt",
- "vi",
- "vic",
- "vid",
- "vif",
- "vig",
- "vil",
- "vin",
- "vis",
- "vit",
- "viv",
- "vjk",
- "vka",
- "vki",
- "vkj",
- "vkk",
- "vkl",
- "vkm",
- "vkn",
- "vko",
- "vkp",
- "vkt",
- "vku",
- "vkz",
- "vlp",
- "vls",
- "vma",
- "vmb",
- "vmc",
- "vmd",
- "vme",
- "vmf",
- "vmg",
- "vmh",
- "vmi",
- "vmj",
- "vmk",
- "vml",
- "vmm",
- "vmp",
- "vmq",
- "vmr",
- "vms",
- "vmu",
- "vmv",
- "vmw",
- "vmx",
- "vmy",
- "vmz",
- "vnk",
- "vnm",
- "vnp",
- "vo",
- "vor",
- "vot",
- "vra",
- "vro",
- "vrs",
- "vrt",
- "vsi",
- "vsl",
- "vsn",
- "vsv",
- "vto",
- "vum",
- "vun",
- "vut",
- "vwa",
- "wa",
- "waa",
- "wab",
- "wac",
- "wad",
- "wae",
- "waf",
- "wag",
- "wah",
- "wai",
- "waj",
- "wak",
- "wal",
- "wam",
- "wan",
- "wao",
- "wap",
- "waq",
- "war",
- "was",
- "wat",
- "wau",
- "wav",
- "waw",
- "wax",
- "way",
- "waz",
- "wba",
- "wbb",
- "wbe",
- "wbf",
- "wbh",
- "wbi",
- "wbj",
- "wbk",
- "wbl",
- "wbm",
- "wbp",
- "wbq",
- "wbr",
- "wbs",
- "wbt",
- "wbv",
- "wbw",
- "wca",
- "wci",
- "wdd",
- "wdg",
- "wdj",
- "wdk",
- "wdt",
- "wdu",
- "wdy",
- "wea",
- "wec",
- "wed",
- "weg",
- "weh",
- "wei",
- "wem",
- "wen",
- "weo",
- "wep",
- "wer",
- "wes",
- "wet",
- "weu",
- "wew",
- "wfg",
- "wga",
- "wgb",
- "wgg",
- "wgi",
- "wgo",
- "wgu",
- "wgw",
- "wgy",
- "wha",
- "whg",
- "whk",
- "whu",
- "wib",
- "wic",
- "wie",
- "wif",
- "wig",
- "wih",
- "wii",
- "wij",
- "wik",
- "wil",
- "wim",
- "win",
- "wir",
- "wit",
- "wiu",
- "wiv",
- "wiw",
- "wiy",
- "wja",
- "wji",
- "wka",
- "wkb",
- "wkd",
- "wkl",
- "wkr",
- "wku",
- "wkw",
- "wky",
- "wla",
- "wlc",
- "wle",
- "wlg",
- "wlh",
- "wli",
- "wlk",
- "wll",
- "wlm",
- "wlo",
- "wlr",
- "wls",
- "wlu",
- "wlv",
- "wlw",
- "wlx",
- "wly",
- "wma",
- "wmb",
- "wmc",
- "wmd",
- "wme",
- "wmg",
- "wmh",
- "wmi",
- "wmm",
- "wmn",
- "wmo",
- "wms",
- "wmt",
- "wmw",
- "wmx",
- "wnb",
- "wnc",
- "wnd",
- "wne",
- "wng",
- "wni",
- "wnk",
- "wnm",
- "wnn",
- "wno",
- "wnp",
- "wnu",
- "wnw",
- "wny",
- "wo",
- "woa",
- "wob",
- "woc",
- "wod",
- "woe",
- "wof",
- "wog",
- "woi",
- "wok",
- "wom",
- "won",
- "woo",
- "wor",
- "wos",
- "wow",
- "woy",
- "wpc",
- "wra",
- "wrb",
- "wrd",
- "wrg",
- "wrh",
- "wri",
- "wrk",
- "wrl",
- "wrm",
- "wrn",
- "wro",
- "wrp",
- "wrr",
- "wrs",
- "wru",
- "wrv",
- "wrw",
- "wrx",
- "wry",
- "wrz",
- "wsa",
- "wsg",
- "wsi",
- "wsk",
- "wsr",
- "wss",
- "wsu",
- "wsv",
- "wtb",
- "wtf",
- "wth",
- "wti",
- "wtk",
- "wtm",
- "wtw",
- "wua",
- "wub",
- "wud",
- "wuh",
- "wul",
- "wum",
- "wun",
- "wur",
- "wut",
- "wuu",
- "wuv",
- "wux",
- "wuy",
- "wwa",
- "wwb",
- "wwo",
- "wwr",
- "www",
- "wxa",
- "wxw",
- "wya",
- "wyb",
- "wyi",
- "wym",
- "wyn",
- "wyr",
- "wyy",
- "xaa",
- "xab",
- "xac",
- "xad",
- "xae",
- "xag",
- "xai",
- "xaj",
- "xak",
- "xal",
- "xam",
- "xan",
- "xao",
- "xap",
- "xaq",
- "xar",
- "xas",
- "xat",
- "xau",
- "xav",
- "xaw",
- "xay",
- "xba",
- "xbb",
- "xbc",
- "xbd",
- "xbe",
- "xbg",
- "xbi",
- "xbj",
- "xbm",
- "xbn",
- "xbo",
- "xbp",
- "xbr",
- "xbw",
- "xbx",
- "xby",
- "xcb",
- "xcc",
- "xce",
- "xcg",
- "xch",
- "xcl",
- "xcm",
- "xcn",
- "xco",
- "xcr",
- "xct",
- "xcu",
- "xcv",
- "xcw",
- "xcy",
- "xda",
- "xdc",
- "xdk",
- "xdm",
- "xdo",
- "xdq",
- "xdy",
- "xeb",
- "xed",
- "xeg",
- "xel",
- "xem",
- "xep",
- "xer",
- "xes",
- "xet",
- "xeu",
- "xfa",
- "xga",
- "xgb",
- "xgd",
- "xgf",
- "xgg",
- "xgi",
- "xgl",
- "xgm",
- "xgn",
- "xgr",
- "xgu",
- "xgw",
- "xh",
- "xha",
- "xhc",
- "xhd",
- "xhe",
- "xhm",
- "xhr",
- "xht",
- "xhu",
- "xhv",
- "xia",
- "xib",
- "xii",
- "xil",
- "xin",
- "xip",
- "xir",
- "xis",
- "xiv",
- "xiy",
- "xjb",
- "xjt",
- "xka",
- "xkb",
- "xkc",
- "xkd",
- "xke",
- "xkf",
- "xkg",
- "xkh",
- "xki",
- "xkj",
- "xkk",
- "xkl",
- "xkn",
- "xko",
- "xkp",
- "xkq",
- "xkr",
- "xks",
- "xkt",
- "xku",
- "xkv",
- "xkw",
- "xkx",
- "xky",
- "xkz",
- "xla",
- "xlb",
- "xlc",
- "xld",
- "xle",
- "xlg",
- "xli",
- "xln",
- "xlo",
- "xlp",
- "xls",
- "xlu",
- "xly",
- "xma",
- "xmb",
- "xmc",
- "xmd",
- "xme",
- "xmf",
- "xmg",
- "xmh",
- "xmj",
- "xmk",
- "xml",
- "xmm",
- "xmn",
- "xmo",
- "xmp",
- "xmq",
- "xmr",
- "xms",
- "xmt",
- "xmu",
- "xmv",
- "xmw",
- "xmx",
- "xmy",
- "xmz",
- "xna",
- "xnb",
- "xnd",
- "xng",
- "xnh",
- "xni",
- "xnj",
- "xnk",
- "xnm",
- "xnn",
- "xno",
- "xnq",
- "xnr",
- "xns",
- "xnt",
- "xnu",
- "xny",
- "xnz",
- "xoc",
- "xod",
- "xog",
- "xoi",
- "xok",
- "xom",
- "xon",
- "xoo",
- "xop",
- "xor",
- "xow",
- "xpa",
- "xpb",
- "xpc",
- "xpd",
- "xpe",
- "xpf",
- "xpg",
- "xph",
- "xpi",
- "xpj",
- "xpk",
- "xpl",
- "xpm",
- "xpn",
- "xpo",
- "xpp",
- "xpq",
- "xpr",
- "xps",
- "xpt",
- "xpu",
- "xpv",
- "xpw",
- "xpx",
- "xpy",
- "xpz",
- "xqa",
- "xqt",
- "xra",
- "xrb",
- "xrd",
- "xre",
- "xrg",
- "xri",
- "xrm",
- "xrn",
- "xrq",
- "xrr",
- "xrt",
- "xru",
- "xrw",
- "xsa",
- "xsb",
- "xsc",
- "xsd",
- "xse",
- "xsh",
- "xsi",
- "xsj",
- "xsl",
- "xsm",
- "xsn",
- "xso",
- "xsp",
- "xsq",
- "xsr",
- "xss",
- "xsu",
- "xsv",
- "xsy",
- "xta",
- "xtb",
- "xtc",
- "xtd",
- "xte",
- "xtg",
- "xth",
- "xti",
- "xtj",
- "xtl",
- "xtm",
- "xtn",
- "xto",
- "xtp",
- "xtq",
- "xtr",
- "xts",
- "xtt",
- "xtu",
- "xtv",
- "xtw",
- "xty",
- "xtz",
- "xua",
- "xub",
- "xud",
- "xug",
- "xuj",
- "xul",
- "xum",
- "xun",
- "xuo",
- "xup",
- "xur",
- "xut",
- "xuu",
- "xve",
- "xvi",
- "xvn",
- "xvo",
- "xvs",
- "xwa",
- "xwc",
- "xwd",
- "xwe",
- "xwg",
- "xwj",
- "xwk",
- "xwl",
- "xwo",
- "xwr",
- "xwt",
- "xww",
- "xxb",
- "xxk",
- "xxm",
- "xxr",
- "xxt",
- "xya",
- "xyb",
- "xyj",
- "xyk",
- "xyl",
- "xyt",
- "xyy",
- "xzh",
- "xzm",
- "xzp",
- "yaa",
- "yab",
- "yac",
- "yad",
- "yae",
- "yaf",
- "yag",
- "yah",
- "yai",
- "yaj",
- "yak",
- "yal",
- "yam",
- "yan",
- "yao",
- "yap",
- "yaq",
- "yar",
- "yas",
- "yat",
- "yau",
- "yav",
- "yaw",
- "yax",
- "yay",
- "yaz",
- "yba",
- "ybb",
- "ybd",
- "ybe",
- "ybh",
- "ybi",
- "ybj",
- "ybk",
- "ybl",
- "ybm",
- "ybn",
- "ybo",
- "ybx",
- "yby",
- "ych",
- "ycl",
- "ycn",
- "ycp",
- "ycr",
- "yda",
- "ydd",
- "yde",
- "ydg",
- "ydk",
- "yds",
- "yea",
- "yec",
- "yee",
- "yei",
- "yej",
- "yel",
- "yen",
- "yer",
- "yes",
- "yet",
- "yeu",
- "yev",
- "yey",
- "yga",
- "ygi",
- "ygl",
- "ygm",
- "ygp",
- "ygr",
- "ygs",
- "ygu",
- "ygw",
- "yha",
- "yhd",
- "yhl",
- "yhs",
- "yi",
- "yia",
- "yif",
- "yig",
- "yih",
- "yii",
- "yij",
- "yik",
- "yil",
- "yim",
- "yin",
- "yip",
- "yiq",
- "yir",
- "yis",
- "yit",
- "yiu",
- "yiv",
- "yix",
- "yiy",
- "yiz",
- "yka",
- "ykg",
- "ykh",
- "yki",
- "ykk",
- "ykl",
- "ykm",
- "ykn",
- "yko",
- "ykr",
- "ykt",
- "yku",
- "yky",
- "yla",
- "ylb",
- "yle",
- "ylg",
- "yli",
- "yll",
- "ylm",
- "yln",
- "ylo",
- "ylr",
- "ylu",
- "yly",
- "yma",
- "ymb",
- "ymc",
- "ymd",
- "yme",
- "ymg",
- "ymh",
- "ymi",
- "ymk",
- "yml",
- "ymm",
- "ymn",
- "ymo",
- "ymp",
- "ymq",
- "ymr",
- "yms",
- "ymt",
- "ymx",
- "ymz",
- "yna",
- "ynb",
- "ynd",
- "yne",
- "yng",
- "ynh",
- "ynk",
- "ynl",
- "ynn",
- "yno",
- "ynq",
- "yns",
- "ynu",
- "yo",
- "yob",
- "yog",
- "yoi",
- "yok",
- "yol",
- "yom",
- "yon",
- "yos",
- "yot",
- "yox",
- "yoy",
- "ypa",
- "ypb",
- "ypg",
- "yph",
- "ypk",
- "ypm",
- "ypn",
- "ypo",
- "ypp",
- "ypz",
- "yra",
- "yrb",
- "yre",
- "yri",
- "yrk",
- "yrl",
- "yrm",
- "yrn",
- "yro",
- "yrs",
- "yrw",
- "yry",
- "ysc",
- "ysd",
- "ysg",
- "ysl",
- "ysm",
- "ysn",
- "yso",
- "ysp",
- "ysr",
- "yss",
- "ysy",
- "yta",
- "ytl",
- "ytp",
- "ytw",
- "yty",
- "yua",
- "yub",
- "yuc",
- "yud",
- "yue",
- "yuf",
- "yug",
- "yui",
- "yuj",
- "yuk",
- "yul",
- "yum",
- "yun",
- "yup",
- "yuq",
- "yur",
- "yut",
- "yuu",
- "yuw",
- "yux",
- "yuy",
- "yuz",
- "yva",
- "yvt",
- "ywa",
- "ywg",
- "ywl",
- "ywn",
- "ywq",
- "ywr",
- "ywt",
- "ywu",
- "yww",
- "yxa",
- "yxg",
- "yxl",
- "yxm",
- "yxu",
- "yxy",
- "yyr",
- "yyu",
- "yyz",
- "yzg",
- "yzk",
- "za",
- "zaa",
- "zab",
- "zac",
- "zad",
- "zae",
- "zaf",
- "zag",
- "zah",
- "zai",
- "zaj",
- "zak",
- "zal",
- "zam",
- "zao",
- "zap",
- "zaq",
- "zar",
- "zas",
- "zat",
- "zau",
- "zav",
- "zaw",
- "zax",
- "zay",
- "zaz",
- "zba",
- "zbc",
- "zbe",
- "zbl",
- "zbt",
- "zbu",
- "zbw",
- "zca",
- "zcd",
- "zch",
- "zdj",
- "zea",
- "zeg",
- "zeh",
- "zem",
- "zen",
- "zga",
- "zgb",
- "zgh",
- "zgm",
- "zgn",
- "zgr",
- "zh",
- "zhb",
- "zhd",
- "zhi",
- "zhn",
- "zhw",
- "zhx",
- "zia",
- "zib",
- "zik",
- "zil",
- "zim",
- "zin",
- "zir",
- "ziw",
- "ziz",
- "zka",
- "zkb",
- "zkd",
- "zkg",
- "zkh",
- "zkk",
- "zkn",
- "zko",
- "zkp",
- "zkr",
- "zkt",
- "zku",
- "zkv",
- "zkz",
- "zla",
- "zle",
- "zlj",
- "zlm",
- "zln",
- "zlq",
- "zls",
- "zlu",
- "zlw",
- "zma",
- "zmb",
- "zmc",
- "zmd",
- "zme",
- "zmf",
- "zmg",
- "zmh",
- "zmi",
- "zmj",
- "zmk",
- "zml",
- "zmm",
- "zmn",
- "zmo",
- "zmp",
- "zmq",
- "zmr",
- "zms",
- "zmt",
- "zmu",
- "zmv",
- "zmw",
- "zmx",
- "zmy",
- "zmz",
- "zna",
- "znd",
- "zne",
- "zng",
- "znk",
- "zns",
- "zoc",
- "zoh",
- "zom",
- "zoo",
- "zoq",
- "zor",
- "zos",
- "zpa",
- "zpb",
- "zpc",
- "zpd",
- "zpe",
- "zpf",
- "zpg",
- "zph",
- "zpi",
- "zpj",
- "zpk",
- "zpl",
- "zpm",
- "zpn",
- "zpo",
- "zpp",
- "zpq",
- "zpr",
- "zps",
- "zpt",
- "zpu",
- "zpv",
- "zpw",
- "zpx",
- "zpy",
- "zpz",
- "zqe",
- "zra",
- "zrg",
- "zrn",
- "zro",
- "zrp",
- "zrs",
- "zsa",
- "zsk",
- "zsl",
- "zsm",
- "zsr",
- "zsu",
- "zte",
- "ztg",
- "ztl",
- "ztm",
- "ztn",
- "ztp",
- "ztq",
- "zts",
- "ztt",
- "ztu",
- "ztx",
- "zty",
- "zu",
- "zua",
- "zuh",
- "zum",
- "zun",
- "zuy",
- "zwa",
- "zxx",
- "zyb",
- "zyg",
- "zyj",
- "zyn",
- "zyp",
- "zza",
- "zzj"
- ],
- "scripts": [
- "Adlm",
- "Afak",
- "Aghb",
- "Ahom",
- "Arab",
- "Aran",
- "Armi",
- "Armn",
- "Avst",
- "Bali",
- "Bamu",
- "Bass",
- "Batk",
- "Beng",
- "Berf",
- "Bhks",
- "Blis",
- "Bopo",
- "Brah",
- "Brai",
- "Bugi",
- "Buhd",
- "Cakm",
- "Cans",
- "Cari",
- "Cham",
- "Cher",
- "Chis",
- "Chrs",
- "Cirt",
- "Copt",
- "Cpmn",
- "Cprt",
- "Cyrl",
- "Cyrs",
- "Deva",
- "Diak",
- "Dogr",
- "Dsrt",
- "Dupl",
- "Egyd",
- "Egyh",
- "Egyp",
- "Elba",
- "Elym",
- "Ethi",
- "Gara",
- "Geok",
- "Geor",
- "Glag",
- "Gong",
- "Gonm",
- "Goth",
- "Gran",
- "Grek",
- "Gujr",
- "Gukh",
- "Guru",
- "Hanb",
- "Hang",
- "Hani",
- "Hano",
- "Hans",
- "Hant",
- "Hatr",
- "Hebr",
- "Hira",
- "Hluw",
- "Hmng",
- "Hmnp",
- "Hntl",
- "Hrkt",
- "Hung",
- "Inds",
- "Ital",
- "Jamo",
- "Java",
- "Jpan",
- "Jurc",
- "Kali",
- "Kana",
- "Kawi",
- "Khar",
- "Khmr",
- "Khoj",
- "Kitl",
- "Kits",
- "Knda",
- "Kore",
- "Kpel",
- "Krai",
- "Kthi",
- "Lana",
- "Laoo",
- "Latf",
- "Latg",
- "Latn",
- "Leke",
- "Lepc",
- "Limb",
- "Lina",
- "Linb",
- "Lisu",
- "Loma",
- "Lyci",
- "Lydi",
- "Mahj",
- "Maka",
- "Mand",
- "Mani",
- "Marc",
- "Maya",
- "Medf",
- "Mend",
- "Merc",
- "Mero",
- "Mlym",
- "Modi",
- "Mong",
- "Moon",
- "Mroo",
- "Mtei",
- "Mult",
- "Mymr",
- "Nagm",
- "Nand",
- "Narb",
- "Nbat",
- "Newa",
- "Nkdb",
- "Nkgb",
- "Nkoo",
- "Nshu",
- "Ogam",
- "Olck",
- "Onao",
- "Orkh",
- "Orya",
- "Osge",
- "Osma",
- "Ougr",
- "Palm",
- "Pauc",
- "Pcun",
- "Pelm",
- "Perm",
- "Phag",
- "Phli",
- "Phlp",
- "Phlv",
- "Phnx",
- "Piqd",
- "Plrd",
- "Prti",
- "Psin",
- "Qaaa..qabx",
- "Ranj",
- "Rjng",
- "Rohg",
- "Roro",
- "Runr",
- "Samr",
- "Sara",
- "Sarb",
- "Saur",
- "Seal",
- "Sgnw",
- "Shaw",
- "Shrd",
- "Shui",
- "Sidd",
- "Sidt",
- "Sind",
- "Sinh",
- "Sogd",
- "Sogo",
- "Sora",
- "Soyo",
- "Sund",
- "Sunu",
- "Sylo",
- "Syrc",
- "Syre",
- "Syrj",
- "Syrn",
- "Tagb",
- "Takr",
- "Tale",
- "Talu",
- "Taml",
- "Tang",
- "Tavt",
- "Tayo",
- "Telu",
- "Teng",
- "Tfng",
- "Tglg",
- "Thaa",
- "Thai",
- "Tibt",
- "Tirh",
- "Tnsa",
- "Todr",
- "Tols",
- "Toto",
- "Tutg",
- "Ugar",
- "Vaii",
- "Visp",
- "Vith",
- "Wara",
- "Wcho",
- "Wole",
- "Xpeo",
- "Xsux",
- "Yezi",
- "Yiii",
- "Zanb",
- "Zinh",
- "Zmth",
- "Zsye",
- "Zsym",
- "Zxxx",
- "Zyyy",
- "Zzzz"
- ],
- "regions": [
- "001",
- "002",
- "003",
- "005",
- "009",
- "011",
- "013",
- "014",
- "015",
- "017",
- "018",
- "019",
- "021",
- "029",
- "030",
- "034",
- "035",
- "039",
- "053",
- "054",
- "057",
- "061",
- "142",
- "143",
- "145",
- "150",
- "151",
- "154",
- "155",
- "202",
- "419",
- "AA",
- "AC",
- "AD",
- "AE",
- "AF",
- "AG",
- "AI",
- "AL",
- "AM",
- "AN",
- "AO",
- "AQ",
- "AR",
- "AS",
- "AT",
- "AU",
- "AW",
- "AX",
- "AZ",
- "BA",
- "BB",
- "BD",
- "BE",
- "BF",
- "BG",
- "BH",
- "BI",
- "BJ",
- "BL",
- "BM",
- "BN",
- "BO",
- "BQ",
- "BR",
- "BS",
- "BT",
- "BU",
- "BV",
- "BW",
- "BY",
- "BZ",
- "CA",
- "CC",
- "CD",
- "CF",
- "CG",
- "CH",
- "CI",
- "CK",
- "CL",
- "CM",
- "CN",
- "CO",
- "CP",
- "CQ",
- "CR",
- "CS",
- "CU",
- "CV",
- "CW",
- "CX",
- "CY",
- "CZ",
- "DD",
- "DE",
- "DG",
- "DJ",
- "DK",
- "DM",
- "DO",
- "DZ",
- "EA",
- "EC",
- "EE",
- "EG",
- "EH",
- "ER",
- "ES",
- "ET",
- "EU",
- "EZ",
- "FI",
- "FJ",
- "FK",
- "FM",
- "FO",
- "FR",
- "FX",
- "GA",
- "GB",
- "GD",
- "GE",
- "GF",
- "GG",
- "GH",
- "GI",
- "GL",
- "GM",
- "GN",
- "GP",
- "GQ",
- "GR",
- "GS",
- "GT",
- "GU",
- "GW",
- "GY",
- "HK",
- "HM",
- "HN",
- "HR",
- "HT",
- "HU",
- "IC",
- "ID",
- "IE",
- "IL",
- "IM",
- "IN",
- "IO",
- "IQ",
- "IR",
- "IS",
- "IT",
- "JE",
- "JM",
- "JO",
- "JP",
- "KE",
- "KG",
- "KH",
- "KI",
- "KM",
- "KN",
- "KP",
- "KR",
- "KW",
- "KY",
- "KZ",
- "LA",
- "LB",
- "LC",
- "LI",
- "LK",
- "LR",
- "LS",
- "LT",
- "LU",
- "LV",
- "LY",
- "MA",
- "MC",
- "MD",
- "ME",
- "MF",
- "MG",
- "MH",
- "MK",
- "ML",
- "MM",
- "MN",
- "MO",
- "MP",
- "MQ",
- "MR",
- "MS",
- "MT",
- "MU",
- "MV",
- "MW",
- "MX",
- "MY",
- "MZ",
- "NA",
- "NC",
- "NE",
- "NF",
- "NG",
- "NI",
- "NL",
- "NO",
- "NP",
- "NR",
- "NT",
- "NU",
- "NZ",
- "OM",
- "PA",
- "PE",
- "PF",
- "PG",
- "PH",
- "PK",
- "PL",
- "PM",
- "PN",
- "PR",
- "PS",
- "PT",
- "PW",
- "PY",
- "QA",
- "QM..QZ",
- "RE",
- "RO",
- "RS",
- "RU",
- "RW",
- "SA",
- "SB",
- "SC",
- "SD",
- "SE",
- "SG",
- "SH",
- "SI",
- "SJ",
- "SK",
- "SL",
- "SM",
- "SN",
- "SO",
- "SR",
- "SS",
- "ST",
- "SU",
- "SV",
- "SX",
- "SY",
- "SZ",
- "TA",
- "TC",
- "TD",
- "TF",
- "TG",
- "TH",
- "TJ",
- "TK",
- "TL",
- "TM",
- "TN",
- "TO",
- "TP",
- "TR",
- "TT",
- "TV",
- "TW",
- "TZ",
- "UA",
- "UG",
- "UM",
- "UN",
- "US",
- "UY",
- "UZ",
- "VA",
- "VC",
- "VE",
- "VG",
- "VI",
- "VN",
- "VU",
- "WF",
- "WS",
- "XA..XZ",
- "YD",
- "YE",
- "YT",
- "YU",
- "ZA",
- "ZM",
- "ZR",
- "ZW",
- "ZZ"
- ],
- "variants": [
- "1606nict",
- "1694acad",
- "1901",
- "1959acad",
- "1994",
- "1996",
- "abl1943",
- "akuapem",
- "alalc97",
- "aluku",
- "anpezo",
- "ao1990",
- "aranes",
- "arevela",
- "arevmda",
- "arkaika",
- "asante",
- "auvern",
- "baku1926",
- "balanka",
- "barla",
- "basiceng",
- "bauddha",
- "bciav",
- "bcizbl",
- "biscayan",
- "biske",
- "blasl",
- "bohoric",
- "boont",
- "bornholm",
- "cisaup",
- "colb1945",
- "cornu",
- "creiss",
- "dajnko",
- "ekavsk",
- "emodeng",
- "fascia",
- "fodom",
- "fonipa",
- "fonkirsh",
- "fonnapa",
- "fonupa",
- "fonxsamp",
- "gallo",
- "gascon",
- "gherd",
- "grclass",
- "grital",
- "grmistr",
- "hanoi",
- "hepburn",
- "heploc",
- "hognorsk",
- "hsistemo",
- "huett",
- "ijekavsk",
- "itihasa",
- "ivanchov",
- "jauer",
- "jyutping",
- "kkcor",
- "kleinsch",
- "kociewie",
- "kscor",
- "laukika",
- "leidentr",
- "lemosin",
- "lengadoc",
- "lipaw",
- "ltg1929",
- "ltg2007",
- "luna1918",
- "mdcegyp",
- "mdctrans",
- "metelko",
- "monoton",
- "ndyuka",
- "nedis",
- "newfound",
- "nicard",
- "njiva",
- "nulik",
- "osojs",
- "oxendict",
- "pahawh2",
- "pahawh3",
- "pahawh4",
- "pamaka",
- "peano",
- "pehoeji",
- "petr1708",
- "pinyin",
- "polyton",
- "provenc",
- "puter",
- "rigik",
- "rozaj",
- "rumgr",
- "saigon",
- "scotland",
- "scouse",
- "simple",
- "solba",
- "sotav",
- "spanglis",
- "surmiran",
- "sursilv",
- "sutsilv",
- "synnejyl",
- "tailo",
- "tarask",
- "tongyong",
- "tunumiit",
- "uccor",
- "ucrcor",
- "ulster",
- "unifon",
- "vaidika",
- "valbadia",
- "valencia",
- "vallader",
- "vecdruka",
- "viennese",
- "vivaraup",
- "wadegile",
- "xsistemo"
- ],
- "grandfathered": [
- "art-lojban",
- "cel-gaulish",
- "en-gb-oed",
- "i-ami",
- "i-bnn",
- "i-default",
- "i-enochian",
- "i-hak",
- "i-klingon",
- "i-lux",
- "i-mingo",
- "i-navajo",
- "i-pwn",
- "i-tao",
- "i-tay",
- "i-tsu",
- "no-bok",
- "no-nyn",
- "sgn-be-fr",
- "sgn-be-nl",
- "sgn-ch-de",
- "zh-guoyu",
- "zh-hakka",
- "zh-min",
- "zh-min-nan",
- "zh-xiang"
- ]
-}
\ No newline at end of file
diff --git a/resources/iana_test.json b/resources/iana_test.json
deleted file mode 100644
index e733806..0000000
--- a/resources/iana_test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "languages": ["en", "fr", "de", "zh"],
- "scripts": ["Latn", "Cyrl", "Hans"],
- "regions": ["US", "FR", "DE", "CN"],
- "variants": ["1901", "1996"],
- "grandfathered": ["i-klingon", "i-navajo"]
-}
\ No newline at end of file
diff --git a/src/BCP47Tag.php b/src/BCP47Tag.php
index 74b85aa..098624d 100644
--- a/src/BCP47Tag.php
+++ b/src/BCP47Tag.php
@@ -4,105 +4,98 @@
namespace LHcze\BCP47;
-use InvalidArgumentException;
use JsonSerializable;
+use LHcze\BCP47\Exception\BCP47IanaRegistryException;
+use LHcze\BCP47\Exception\BCP47InvalidArgumentException;
+use LHcze\BCP47\Exception\BCP47InvalidFallbackLocaleException;
+use LHcze\BCP47\Exception\BCP47InvalidLocaleException;
+use LHcze\BCP47\Exception\BCP47InvalidMatchingTagException;
+use LHcze\BCP47\Exception\BCP47ParserException;
use LHcze\BCP47\Normalizer\BCP47Normalizer;
use LHcze\BCP47\Parser\BCP47Parser;
use LHcze\BCP47\Registry\IanaSubtagRegistry;
+use LHcze\BCP47\ValueObject\LanguageTag;
use LHcze\BCP47\ValueObject\ParsedTag;
use Stringable;
final readonly class BCP47Tag implements Stringable, JsonSerializable
{
/** RFC 5646 representation of a lang-tag */
- private string $locale;
-
- /** Original input string */
- private string $originalInput;
+ private LanguageTag $locale;
/** IANA Language Subtag Registry */
private IanaSubtagRegistry $registry;
+ /** BCP47 Normalizer */
+ private BCP47Normalizer $normalizer;
+
+ /** BCP47 Parser */
+ private BCP47Parser $parser;
+
/**
- * @param string $locale Raw string locale input
+ * Create a new BCP47Tag instance with a LanguageTag value object
+ *
+ * It's intended to carry the BCP47Tag instance around as is, but you can also use LanguageTag directly if you
+ * want something more lightweight and verbally simple.
+ *
+ * NOTE: One specific behavior for fallback locale is, that when the inputLocale is valid, but not to be found
+ * in the matchTags, the fallback won't be used.
+ * This is because the purpose of fallback is to only replace inputLocale if it's not valid.
+ *
+ * @param string $inputLocale Raw string locale input
* @param string|null $fallbackLocale If everything fails, use this locale instead
- * @param string[]|null $knownTags A list of known canonical BCP 47 language tags
- * @param bool $requireCanonical If true and the locale is language-only (e.g., 'en'),
- * it will attempt to match with the first known tag with that language
- * and throw an exception if no match is found
- * @throws InvalidArgumentException When the locale is invalid and no fallback is provided
+ * @param string[]|null $useCanonicalMatchTags Locale must match or resolve to one of the canonical tags in the list
+ *
+ * @throws BCP47InvalidLocaleException When the locale is invalid and no fallback is provided
+ * @throws BCP47InvalidFallbackLocaleException When the locale is invalid and so is the provided fallback
+ * @throws BCP47InvalidMatchingTagException When one of the provided known tags is invalid
+ * @throws BCP47IanaRegistryException When the IANA registry cannot be loaded
+ * @throws BCP47InvalidArgumentException
*/
public function __construct(
- string $locale,
+ private string $inputLocale,
?string $fallbackLocale = null,
- ?array $knownTags = null,
- bool $requireCanonical = false,
+ ?array $useCanonicalMatchTags = null,
) {
- // Initialize helper classes
- $normalizer = new BCP47Normalizer();
- $parser = new BCP47Parser($normalizer);
-
- // Load the IANA registry
- $this->registry = IanaSubtagRegistry::load($parser);
+ // Initialize hard-working class objects
+ $this->normalizer = new BCP47Normalizer();
+ $this->parser = new BCP47Parser($this->normalizer);
- // Store the original input string
- $this->originalInput = $locale;
+ $this->validateOptionalArguments($fallbackLocale, $useCanonicalMatchTags);
- // Step 1: Normalize the locale string
- $normalized = $normalizer->normalize($locale);
-
- // Step 2: Process with known tags if available
- if ($knownTags !== null) {
- $normalizedKnownTags = $parser->parseKnownTags($knownTags);
+ // Load the IANA registry
+ $this->registry = IanaSubtagRegistry::load();
- // Try an exact or case-insensitive match first
- $matchResult = $parser->findMatchInKnownTags($normalized, $normalizedKnownTags);
- if ($matchResult !== null) {
- $this->locale = $matchResult;
- return;
- }
+ $languageTag = $this->handleValidationNormalizationAndFallback($this->inputLocale, $fallbackLocale);
- // Handle language-only case
- if (!str_contains($normalized, '-')) {
- if ($requireCanonical) {
- // When requireCanonical is true, try to find a match or throw exception
- $languageMatch = $parser->findLanguageOnlyMatch($normalized, $normalizedKnownTags);
- if ($languageMatch !== null) {
- $this->locale = $languageMatch;
- return;
- }
-
- throw new InvalidArgumentException(
- sprintf('No region found for language "%s" in known tags.', $normalized),
- );
- }
- // When requireCanonical is false, keep the language-only locale as is
- }
+ // Function is enabled if it's not null
+ if ($useCanonicalMatchTags !== null) {
+ $languageTag = $this->matchCanonicalTag($languageTag, $useCanonicalMatchTags);
}
- // Step 3: Handle validation and fallback
- $this->locale = $this->handleValidationAndFallback($normalized, $locale, $fallbackLocale, $normalizer);
+ // Final version of the locale value object
+ $this->locale = $languageTag;
}
- public function getOriginalInput(): string
+ public function getInputLocale(): string
{
- return $this->originalInput;
+ return $this->inputLocale;
}
/**
- * Get the normalized locale (default storage format: `xx-XX`).
+ * Get the normalized locale
*/
public function getNormalized(): string
{
- return $this->locale;
+ return (string) $this->locale;
}
/**
* Get the underscore-separated format (`xx_XX`).
*/
- public function getUnderscored(): string
+ public function getICUformat(): string
{
- return str_replace('-', '_', $this->locale);
+ return str_replace('-', '_', (string) $this->locale);
}
/**
@@ -111,7 +104,7 @@ public function getUnderscored(): string
*/
public function getLC(): string
{
- return strtolower($this->locale);
+ return strtolower((string) $this->locale);
}
/**
@@ -120,7 +113,7 @@ public function getLC(): string
*/
public function getUC(): string
{
- return strtoupper($this->locale);
+ return strtoupper((string) $this->locale);
}
/**
@@ -144,11 +137,11 @@ public function getUCU(): string
/**
* Get the parsed tag as a value object
*
- * @return ParsedTag|null The parsed tag, or null if parsing fails
+ * @return LanguageTag Language tag value object
*/
- public function getParsedTag(): ?ParsedTag
+ public function getLanguageTag(): LanguageTag
{
- return $this->registry->parseLocale($this->locale);
+ return $this->locale;
}
public function jsonSerialize(): string
@@ -156,41 +149,168 @@ public function jsonSerialize(): string
return $this->getNormalized();
}
+ /**
+ * If matchTags and fallback are both provided, validate that fallback is one of the matchTags.
+ * Before the search, normalize both arguments.
+ *
+ * @param string[]|null $useCanonicalMatchTags
+ * @throws BCP47InvalidArgumentException
+ */
+ public function validateOptionalArguments(?string $fallbackLocale, ?array $useCanonicalMatchTags): void
+ {
+ if ($fallbackLocale === null || $useCanonicalMatchTags === null) {
+ return;
+ }
+
+ $fallbackLocale = $this->normalizer->normalize($fallbackLocale);
+ $useCanonicalMatchTags = $this->parser->parseMatchTags($useCanonicalMatchTags);
+
+ if (!in_array($fallbackLocale, $useCanonicalMatchTags, true)) {
+ throw new BCP47InvalidArgumentException(sprintf(
+ 'If you want to use matchTags and fallback locale, the fallback must be one of the matchTags.
+ Fallback: "%s", matchTags: "%s"',
+ $fallbackLocale,
+ implode(', ', $useCanonicalMatchTags),
+ ));
+ }
+ }
+
/**
* Handle validation of the locale and fallback if needed
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
*/
- private function handleValidationAndFallback(
- string $normalized,
- string $originalLocale,
+ private function handleValidationNormalizationAndFallback(
+ string $inputLocale,
?string $fallbackLocale,
- BCP47Normalizer $normalizer,
- ): string {
- // Validate the locale
- if (!$this->isValidLocale($normalized)) {
- // If invalid and we have a fallback, use it
- if ($fallbackLocale !== null) {
- $fallbackNormalized = $normalizer->normalize($fallbackLocale);
- if ($this->isValidLocale($fallbackNormalized)) {
- return $fallbackNormalized;
- }
- throw new InvalidArgumentException(
- sprintf('Both locale "%s" and fallback locale "%s" are invalid.', $originalLocale, $fallbackLocale),
+ ): LanguageTag {
+ $parsedTag = $this->getValidParsedTag($inputLocale);
+
+ if ($parsedTag === null) {
+ if ($fallbackLocale === null) {
+ throw new BCP47InvalidLocaleException(
+ sprintf('Invalid locale format: "%s". No fallback to go to.', $inputLocale),
);
}
+ $parsedTag = $this->getValidParsedTag($fallbackLocale);
- throw new InvalidArgumentException(sprintf('Invalid locale format: "%s".', $originalLocale));
+ if ($parsedTag === null) {
+ throw new BCP47InvalidFallbackLocaleException(
+ sprintf(
+ 'Both locale "%s" and fallback locale "%s" are invalid.',
+ $inputLocale,
+ $fallbackLocale,
+ ),
+ );
+ }
}
- // Use the normalized locale if it's valid and no match was found in supported locales
- return $normalized;
+ return LanguageTag::fromValidatedParsedTag($parsedTag);
+ }
+
+ private function getValidParsedTag(string $languageTag): ?ParsedTag
+ {
+ try {
+ $parsedTag = $this->parser->parseTag($languageTag);
+ if ($this->registry->isValidParsedTag($parsedTag)) {
+ return $parsedTag;
+ }
+ } catch (BCP47ParserException) {
+ // Intentionally left empty
+ }
+ return null;
}
/**
- * Validate the locale using the IANA Language Subtag Registry
+ * @throws BCP47ParserException
+ * @throws BCP47IanaRegistryException
*/
- private function isValidLocale(string $locale): bool
+ private function getParsedTag(string $languageTag): ParsedTag
{
- return $this->registry->isValidLocale($locale);
+ $parsedTag = $this->parser->parseTag($languageTag);
+ $this->registry->validateParsedTag($parsedTag);
+
+ return $parsedTag;
+ }
+
+ /**
+ * Normalize, validate and evaluate best matching language tag
+ *
+ * @param LanguageTag $languageTag Language tag to match
+ * @param string[] $canonicalMatchTags List of canonical tags to match against
+ *
+ * @return LanguageTag The best matching language tag
+ * @throws BCP47InvalidMatchingTagException
+ */
+ private function matchCanonicalTag(LanguageTag $languageTag, array $canonicalMatchTags): LanguageTag
+ {
+ $bestMatch = null;
+ $bestScore = -1;
+
+ foreach ($canonicalMatchTags as $matchingTag) {
+ $candidateTag = $this->parseMatchingTag($matchingTag);
+
+ // Basic language must-match β skip otherwise
+ if ($languageTag->getLanguage() !== $candidateTag->getLanguage()) {
+ continue;
+ }
+
+ $score = $this->calculateScore($languageTag, $candidateTag);
+
+ if ($score > $bestScore) {
+ $bestScore = $score;
+ $bestMatch = $candidateTag;
+ }
+ }
+
+ if ($bestMatch === null) {
+ throw new BCP47InvalidMatchingTagException(sprintf(
+ 'No matching language tag (%s) found in known tags. Provided: %s',
+ $languageTag,
+ implode(', ', $canonicalMatchTags),
+ ));
+ }
+
+ return LanguageTag::fromValidatedParsedTag($bestMatch);
+ }
+
+ private function calculateScore(LanguageTag $a, ParsedTag $b): int
+ {
+ // A hundred points for a language match
+ $score = 100;
+
+ // +10 if a region matches
+ if ($a->getRegion() !== null && $b->getRegion() !== null && $a->getRegion() === $b->getRegion()) {
+ $score += 10;
+ }
+
+ // +1 if a script matches
+ if ($a->getScript() !== null && $b->getScript() !== null && $a->getScript() === $b->getScript()) {
+ $score += 1;
+ }
+
+ return $score;
+ }
+
+ /**
+ * @throws BCP47InvalidMatchingTagException
+ */
+ private function parseMatchingTag(string $matchingTag): ParsedTag
+ {
+ try {
+ return $this->getParsedTag($matchingTag);
+ } catch (BCP47IanaRegistryException $e) {
+ throw new BCP47InvalidMatchingTagException(
+ sprintf('Matching language tag "%s" is not a valid IANA tag.', $matchingTag),
+ previous: $e,
+ );
+ } catch (BCP47ParserException $e) {
+ throw new BCP47InvalidMatchingTagException(
+ sprintf('Matching language tag "%s" input is invalid.', $matchingTag),
+ previous: $e,
+ );
+ }
}
/**
diff --git a/src/Enum/GrandfatheredTag.php b/src/Enum/GrandfatheredTag.php
new file mode 100644
index 0000000..5960f5d
--- /dev/null
+++ b/src/Enum/GrandfatheredTag.php
@@ -0,0 +1,40 @@
+value;
}
// Split into language and region parts
diff --git a/src/Parser/BCP47Parser.php b/src/Parser/BCP47Parser.php
index bcfe4d0..f1c020f 100644
--- a/src/Parser/BCP47Parser.php
+++ b/src/Parser/BCP47Parser.php
@@ -4,28 +4,35 @@
namespace LHcze\BCP47\Parser;
+use LHcze\BCP47\Enum\GrandfatheredTag;
+use LHcze\BCP47\Exception\BCP47ParserException;
use LHcze\BCP47\Normalizer\BCP47Normalizer;
use LHcze\BCP47\ValueObject\ParsedTag;
-
+use Throwable;
+
+/**
+ * TODO Does not support extensions, transformations and private use tags yet
+ * @see https://www.rfc-editor.org/rfc/bcp/bcp47.html#tag-syntax
+ * @see https://www.rfc-editor.org/rfc/rfc4647.html
+ * @see https://www.rfc-editor.org/rfc/rfc5646.html
+ * @see https://cldr.unicode.org/development/development-process/design-proposals/bcp47-syntax-mapping
+ */
final readonly class BCP47Parser
{
- private BCP47Normalizer $normalizer;
-
- public function __construct(BCP47Normalizer $normalizer)
+ public function __construct(private BCP47Normalizer $normalizer)
{
- $this->normalizer = $normalizer;
}
/**
* Normalize the known tags array
- * @param string[] $knownTags
+ * @param string[] $matchTags
* @return string[]
*/
- public function parseKnownTags(array $knownTags): array
+ public function parseMatchTags(array $matchTags): array
{
return array_map(
fn(string $loc) => $this->normalizer->normalize($loc),
- $knownTags,
+ $matchTags,
);
}
@@ -73,53 +80,111 @@ public function findLanguageOnlyMatch(string $language, array $normalizedKnownTa
*
* @param string $locale The locale string to parse (e.g., 'en-US', 'zh-Hans-CN')
* @return ParsedTag The parsed tag
+ * @throws BCP47ParserException
*/
public function parseTag(string $locale): ParsedTag
{
- // Normalize the locale first
- $normalized = $this->normalizer->normalize($locale);
+ try {
+ // Normalize the locale first
+ $normalized = $this->normalizer->normalize($locale);
+
+ if ($normalized === '') {
+ throw new BCP47ParserException('Empty locale.');
+ }
+
+ // Get parts from the normalized locale
+ $parts = $this->getParts($normalized);
+
+ // The first part is always the language
+ $language = strtolower($parts[0]);
+
+ // Process remaining parts to extract script, region, and variants
+ $remainingParts = array_slice($parts, 1);
+ [$script, $region, $variants] = $this->processRemainingParts($remainingParts);
+
+ // TODO: Handle extensions and private use in future versions
+
+ return new ParsedTag($language, $script, $region, $variants);
+ } catch (Throwable $e) {
+ throw new BCP47ParserException('Failed to parse locale.', 0, $e);
+ }
+ }
- // Split the locale into parts
- $parts = explode('-', $normalized);
+ /**
+ * Get parts from a normalized locale string, handling grandfathered tags
+ *
+ * @param string $normalized The normalized locale string
+ * @return string[] The parts of the locale
+ */
+ private function getParts(string $normalized): array
+ {
+ $grandfatheredTag = GrandfatheredTag::tryFrom($normalized);
+ if ($grandfatheredTag !== null) {
+ return [$grandfatheredTag->value];
+ }
- // The first part is always the language
- $language = strtolower($parts[0]);
+ return explode('-', $normalized);
+ }
- // Initialize optional parts
+ /**
+ * Process the remaining parts of a locale to extract a script, region, and variants
+ *
+ * @param string[] $remainingParts The remaining parts after the language
+ * @return array{0: ?string, 1: ?string, 2: string[]} Array containing [script, region, variants]
+ */
+ private function processRemainingParts(array $remainingParts): array
+ {
$script = null;
$region = null;
$variants = [];
- // Process remaining parts
- $remainingParts = array_slice($parts, 1);
$partCount = count($remainingParts);
- if ($partCount > 0) {
- $index = 0;
+ if ($partCount === 0) {
+ return [$script, $region, $variants];
+ }
- // Check for script (4 letters, first is uppercase, rest lowercase)
- if (strlen($remainingParts[$index]) === 4 && ctype_alpha($remainingParts[$index])) {
- $script = ucfirst(strtolower($remainingParts[$index]));
- $index++;
- }
+ $index = 0;
- // Check for a region (2 letters uppercase or 3 digits)
- if ($partCount > $index) {
- $part = $remainingParts[$index];
- if ((strlen($part) === 2 && ctype_alpha($part)) || (strlen($part) === 3 && ctype_digit($part))) {
- $region = strtoupper($part);
- $index++;
- }
- }
+ // Check for script (4 letters, first is uppercase, rest lowercase)
+ if ($this->isScript($remainingParts[$index])) {
+ $script = ucfirst(strtolower($remainingParts[$index]));
+ $index++;
+ }
- // The remaining parts are variants
- if ($partCount > $index) {
- $variants = array_slice($remainingParts, $index);
- }
+ // Check for a region (2 letters uppercase or 3 digits)
+ if ($partCount > $index && $this->isRegion($remainingParts[$index])) {
+ $region = strtoupper($remainingParts[$index]);
+ $index++;
}
- // TODO: Handle extensions and private use in future versions
+ // The remaining parts are variants
+ if ($partCount > $index) {
+ $variants = array_slice($remainingParts, $index);
+ }
- return new ParsedTag($language, $script, $region, $variants);
+ return [$script, $region, $variants];
+ }
+
+ /**
+ * Check if a part is a script subtag
+ *
+ * @param string $part The part to check
+ * @return bool True if the part is a script subtag
+ */
+ private function isScript(string $part): bool
+ {
+ return strlen($part) === 4 && ctype_alpha($part);
+ }
+
+ /**
+ * Check if a part is a region subtag
+ *
+ * @param string $part The part to check
+ * @return bool True if the part is a region subtag
+ */
+ private function isRegion(string $part): bool
+ {
+ return (strlen($part) === 2 && ctype_alpha($part)) || (strlen($part) === 3 && ctype_digit($part));
}
}
diff --git a/src/Registry/IanaSubtagRegistry.php b/src/Registry/IanaSubtagRegistry.php
index 7b9972f..1a2168c 100644
--- a/src/Registry/IanaSubtagRegistry.php
+++ b/src/Registry/IanaSubtagRegistry.php
@@ -4,54 +4,27 @@
namespace LHcze\BCP47\Registry;
-use LHcze\BCP47\Normalizer\BCP47Normalizer;
-use LHcze\BCP47\Parser\BCP47Parser;
+use LHcze\BCP47\Exception\BCP47IanaRegistryException;
use LHcze\BCP47\ValueObject\ParsedTag;
-use RuntimeException;
-use Throwable;
final class IanaSubtagRegistry
{
/**
- * Array of valid language subtags
- * @var string[]
- */
- private readonly array $languages;
-
- /**
- * Array of valid script subtags
- * @var string[]
- */
- private readonly array $scripts;
-
- /**
- * Array of valid region subtags
- * @var string[]
- */
- private readonly array $regions;
-
- /**
- * Array of valid variant subtags
- * @var string[]
- */
- private readonly array $variants;
-
- /**
- * Array of grandfathered tags
- * @var string[]
- */
- private readonly array $grandfathered;
-
- /**
- * Parser for BCP47 tags
- */
- private readonly BCP47Parser $parser;
-
- /**
- * Static cache for the registry data
- * @var array>|null
+ *
+ * Static cache for the registry data.
+ * Default yet empty structure ensures the safety.
+ *
+ * NOTE: keep the order of the keys in the array the same as arguments in the __construct() method!
+ *
+ * @var array
*/
- private static ?array $cache = null;
+ private static array $cache = [
+ 'languages' => [],
+ 'scripts' => [],
+ 'regions' => [],
+ 'variants' => [],
+ 'grandfathered' => [],
+ ];
/**
* Static instance of the registry
@@ -59,81 +32,69 @@ final class IanaSubtagRegistry
private static ?self $instance = null;
/**
+ * IANA Language Subtag Registry [RFC5646]
+ * Registry file: https://www.iana.org/assignments/language-subtag-registry
+ *
+ * TODO
+ * Validates that each of the components exists in the IANA LSR registry, however, some variants predicate that
+ * the region or language subtag (prefix) is mandatory.
+ * Same goes for the language suppress-script subtag, preferred, collection,...
+ * This is not in the current scope of this library, but its planned to be added in the future.
+ * @see https://www.reecedunn.co.uk/schema/2013/iana
+ *
+ * In the future, this registry should support additional IANA properties:
+ * - 'extlang' An ISO 639-3 language code that belongs to a macrolanguage.
+ * - 'comments' Notes about the subtag.
+ * - 'deprecated' The date at which the subtag was deprecated.
+ * - 'description'
+ * - 'macrolanguage' The associated parent language.
+ * - 'preferred-Value' The value that should be used instead of this subtag.
+ * - 'prefix' The subtag occurring before this subtag.
+ * - 'supress-script' The default script for the subtag.
+ *
* Private constructor to enforce using the static factory method
*
- * @param array $languages Array of language subtags
- * @param array $scripts Array of script subtags
- * @param array $regions Array of region subtags
- * @param array $variants Array of variant subtags
- * @param array $grandfathered Array of grandfathered tags
- * @param BCP47Parser $parser Parser for BCP47 tags
+ * @param string[] $languages Array of language subtags
+ * @param string[] $scripts Array of script subtags
+ * @param string[] $regions Array of region subtags
+ * @param string[] $variants Array of variant subtags
+ * @param string[] $grandfathered Array of grandfathered tags
*/
private function __construct(
- array $languages,
- array $scripts,
- array $regions,
- array $variants,
- array $grandfathered,
- BCP47Parser $parser,
+ private readonly array $languages,
+ private readonly array $scripts,
+ private readonly array $regions,
+ private readonly array $variants,
+ private readonly array $grandfathered,
) {
- $this->languages = $languages;
- $this->scripts = $scripts;
- $this->regions = $regions;
- $this->variants = $variants;
- $this->grandfathered = $grandfathered;
- $this->parser = $parser;
}
/**
- * Load the registry data
+ * Load the registry data and populates the cache.
+ *
+ * @return IanaSubtagRegistry The registry instance with the loaded data.
*
- * @param BCP47Parser|null $parser Optional parser instance (will create one if not provided)
- * @return self The registry instance
+ * @throws BCP47IanaRegistryException
*/
- public static function load(?BCP47Parser $parser = null): self
+ public static function load(): self
{
if (self::$instance !== null) {
return self::$instance;
}
- if (self::$cache === null) {
- $registryFile = __DIR__ . '/../Resources/IanaSubtagRegistry.php';
- if (!file_exists($registryFile)) {
- throw new RuntimeException("Registry file not found: $registryFile");
- }
-
- self::$cache = require $registryFile;
+ $registryFile = __DIR__ . '/../Resources/IanaSubtagRegistryResource.php';
+ if (!file_exists($registryFile)) {
+ throw new BCP47IanaRegistryException("Registry file not found: $registryFile");
}
- // Create a parser if one wasn't provided
- if ($parser === null) {
- $normalizer = new BCP47Normalizer();
- $parser = new BCP47Parser($normalizer);
+ $registryData = require $registryFile;
+ if (!is_array($registryData)) {
+ throw new BCP47IanaRegistryException("Registry resource file must return an array: $registryFile");
}
- self::$instance = new self(
- self::$cache['languages'] ?? [],
- self::$cache['scripts'] ?? [],
- self::$cache['regions'] ?? [],
- self::$cache['variants'] ?? [],
- self::$cache['grandfathered'] ?? [],
- $parser,
- );
+ self::cacheRegistryData($registryData);
- return self::$instance;
- }
-
- /**
- * For backward compatibility - load from a JSON file
- *
- * @param string $path Path to the JSON file
- * @param BCP47Parser|null $parser Optional parser instance (will create one if not provided)
- * @throws RuntimeException If the file cannot be read or parsed
- * @deprecated Use load() instead
- */
- public static function loadFromFile(string $path, ?BCP47Parser $parser = null): self
- {
- return self::load($parser);
+ return self::$instance = new IanaSubtagRegistry(...self::$cache);
}
/**
@@ -144,7 +105,7 @@ public static function loadFromFile(string $path, ?BCP47Parser $parser = null):
*/
public function isValidLanguage(string $language): bool
{
- return in_array(strtolower($language), $this->languages, true);
+ return in_array($language, $this->languages, true);
}
/**
@@ -155,7 +116,7 @@ public function isValidLanguage(string $language): bool
*/
public function isValidScript(string $script): bool
{
- return in_array(ucfirst(strtolower($script)), $this->scripts, true);
+ return in_array($script, $this->scripts, true);
}
/**
@@ -166,7 +127,7 @@ public function isValidScript(string $script): bool
*/
public function isValidRegion(string $region): bool
{
- return in_array(strtoupper($region), $this->regions, true);
+ return in_array($region, $this->regions, true);
}
/**
@@ -177,7 +138,7 @@ public function isValidRegion(string $region): bool
*/
public function isValidVariant(string $variant): bool
{
- return in_array(strtolower($variant), $this->variants, true);
+ return in_array($variant, $this->variants, true);
}
/**
@@ -188,53 +149,42 @@ public function isValidVariant(string $variant): bool
*/
public function isGrandfathered(string $tag): bool
{
- return in_array(strtolower($tag), $this->grandfathered, true);
+ return in_array($tag, $this->grandfathered, true);
}
/**
- * Parse a locale string into a ParsedTag object
+ * Check if a locale is valid, according to IANA registry
*
- * @param string $locale The locale string to parse
- * @return ParsedTag|null The parsed tag, or null if parsing fails
- */
- public function parseLocale(string $locale): ?ParsedTag
- {
- return $this->parseTagInternal($locale);
- }
-
- /**
- * Check if a locale is valid according to IANA registry
- *
- * @param string $locale Locale to check
+ * @param ParsedTag $parsedTag Locale to check
+ * @param bool $requireRegion If true, the locale region subtag is mandatory. Otherwise optional
* @return bool True if the locale is valid
*/
- public function isValidLocale(string $locale): bool
- {
- // First check if it's a grandfathered tag
- if ($this->isGrandfathered($locale)) {
+ public function isValidParsedTag(
+ ParsedTag $parsedTag,
+ bool $requireRegion = false,
+ bool $requireScript = false,
+ ): bool {
+ // First, check if it's a grandfathered tag
+ if ($this->isGrandfathered((string) $parsedTag)) {
return true;
}
- // Parse the locale into its components
- $parsedTag = $this->parseTagInternal($locale);
-
- // If parsing failed, the locale is invalid
- if ($parsedTag === null) {
- return false;
- }
-
// Validate each component
if (!$this->isValidLanguage($parsedTag->getLanguage())) {
return false;
}
- $script = $parsedTag->getScript();
- if ($script !== null && !$this->isValidScript($script)) {
+ $region = $parsedTag->getRegion();
+ if (($requireRegion === true && ($region === null || !$this->isValidRegion($region))) ||
+ ($region !== null && !$this->isValidRegion($region))
+ ) {
return false;
}
- $region = $parsedTag->getRegion();
- if ($region !== null && !$this->isValidRegion($region)) {
+ $script = $parsedTag->getScript();
+ if (($requireScript === true && ($script === null || !$this->isValidscript($script))) ||
+ ($script !== null && !$this->isValidscript($script))
+ ) {
return false;
}
@@ -249,18 +199,47 @@ public function isValidLocale(string $locale): bool
}
/**
- * Internal method to parse a locale string into a ParsedTag object
- * This is used by both parseLocale() and isValidLocale() to avoid duplicate parsing
+ * @throws BCP47IanaRegistryException
+ */
+ public function validateParsedTag(ParsedTag $parsedTag): void
+ {
+ if (!$this->isValidParsedTag($parsedTag)) {
+ throw new BCP47IanaRegistryException('Invalid parsed tag');
+ }
+ }
+
+ /**
+ * Validate and put registry data into the static cache
+ *
+ * @param mixed[] $registryData The registry data to cache
*
- * @param string $locale The locale string to parse
- * @return ParsedTag|null The parsed tag, or null if parsing fails
+ * @SuppressWarnings("PHPMD.UnusedLocalVariable")
*/
- private function parseTagInternal(string $locale): ?ParsedTag
+ private static function cacheRegistryData(array $registryData): void
{
- try {
- return $this->parser->parseTag($locale);
- } catch (Throwable) {
- return null;
+ // Only allow known keys
+ /** @var array> $allowedKeys */
+ $allowedKeys = array_flip(array_keys(self::$cache));
+
+ foreach ($registryData as $rawKey => $items) {
+ $part = strtolower((string) $rawKey);
+
+ if (!isset($allowedKeys[$part]) || !is_array($items)) {
+ continue; // skip unwanted and invalid keys
+ }
+
+ // Duplicate values but before, convert them to strings
+ $deduplicated = array_flip(
+ array_map(
+ static fn($v) => (string) $v,
+ array_filter($items, static fn($v) => is_numeric($v) || is_string($v)),
+ ),
+ );
+
+ // Sort the values by their original index
+ foreach ($deduplicated as $value => $originalIndex) {
+ self::$cache[$part][] = (string) $value;
+ }
}
}
}
diff --git a/src/Resources/IanaSubtagRegistry.php b/src/Resources/IanaSubtagRegistryResource.php
similarity index 66%
rename from src/Resources/IanaSubtagRegistry.php
rename to src/Resources/IanaSubtagRegistryResource.php
index 8d7e94d..46fe4c0 100644
--- a/src/Resources/IanaSubtagRegistry.php
+++ b/src/Resources/IanaSubtagRegistryResource.php
@@ -3,7 +3,7 @@
declare(strict_types=1);
// This file is auto-generated by bin/fetch_iana_registry.php
-// Do not edit manually
+// Do not edit manually. Run composer iana:refresh to update the resource file.
return array (
'languages' =>
@@ -5723,2559 +5723,3078 @@
5712 => 'pze',
5713 => 'pzh',
5714 => 'pzn',
- 5715 => 'qaa..qtz',
- 5716 => 'qu',
- 5717 => 'qua',
- 5718 => 'qub',
- 5719 => 'quc',
- 5720 => 'qud',
- 5721 => 'quf',
- 5722 => 'qug',
- 5723 => 'quh',
- 5724 => 'qui',
- 5725 => 'quk',
- 5726 => 'qul',
- 5727 => 'qum',
- 5728 => 'qun',
- 5729 => 'qup',
- 5730 => 'quq',
- 5731 => 'qur',
- 5732 => 'qus',
- 5733 => 'quv',
- 5734 => 'quw',
- 5735 => 'qux',
- 5736 => 'quy',
- 5737 => 'quz',
- 5738 => 'qva',
- 5739 => 'qvc',
- 5740 => 'qve',
- 5741 => 'qvh',
- 5742 => 'qvi',
- 5743 => 'qvj',
- 5744 => 'qvl',
- 5745 => 'qvm',
- 5746 => 'qvn',
- 5747 => 'qvo',
- 5748 => 'qvp',
- 5749 => 'qvs',
- 5750 => 'qvw',
- 5751 => 'qvy',
- 5752 => 'qvz',
- 5753 => 'qwa',
- 5754 => 'qwc',
- 5755 => 'qwe',
- 5756 => 'qwh',
- 5757 => 'qwm',
- 5758 => 'qws',
- 5759 => 'qwt',
- 5760 => 'qxa',
- 5761 => 'qxc',
- 5762 => 'qxh',
- 5763 => 'qxl',
- 5764 => 'qxn',
- 5765 => 'qxo',
- 5766 => 'qxp',
- 5767 => 'qxq',
- 5768 => 'qxr',
- 5769 => 'qxs',
- 5770 => 'qxt',
- 5771 => 'qxu',
- 5772 => 'qxw',
- 5773 => 'qya',
- 5774 => 'qyp',
- 5775 => 'raa',
- 5776 => 'rab',
- 5777 => 'rac',
- 5778 => 'rad',
- 5779 => 'raf',
- 5780 => 'rag',
- 5781 => 'rah',
- 5782 => 'rai',
- 5783 => 'raj',
- 5784 => 'rak',
- 5785 => 'ral',
- 5786 => 'ram',
- 5787 => 'ran',
- 5788 => 'rao',
- 5789 => 'rap',
- 5790 => 'raq',
- 5791 => 'rar',
- 5792 => 'ras',
- 5793 => 'rat',
- 5794 => 'rau',
- 5795 => 'rav',
- 5796 => 'raw',
- 5797 => 'rax',
- 5798 => 'ray',
- 5799 => 'raz',
- 5800 => 'rbb',
- 5801 => 'rbk',
- 5802 => 'rbl',
- 5803 => 'rbp',
- 5804 => 'rcf',
- 5805 => 'rdb',
- 5806 => 'rea',
- 5807 => 'reb',
- 5808 => 'ree',
- 5809 => 'reg',
- 5810 => 'rei',
- 5811 => 'rej',
- 5812 => 'rel',
- 5813 => 'rem',
- 5814 => 'ren',
- 5815 => 'rer',
- 5816 => 'res',
- 5817 => 'ret',
- 5818 => 'rey',
- 5819 => 'rga',
- 5820 => 'rge',
- 5821 => 'rgk',
- 5822 => 'rgn',
- 5823 => 'rgr',
- 5824 => 'rgs',
- 5825 => 'rgu',
- 5826 => 'rhg',
- 5827 => 'rhp',
- 5828 => 'ria',
- 5829 => 'rib',
- 5830 => 'rie',
- 5831 => 'rif',
- 5832 => 'ril',
- 5833 => 'rim',
- 5834 => 'rin',
- 5835 => 'rir',
- 5836 => 'rit',
- 5837 => 'riu',
- 5838 => 'rjg',
- 5839 => 'rji',
- 5840 => 'rjs',
- 5841 => 'rka',
- 5842 => 'rkb',
- 5843 => 'rkh',
- 5844 => 'rki',
- 5845 => 'rkm',
- 5846 => 'rkt',
- 5847 => 'rkw',
- 5848 => 'rm',
- 5849 => 'rma',
- 5850 => 'rmb',
- 5851 => 'rmc',
- 5852 => 'rmd',
- 5853 => 'rme',
- 5854 => 'rmf',
- 5855 => 'rmg',
- 5856 => 'rmh',
- 5857 => 'rmi',
- 5858 => 'rmk',
- 5859 => 'rml',
- 5860 => 'rmm',
- 5861 => 'rmn',
- 5862 => 'rmo',
- 5863 => 'rmp',
- 5864 => 'rmq',
- 5865 => 'rmr',
- 5866 => 'rms',
- 5867 => 'rmt',
- 5868 => 'rmu',
- 5869 => 'rmv',
- 5870 => 'rmw',
- 5871 => 'rmx',
- 5872 => 'rmy',
- 5873 => 'rmz',
- 5874 => 'rn',
- 5875 => 'rna',
- 5876 => 'rnb',
- 5877 => 'rnd',
- 5878 => 'rng',
- 5879 => 'rnl',
- 5880 => 'rnn',
- 5881 => 'rnp',
- 5882 => 'rnr',
- 5883 => 'rnw',
- 5884 => 'ro',
- 5885 => 'roa',
- 5886 => 'rob',
- 5887 => 'roc',
- 5888 => 'rod',
- 5889 => 'roe',
- 5890 => 'rof',
- 5891 => 'rog',
- 5892 => 'rol',
- 5893 => 'rom',
- 5894 => 'roo',
- 5895 => 'rop',
- 5896 => 'ror',
- 5897 => 'rou',
- 5898 => 'row',
- 5899 => 'rpn',
- 5900 => 'rpt',
- 5901 => 'rri',
- 5902 => 'rrm',
- 5903 => 'rro',
- 5904 => 'rrt',
- 5905 => 'rsb',
- 5906 => 'rsi',
- 5907 => 'rsk',
- 5908 => 'rsl',
- 5909 => 'rsm',
- 5910 => 'rsn',
- 5911 => 'rsw',
- 5912 => 'rtc',
- 5913 => 'rth',
- 5914 => 'rtm',
- 5915 => 'rts',
- 5916 => 'rtw',
- 5917 => 'ru',
- 5918 => 'rub',
- 5919 => 'ruc',
- 5920 => 'rue',
- 5921 => 'ruf',
- 5922 => 'rug',
- 5923 => 'ruh',
- 5924 => 'rui',
- 5925 => 'ruk',
- 5926 => 'ruo',
- 5927 => 'rup',
- 5928 => 'ruq',
- 5929 => 'rut',
- 5930 => 'ruu',
- 5931 => 'ruy',
- 5932 => 'ruz',
- 5933 => 'rw',
- 5934 => 'rwa',
- 5935 => 'rwk',
- 5936 => 'rwl',
- 5937 => 'rwm',
- 5938 => 'rwo',
- 5939 => 'rwr',
- 5940 => 'rxd',
- 5941 => 'rxw',
- 5942 => 'ryn',
- 5943 => 'rys',
- 5944 => 'ryu',
- 5945 => 'rzh',
- 5946 => 'sa',
- 5947 => 'saa',
- 5948 => 'sab',
- 5949 => 'sac',
- 5950 => 'sad',
- 5951 => 'sae',
- 5952 => 'saf',
- 5953 => 'sah',
- 5954 => 'sai',
- 5955 => 'saj',
- 5956 => 'sak',
- 5957 => 'sal',
- 5958 => 'sam',
- 5959 => 'sao',
- 5960 => 'sap',
- 5961 => 'saq',
- 5962 => 'sar',
- 5963 => 'sas',
- 5964 => 'sat',
- 5965 => 'sau',
- 5966 => 'sav',
- 5967 => 'saw',
- 5968 => 'sax',
- 5969 => 'say',
- 5970 => 'saz',
- 5971 => 'sba',
- 5972 => 'sbb',
- 5973 => 'sbc',
- 5974 => 'sbd',
- 5975 => 'sbe',
- 5976 => 'sbf',
- 5977 => 'sbg',
- 5978 => 'sbh',
- 5979 => 'sbi',
- 5980 => 'sbj',
- 5981 => 'sbk',
- 5982 => 'sbl',
- 5983 => 'sbm',
- 5984 => 'sbn',
- 5985 => 'sbo',
- 5986 => 'sbp',
- 5987 => 'sbq',
- 5988 => 'sbr',
- 5989 => 'sbs',
- 5990 => 'sbt',
- 5991 => 'sbu',
- 5992 => 'sbv',
- 5993 => 'sbw',
- 5994 => 'sbx',
- 5995 => 'sby',
- 5996 => 'sbz',
- 5997 => 'sc',
- 5998 => 'sca',
- 5999 => 'scb',
- 6000 => 'sce',
- 6001 => 'scf',
- 6002 => 'scg',
- 6003 => 'sch',
- 6004 => 'sci',
- 6005 => 'sck',
- 6006 => 'scl',
- 6007 => 'scn',
- 6008 => 'sco',
- 6009 => 'scp',
- 6010 => 'scq',
- 6011 => 'scs',
- 6012 => 'sct',
- 6013 => 'scu',
- 6014 => 'scv',
- 6015 => 'scw',
- 6016 => 'scx',
- 6017 => 'sd',
- 6018 => 'sda',
- 6019 => 'sdb',
- 6020 => 'sdc',
- 6021 => 'sde',
- 6022 => 'sdf',
- 6023 => 'sdg',
- 6024 => 'sdh',
- 6025 => 'sdj',
- 6026 => 'sdk',
- 6027 => 'sdl',
- 6028 => 'sdm',
- 6029 => 'sdn',
- 6030 => 'sdo',
- 6031 => 'sdp',
- 6032 => 'sdq',
- 6033 => 'sdr',
- 6034 => 'sds',
- 6035 => 'sdt',
- 6036 => 'sdu',
- 6037 => 'sdv',
- 6038 => 'sdx',
- 6039 => 'sdz',
- 6040 => 'se',
- 6041 => 'sea',
- 6042 => 'seb',
- 6043 => 'sec',
- 6044 => 'sed',
- 6045 => 'see',
- 6046 => 'sef',
- 6047 => 'seg',
- 6048 => 'seh',
- 6049 => 'sei',
- 6050 => 'sej',
- 6051 => 'sek',
- 6052 => 'sel',
- 6053 => 'sem',
- 6054 => 'sen',
- 6055 => 'seo',
- 6056 => 'sep',
- 6057 => 'seq',
- 6058 => 'ser',
- 6059 => 'ses',
- 6060 => 'set',
- 6061 => 'seu',
- 6062 => 'sev',
- 6063 => 'sew',
- 6064 => 'sey',
- 6065 => 'sez',
- 6066 => 'sfb',
- 6067 => 'sfe',
- 6068 => 'sfm',
- 6069 => 'sfs',
- 6070 => 'sfw',
- 6071 => 'sg',
- 6072 => 'sga',
- 6073 => 'sgb',
- 6074 => 'sgc',
- 6075 => 'sgd',
- 6076 => 'sge',
- 6077 => 'sgg',
- 6078 => 'sgh',
- 6079 => 'sgi',
- 6080 => 'sgj',
- 6081 => 'sgk',
- 6082 => 'sgl',
- 6083 => 'sgm',
- 6084 => 'sgn',
- 6085 => 'sgo',
- 6086 => 'sgp',
- 6087 => 'sgr',
- 6088 => 'sgs',
- 6089 => 'sgt',
- 6090 => 'sgu',
- 6091 => 'sgw',
- 6092 => 'sgx',
- 6093 => 'sgy',
- 6094 => 'sgz',
- 6095 => 'sh',
- 6096 => 'sha',
- 6097 => 'shb',
- 6098 => 'shc',
- 6099 => 'shd',
- 6100 => 'she',
- 6101 => 'shg',
- 6102 => 'shh',
- 6103 => 'shi',
- 6104 => 'shj',
- 6105 => 'shk',
- 6106 => 'shl',
- 6107 => 'shm',
- 6108 => 'shn',
- 6109 => 'sho',
- 6110 => 'shp',
- 6111 => 'shq',
- 6112 => 'shr',
- 6113 => 'shs',
- 6114 => 'sht',
- 6115 => 'shu',
- 6116 => 'shv',
- 6117 => 'shw',
- 6118 => 'shx',
- 6119 => 'shy',
- 6120 => 'shz',
- 6121 => 'si',
- 6122 => 'sia',
- 6123 => 'sib',
- 6124 => 'sid',
- 6125 => 'sie',
- 6126 => 'sif',
- 6127 => 'sig',
- 6128 => 'sih',
- 6129 => 'sii',
- 6130 => 'sij',
- 6131 => 'sik',
- 6132 => 'sil',
- 6133 => 'sim',
- 6134 => 'sio',
- 6135 => 'sip',
- 6136 => 'siq',
- 6137 => 'sir',
- 6138 => 'sis',
- 6139 => 'sit',
- 6140 => 'siu',
- 6141 => 'siv',
- 6142 => 'siw',
- 6143 => 'six',
- 6144 => 'siy',
- 6145 => 'siz',
- 6146 => 'sja',
- 6147 => 'sjb',
- 6148 => 'sjc',
- 6149 => 'sjd',
- 6150 => 'sje',
- 6151 => 'sjg',
- 6152 => 'sjk',
- 6153 => 'sjl',
- 6154 => 'sjm',
- 6155 => 'sjn',
- 6156 => 'sjo',
- 6157 => 'sjp',
- 6158 => 'sjr',
- 6159 => 'sjs',
- 6160 => 'sjt',
- 6161 => 'sju',
- 6162 => 'sjw',
- 6163 => 'sk',
- 6164 => 'ska',
- 6165 => 'skb',
- 6166 => 'skc',
- 6167 => 'skd',
- 6168 => 'ske',
- 6169 => 'skf',
- 6170 => 'skg',
- 6171 => 'skh',
- 6172 => 'ski',
- 6173 => 'skj',
- 6174 => 'skk',
- 6175 => 'skm',
- 6176 => 'skn',
- 6177 => 'sko',
- 6178 => 'skp',
- 6179 => 'skq',
- 6180 => 'skr',
- 6181 => 'sks',
- 6182 => 'skt',
- 6183 => 'sku',
- 6184 => 'skv',
- 6185 => 'skw',
- 6186 => 'skx',
- 6187 => 'sky',
- 6188 => 'skz',
- 6189 => 'sl',
- 6190 => 'sla',
- 6191 => 'slc',
- 6192 => 'sld',
- 6193 => 'sle',
- 6194 => 'slf',
- 6195 => 'slg',
- 6196 => 'slh',
- 6197 => 'sli',
- 6198 => 'slj',
- 6199 => 'sll',
- 6200 => 'slm',
- 6201 => 'sln',
- 6202 => 'slp',
- 6203 => 'slq',
- 6204 => 'slr',
- 6205 => 'sls',
- 6206 => 'slt',
- 6207 => 'slu',
- 6208 => 'slw',
- 6209 => 'slx',
- 6210 => 'sly',
- 6211 => 'slz',
- 6212 => 'sm',
- 6213 => 'sma',
- 6214 => 'smb',
- 6215 => 'smc',
- 6216 => 'smd',
- 6217 => 'smf',
- 6218 => 'smg',
- 6219 => 'smh',
- 6220 => 'smi',
- 6221 => 'smj',
- 6222 => 'smk',
- 6223 => 'sml',
- 6224 => 'smm',
- 6225 => 'smn',
- 6226 => 'smp',
- 6227 => 'smq',
- 6228 => 'smr',
- 6229 => 'sms',
- 6230 => 'smt',
- 6231 => 'smu',
- 6232 => 'smv',
- 6233 => 'smw',
- 6234 => 'smx',
- 6235 => 'smy',
- 6236 => 'smz',
- 6237 => 'sn',
- 6238 => 'snb',
- 6239 => 'snc',
- 6240 => 'sne',
- 6241 => 'snf',
- 6242 => 'sng',
- 6243 => 'snh',
- 6244 => 'sni',
- 6245 => 'snj',
- 6246 => 'snk',
- 6247 => 'snl',
- 6248 => 'snm',
- 6249 => 'snn',
- 6250 => 'sno',
- 6251 => 'snp',
- 6252 => 'snq',
- 6253 => 'snr',
- 6254 => 'sns',
- 6255 => 'snu',
- 6256 => 'snv',
- 6257 => 'snw',
- 6258 => 'snx',
- 6259 => 'sny',
- 6260 => 'snz',
- 6261 => 'so',
- 6262 => 'soa',
- 6263 => 'sob',
- 6264 => 'soc',
- 6265 => 'sod',
- 6266 => 'soe',
- 6267 => 'sog',
- 6268 => 'soh',
- 6269 => 'soi',
- 6270 => 'soj',
- 6271 => 'sok',
- 6272 => 'sol',
- 6273 => 'son',
- 6274 => 'soo',
- 6275 => 'sop',
- 6276 => 'soq',
- 6277 => 'sor',
- 6278 => 'sos',
- 6279 => 'sou',
- 6280 => 'sov',
- 6281 => 'sow',
- 6282 => 'sox',
- 6283 => 'soy',
- 6284 => 'soz',
- 6285 => 'spb',
- 6286 => 'spc',
- 6287 => 'spd',
- 6288 => 'spe',
- 6289 => 'spg',
- 6290 => 'spi',
- 6291 => 'spk',
- 6292 => 'spl',
- 6293 => 'spm',
- 6294 => 'spn',
- 6295 => 'spo',
- 6296 => 'spp',
- 6297 => 'spq',
- 6298 => 'spr',
- 6299 => 'sps',
- 6300 => 'spt',
- 6301 => 'spu',
- 6302 => 'spv',
- 6303 => 'spx',
- 6304 => 'spy',
- 6305 => 'sq',
- 6306 => 'sqa',
- 6307 => 'sqh',
- 6308 => 'sqj',
- 6309 => 'sqk',
- 6310 => 'sqm',
- 6311 => 'sqn',
- 6312 => 'sqo',
- 6313 => 'sqq',
- 6314 => 'sqr',
- 6315 => 'sqs',
- 6316 => 'sqt',
- 6317 => 'squ',
- 6318 => 'sqx',
- 6319 => 'sr',
- 6320 => 'sra',
- 6321 => 'srb',
- 6322 => 'src',
- 6323 => 'sre',
- 6324 => 'srf',
- 6325 => 'srg',
- 6326 => 'srh',
- 6327 => 'sri',
- 6328 => 'srk',
- 6329 => 'srl',
- 6330 => 'srm',
- 6331 => 'srn',
- 6332 => 'sro',
- 6333 => 'srq',
- 6334 => 'srr',
- 6335 => 'srs',
- 6336 => 'srt',
- 6337 => 'sru',
- 6338 => 'srv',
- 6339 => 'srw',
- 6340 => 'srx',
- 6341 => 'sry',
- 6342 => 'srz',
- 6343 => 'ss',
- 6344 => 'ssa',
- 6345 => 'ssb',
- 6346 => 'ssc',
- 6347 => 'ssd',
- 6348 => 'sse',
- 6349 => 'ssf',
- 6350 => 'ssg',
- 6351 => 'ssh',
- 6352 => 'ssi',
- 6353 => 'ssj',
- 6354 => 'ssk',
- 6355 => 'ssl',
- 6356 => 'ssm',
- 6357 => 'ssn',
- 6358 => 'sso',
- 6359 => 'ssp',
- 6360 => 'ssq',
- 6361 => 'ssr',
- 6362 => 'sss',
- 6363 => 'sst',
- 6364 => 'ssu',
- 6365 => 'ssv',
- 6366 => 'ssx',
- 6367 => 'ssy',
- 6368 => 'ssz',
- 6369 => 'st',
- 6370 => 'sta',
- 6371 => 'stb',
- 6372 => 'std',
- 6373 => 'ste',
- 6374 => 'stf',
- 6375 => 'stg',
- 6376 => 'sth',
- 6377 => 'sti',
- 6378 => 'stj',
- 6379 => 'stk',
- 6380 => 'stl',
- 6381 => 'stm',
- 6382 => 'stn',
- 6383 => 'sto',
- 6384 => 'stp',
- 6385 => 'stq',
- 6386 => 'str',
- 6387 => 'sts',
- 6388 => 'stt',
- 6389 => 'stu',
- 6390 => 'stv',
- 6391 => 'stw',
- 6392 => 'sty',
- 6393 => 'su',
- 6394 => 'sua',
- 6395 => 'sub',
- 6396 => 'suc',
- 6397 => 'sue',
- 6398 => 'sug',
- 6399 => 'sui',
- 6400 => 'suj',
- 6401 => 'suk',
- 6402 => 'sul',
- 6403 => 'sum',
- 6404 => 'suo',
- 6405 => 'suq',
- 6406 => 'sur',
- 6407 => 'sus',
- 6408 => 'sut',
- 6409 => 'suv',
- 6410 => 'suw',
- 6411 => 'sux',
- 6412 => 'suy',
- 6413 => 'suz',
- 6414 => 'sv',
- 6415 => 'sva',
- 6416 => 'svb',
- 6417 => 'svc',
- 6418 => 'sve',
- 6419 => 'svk',
- 6420 => 'svm',
- 6421 => 'svr',
- 6422 => 'svs',
- 6423 => 'svx',
- 6424 => 'sw',
- 6425 => 'swb',
- 6426 => 'swc',
- 6427 => 'swf',
- 6428 => 'swg',
- 6429 => 'swh',
- 6430 => 'swi',
- 6431 => 'swj',
- 6432 => 'swk',
- 6433 => 'swl',
- 6434 => 'swm',
- 6435 => 'swn',
- 6436 => 'swo',
- 6437 => 'swp',
- 6438 => 'swq',
- 6439 => 'swr',
- 6440 => 'sws',
- 6441 => 'swt',
- 6442 => 'swu',
- 6443 => 'swv',
- 6444 => 'sww',
- 6445 => 'swx',
- 6446 => 'swy',
- 6447 => 'sxb',
- 6448 => 'sxc',
- 6449 => 'sxe',
- 6450 => 'sxg',
- 6451 => 'sxk',
- 6452 => 'sxl',
- 6453 => 'sxm',
- 6454 => 'sxn',
- 6455 => 'sxo',
- 6456 => 'sxr',
- 6457 => 'sxs',
- 6458 => 'sxu',
- 6459 => 'sxw',
- 6460 => 'sya',
- 6461 => 'syb',
- 6462 => 'syc',
- 6463 => 'syd',
- 6464 => 'syi',
- 6465 => 'syk',
- 6466 => 'syl',
- 6467 => 'sym',
- 6468 => 'syn',
- 6469 => 'syo',
- 6470 => 'syr',
- 6471 => 'sys',
- 6472 => 'syw',
- 6473 => 'syx',
- 6474 => 'syy',
- 6475 => 'sza',
- 6476 => 'szb',
- 6477 => 'szc',
- 6478 => 'szd',
- 6479 => 'sze',
- 6480 => 'szg',
- 6481 => 'szl',
- 6482 => 'szn',
- 6483 => 'szp',
- 6484 => 'szs',
- 6485 => 'szv',
- 6486 => 'szw',
- 6487 => 'szy',
- 6488 => 'ta',
- 6489 => 'taa',
- 6490 => 'tab',
- 6491 => 'tac',
- 6492 => 'tad',
- 6493 => 'tae',
- 6494 => 'taf',
- 6495 => 'tag',
- 6496 => 'tai',
- 6497 => 'taj',
- 6498 => 'tak',
- 6499 => 'tal',
- 6500 => 'tan',
- 6501 => 'tao',
- 6502 => 'tap',
- 6503 => 'taq',
- 6504 => 'tar',
- 6505 => 'tas',
- 6506 => 'tau',
- 6507 => 'tav',
- 6508 => 'taw',
- 6509 => 'tax',
- 6510 => 'tay',
- 6511 => 'taz',
- 6512 => 'tba',
- 6513 => 'tbb',
- 6514 => 'tbc',
- 6515 => 'tbd',
- 6516 => 'tbe',
- 6517 => 'tbf',
- 6518 => 'tbg',
- 6519 => 'tbh',
- 6520 => 'tbi',
- 6521 => 'tbj',
- 6522 => 'tbk',
- 6523 => 'tbl',
- 6524 => 'tbm',
- 6525 => 'tbn',
- 6526 => 'tbo',
- 6527 => 'tbp',
- 6528 => 'tbq',
- 6529 => 'tbr',
- 6530 => 'tbs',
- 6531 => 'tbt',
- 6532 => 'tbu',
- 6533 => 'tbv',
- 6534 => 'tbw',
- 6535 => 'tbx',
- 6536 => 'tby',
- 6537 => 'tbz',
- 6538 => 'tca',
- 6539 => 'tcb',
- 6540 => 'tcc',
- 6541 => 'tcd',
- 6542 => 'tce',
- 6543 => 'tcf',
- 6544 => 'tcg',
- 6545 => 'tch',
- 6546 => 'tci',
- 6547 => 'tck',
- 6548 => 'tcl',
- 6549 => 'tcm',
- 6550 => 'tcn',
- 6551 => 'tco',
- 6552 => 'tcp',
- 6553 => 'tcq',
- 6554 => 'tcs',
- 6555 => 'tct',
- 6556 => 'tcu',
- 6557 => 'tcw',
- 6558 => 'tcx',
- 6559 => 'tcy',
- 6560 => 'tcz',
- 6561 => 'tda',
- 6562 => 'tdb',
- 6563 => 'tdc',
- 6564 => 'tdd',
- 6565 => 'tde',
- 6566 => 'tdf',
- 6567 => 'tdg',
- 6568 => 'tdh',
- 6569 => 'tdi',
- 6570 => 'tdj',
- 6571 => 'tdk',
- 6572 => 'tdl',
- 6573 => 'tdm',
- 6574 => 'tdn',
- 6575 => 'tdo',
- 6576 => 'tdq',
- 6577 => 'tdr',
- 6578 => 'tds',
- 6579 => 'tdt',
- 6580 => 'tdu',
- 6581 => 'tdv',
- 6582 => 'tdx',
- 6583 => 'tdy',
- 6584 => 'te',
- 6585 => 'tea',
- 6586 => 'teb',
- 6587 => 'tec',
- 6588 => 'ted',
- 6589 => 'tee',
- 6590 => 'tef',
- 6591 => 'teg',
- 6592 => 'teh',
- 6593 => 'tei',
- 6594 => 'tek',
- 6595 => 'tem',
- 6596 => 'ten',
- 6597 => 'teo',
- 6598 => 'tep',
- 6599 => 'teq',
- 6600 => 'ter',
- 6601 => 'tes',
- 6602 => 'tet',
- 6603 => 'teu',
- 6604 => 'tev',
- 6605 => 'tew',
- 6606 => 'tex',
- 6607 => 'tey',
- 6608 => 'tez',
- 6609 => 'tfi',
- 6610 => 'tfn',
- 6611 => 'tfo',
- 6612 => 'tfr',
- 6613 => 'tft',
- 6614 => 'tg',
- 6615 => 'tga',
- 6616 => 'tgb',
- 6617 => 'tgc',
- 6618 => 'tgd',
- 6619 => 'tge',
- 6620 => 'tgf',
- 6621 => 'tgg',
- 6622 => 'tgh',
- 6623 => 'tgi',
- 6624 => 'tgj',
- 6625 => 'tgn',
- 6626 => 'tgo',
- 6627 => 'tgp',
- 6628 => 'tgq',
- 6629 => 'tgr',
- 6630 => 'tgs',
- 6631 => 'tgt',
- 6632 => 'tgu',
- 6633 => 'tgv',
- 6634 => 'tgw',
- 6635 => 'tgx',
- 6636 => 'tgy',
- 6637 => 'tgz',
- 6638 => 'th',
- 6639 => 'thc',
- 6640 => 'thd',
- 6641 => 'the',
- 6642 => 'thf',
- 6643 => 'thh',
- 6644 => 'thi',
- 6645 => 'thk',
- 6646 => 'thl',
- 6647 => 'thm',
- 6648 => 'thn',
- 6649 => 'thp',
- 6650 => 'thq',
- 6651 => 'thr',
- 6652 => 'ths',
- 6653 => 'tht',
- 6654 => 'thu',
- 6655 => 'thv',
- 6656 => 'thw',
- 6657 => 'thx',
- 6658 => 'thy',
- 6659 => 'thz',
- 6660 => 'ti',
- 6661 => 'tia',
- 6662 => 'tic',
- 6663 => 'tid',
- 6664 => 'tie',
- 6665 => 'tif',
- 6666 => 'tig',
- 6667 => 'tih',
- 6668 => 'tii',
- 6669 => 'tij',
- 6670 => 'tik',
- 6671 => 'til',
- 6672 => 'tim',
- 6673 => 'tin',
- 6674 => 'tio',
- 6675 => 'tip',
- 6676 => 'tiq',
- 6677 => 'tis',
- 6678 => 'tit',
- 6679 => 'tiu',
- 6680 => 'tiv',
- 6681 => 'tiw',
- 6682 => 'tix',
- 6683 => 'tiy',
- 6684 => 'tiz',
- 6685 => 'tja',
- 6686 => 'tjg',
- 6687 => 'tji',
- 6688 => 'tjj',
- 6689 => 'tjl',
- 6690 => 'tjm',
- 6691 => 'tjn',
- 6692 => 'tjo',
- 6693 => 'tjp',
- 6694 => 'tjs',
- 6695 => 'tju',
- 6696 => 'tjw',
- 6697 => 'tk',
- 6698 => 'tka',
- 6699 => 'tkb',
- 6700 => 'tkd',
- 6701 => 'tke',
- 6702 => 'tkf',
- 6703 => 'tkg',
- 6704 => 'tkk',
- 6705 => 'tkl',
- 6706 => 'tkm',
- 6707 => 'tkn',
- 6708 => 'tkp',
- 6709 => 'tkq',
- 6710 => 'tkr',
- 6711 => 'tks',
- 6712 => 'tkt',
- 6713 => 'tku',
- 6714 => 'tkv',
- 6715 => 'tkw',
- 6716 => 'tkx',
- 6717 => 'tkz',
- 6718 => 'tl',
- 6719 => 'tla',
- 6720 => 'tlb',
- 6721 => 'tlc',
- 6722 => 'tld',
- 6723 => 'tlf',
- 6724 => 'tlg',
- 6725 => 'tlh',
- 6726 => 'tli',
- 6727 => 'tlj',
- 6728 => 'tlk',
- 6729 => 'tll',
- 6730 => 'tlm',
- 6731 => 'tln',
- 6732 => 'tlo',
- 6733 => 'tlp',
- 6734 => 'tlq',
- 6735 => 'tlr',
- 6736 => 'tls',
- 6737 => 'tlt',
- 6738 => 'tlu',
- 6739 => 'tlv',
- 6740 => 'tlw',
- 6741 => 'tlx',
- 6742 => 'tly',
- 6743 => 'tma',
- 6744 => 'tmb',
- 6745 => 'tmc',
- 6746 => 'tmd',
- 6747 => 'tme',
- 6748 => 'tmf',
- 6749 => 'tmg',
- 6750 => 'tmh',
- 6751 => 'tmi',
- 6752 => 'tmj',
- 6753 => 'tmk',
- 6754 => 'tml',
- 6755 => 'tmm',
- 6756 => 'tmn',
- 6757 => 'tmo',
- 6758 => 'tmp',
- 6759 => 'tmq',
- 6760 => 'tmr',
- 6761 => 'tms',
- 6762 => 'tmt',
- 6763 => 'tmu',
- 6764 => 'tmv',
- 6765 => 'tmw',
- 6766 => 'tmy',
- 6767 => 'tmz',
- 6768 => 'tn',
- 6769 => 'tna',
- 6770 => 'tnb',
- 6771 => 'tnc',
- 6772 => 'tnd',
- 6773 => 'tne',
- 6774 => 'tnf',
- 6775 => 'tng',
- 6776 => 'tnh',
- 6777 => 'tni',
- 6778 => 'tnk',
- 6779 => 'tnl',
- 6780 => 'tnm',
- 6781 => 'tnn',
- 6782 => 'tno',
- 6783 => 'tnp',
- 6784 => 'tnq',
- 6785 => 'tnr',
- 6786 => 'tns',
- 6787 => 'tnt',
- 6788 => 'tnu',
- 6789 => 'tnv',
- 6790 => 'tnw',
- 6791 => 'tnx',
- 6792 => 'tny',
- 6793 => 'tnz',
- 6794 => 'to',
- 6795 => 'tob',
- 6796 => 'toc',
- 6797 => 'tod',
- 6798 => 'toe',
- 6799 => 'tof',
- 6800 => 'tog',
- 6801 => 'toh',
- 6802 => 'toi',
- 6803 => 'toj',
- 6804 => 'tok',
- 6805 => 'tol',
- 6806 => 'tom',
- 6807 => 'too',
- 6808 => 'top',
- 6809 => 'toq',
- 6810 => 'tor',
- 6811 => 'tos',
- 6812 => 'tou',
- 6813 => 'tov',
- 6814 => 'tow',
- 6815 => 'tox',
- 6816 => 'toy',
- 6817 => 'toz',
- 6818 => 'tpa',
- 6819 => 'tpc',
- 6820 => 'tpe',
- 6821 => 'tpf',
- 6822 => 'tpg',
- 6823 => 'tpi',
- 6824 => 'tpj',
- 6825 => 'tpk',
- 6826 => 'tpl',
- 6827 => 'tpm',
- 6828 => 'tpn',
- 6829 => 'tpo',
- 6830 => 'tpp',
- 6831 => 'tpq',
- 6832 => 'tpr',
- 6833 => 'tpt',
- 6834 => 'tpu',
- 6835 => 'tpv',
- 6836 => 'tpw',
- 6837 => 'tpx',
- 6838 => 'tpy',
- 6839 => 'tpz',
- 6840 => 'tqb',
- 6841 => 'tql',
- 6842 => 'tqm',
- 6843 => 'tqn',
- 6844 => 'tqo',
- 6845 => 'tqp',
- 6846 => 'tqq',
- 6847 => 'tqr',
- 6848 => 'tqt',
- 6849 => 'tqu',
- 6850 => 'tqw',
- 6851 => 'tr',
- 6852 => 'tra',
- 6853 => 'trb',
- 6854 => 'trc',
- 6855 => 'trd',
- 6856 => 'tre',
- 6857 => 'trf',
- 6858 => 'trg',
- 6859 => 'trh',
- 6860 => 'tri',
- 6861 => 'trj',
- 6862 => 'trk',
- 6863 => 'trl',
- 6864 => 'trm',
- 6865 => 'trn',
- 6866 => 'tro',
- 6867 => 'trp',
- 6868 => 'trq',
- 6869 => 'trr',
- 6870 => 'trs',
- 6871 => 'trt',
- 6872 => 'tru',
- 6873 => 'trv',
- 6874 => 'trw',
- 6875 => 'trx',
- 6876 => 'try',
- 6877 => 'trz',
- 6878 => 'ts',
- 6879 => 'tsa',
- 6880 => 'tsb',
- 6881 => 'tsc',
- 6882 => 'tsd',
- 6883 => 'tse',
- 6884 => 'tsf',
- 6885 => 'tsg',
- 6886 => 'tsh',
- 6887 => 'tsi',
- 6888 => 'tsj',
- 6889 => 'tsk',
- 6890 => 'tsl',
- 6891 => 'tsm',
- 6892 => 'tsp',
- 6893 => 'tsq',
- 6894 => 'tsr',
- 6895 => 'tss',
- 6896 => 'tst',
- 6897 => 'tsu',
- 6898 => 'tsv',
- 6899 => 'tsw',
- 6900 => 'tsx',
- 6901 => 'tsy',
- 6902 => 'tsz',
- 6903 => 'tt',
- 6904 => 'tta',
- 6905 => 'ttb',
- 6906 => 'ttc',
- 6907 => 'ttd',
- 6908 => 'tte',
- 6909 => 'ttf',
- 6910 => 'ttg',
- 6911 => 'tth',
- 6912 => 'tti',
- 6913 => 'ttj',
- 6914 => 'ttk',
- 6915 => 'ttl',
- 6916 => 'ttm',
- 6917 => 'ttn',
- 6918 => 'tto',
- 6919 => 'ttp',
- 6920 => 'ttq',
- 6921 => 'ttr',
- 6922 => 'tts',
- 6923 => 'ttt',
- 6924 => 'ttu',
- 6925 => 'ttv',
- 6926 => 'ttw',
- 6927 => 'tty',
- 6928 => 'ttz',
- 6929 => 'tua',
- 6930 => 'tub',
- 6931 => 'tuc',
- 6932 => 'tud',
- 6933 => 'tue',
- 6934 => 'tuf',
- 6935 => 'tug',
- 6936 => 'tuh',
- 6937 => 'tui',
- 6938 => 'tuj',
- 6939 => 'tul',
- 6940 => 'tum',
- 6941 => 'tun',
- 6942 => 'tuo',
- 6943 => 'tup',
- 6944 => 'tuq',
- 6945 => 'tus',
- 6946 => 'tut',
- 6947 => 'tuu',
- 6948 => 'tuv',
- 6949 => 'tuw',
- 6950 => 'tux',
- 6951 => 'tuy',
- 6952 => 'tuz',
- 6953 => 'tva',
- 6954 => 'tvd',
- 6955 => 'tve',
- 6956 => 'tvi',
- 6957 => 'tvk',
- 6958 => 'tvl',
- 6959 => 'tvm',
- 6960 => 'tvn',
- 6961 => 'tvo',
- 6962 => 'tvs',
- 6963 => 'tvt',
- 6964 => 'tvu',
- 6965 => 'tvw',
- 6966 => 'tvx',
- 6967 => 'tvy',
- 6968 => 'tw',
- 6969 => 'twa',
- 6970 => 'twb',
- 6971 => 'twc',
- 6972 => 'twd',
- 6973 => 'twe',
- 6974 => 'twf',
- 6975 => 'twg',
- 6976 => 'twh',
- 6977 => 'twl',
- 6978 => 'twm',
- 6979 => 'twn',
- 6980 => 'two',
- 6981 => 'twp',
- 6982 => 'twq',
- 6983 => 'twr',
- 6984 => 'twt',
- 6985 => 'twu',
- 6986 => 'tww',
- 6987 => 'twx',
- 6988 => 'twy',
- 6989 => 'txa',
- 6990 => 'txb',
- 6991 => 'txc',
- 6992 => 'txe',
- 6993 => 'txg',
- 6994 => 'txh',
- 6995 => 'txi',
- 6996 => 'txj',
- 6997 => 'txm',
- 6998 => 'txn',
- 6999 => 'txo',
- 7000 => 'txq',
- 7001 => 'txr',
- 7002 => 'txs',
- 7003 => 'txt',
- 7004 => 'txu',
- 7005 => 'txx',
- 7006 => 'txy',
- 7007 => 'ty',
- 7008 => 'tya',
- 7009 => 'tye',
- 7010 => 'tyh',
- 7011 => 'tyi',
- 7012 => 'tyj',
- 7013 => 'tyl',
- 7014 => 'tyn',
- 7015 => 'typ',
- 7016 => 'tyr',
- 7017 => 'tys',
- 7018 => 'tyt',
- 7019 => 'tyu',
- 7020 => 'tyv',
- 7021 => 'tyx',
- 7022 => 'tyy',
- 7023 => 'tyz',
- 7024 => 'tza',
- 7025 => 'tzh',
- 7026 => 'tzj',
- 7027 => 'tzl',
- 7028 => 'tzm',
- 7029 => 'tzn',
- 7030 => 'tzo',
- 7031 => 'tzx',
- 7032 => 'uam',
- 7033 => 'uan',
- 7034 => 'uar',
- 7035 => 'uba',
- 7036 => 'ubi',
- 7037 => 'ubl',
- 7038 => 'ubr',
- 7039 => 'ubu',
- 7040 => 'uby',
- 7041 => 'uda',
- 7042 => 'ude',
- 7043 => 'udg',
- 7044 => 'udi',
- 7045 => 'udj',
- 7046 => 'udl',
- 7047 => 'udm',
- 7048 => 'udu',
- 7049 => 'ues',
- 7050 => 'ufi',
- 7051 => 'ug',
- 7052 => 'uga',
- 7053 => 'ugb',
- 7054 => 'uge',
- 7055 => 'ugh',
- 7056 => 'ugn',
- 7057 => 'ugo',
- 7058 => 'ugy',
- 7059 => 'uha',
- 7060 => 'uhn',
- 7061 => 'uis',
- 7062 => 'uiv',
- 7063 => 'uji',
- 7064 => 'uk',
- 7065 => 'uka',
- 7066 => 'ukg',
- 7067 => 'ukh',
- 7068 => 'uki',
- 7069 => 'ukk',
- 7070 => 'ukl',
- 7071 => 'ukp',
- 7072 => 'ukq',
- 7073 => 'uks',
- 7074 => 'uku',
- 7075 => 'ukv',
- 7076 => 'ukw',
- 7077 => 'uky',
- 7078 => 'ula',
- 7079 => 'ulb',
- 7080 => 'ulc',
- 7081 => 'ule',
- 7082 => 'ulf',
- 7083 => 'uli',
- 7084 => 'ulk',
- 7085 => 'ull',
- 7086 => 'ulm',
- 7087 => 'uln',
- 7088 => 'ulu',
- 7089 => 'ulw',
- 7090 => 'uly',
- 7091 => 'uma',
- 7092 => 'umb',
- 7093 => 'umc',
- 7094 => 'umd',
- 7095 => 'umg',
- 7096 => 'umi',
- 7097 => 'umm',
- 7098 => 'umn',
- 7099 => 'umo',
- 7100 => 'ump',
- 7101 => 'umr',
- 7102 => 'ums',
- 7103 => 'umu',
- 7104 => 'una',
- 7105 => 'und',
- 7106 => 'une',
- 7107 => 'ung',
- 7108 => 'uni',
- 7109 => 'unk',
- 7110 => 'unm',
- 7111 => 'unn',
- 7112 => 'unp',
- 7113 => 'unr',
- 7114 => 'unu',
- 7115 => 'unx',
- 7116 => 'unz',
- 7117 => 'uok',
- 7118 => 'uon',
- 7119 => 'upi',
- 7120 => 'upv',
- 7121 => 'ur',
- 7122 => 'ura',
- 7123 => 'urb',
- 7124 => 'urc',
- 7125 => 'ure',
- 7126 => 'urf',
- 7127 => 'urg',
- 7128 => 'urh',
- 7129 => 'uri',
- 7130 => 'urj',
- 7131 => 'urk',
- 7132 => 'url',
- 7133 => 'urm',
- 7134 => 'urn',
- 7135 => 'uro',
- 7136 => 'urp',
- 7137 => 'urr',
- 7138 => 'urt',
- 7139 => 'uru',
- 7140 => 'urv',
- 7141 => 'urw',
- 7142 => 'urx',
- 7143 => 'ury',
- 7144 => 'urz',
- 7145 => 'usa',
- 7146 => 'ush',
- 7147 => 'usi',
- 7148 => 'usk',
- 7149 => 'usp',
- 7150 => 'uss',
- 7151 => 'usu',
- 7152 => 'uta',
- 7153 => 'ute',
- 7154 => 'uth',
- 7155 => 'utp',
- 7156 => 'utr',
- 7157 => 'utu',
- 7158 => 'uum',
- 7159 => 'uun',
- 7160 => 'uur',
- 7161 => 'uuu',
- 7162 => 'uve',
- 7163 => 'uvh',
- 7164 => 'uvl',
- 7165 => 'uwa',
- 7166 => 'uya',
- 7167 => 'uz',
- 7168 => 'uzn',
- 7169 => 'uzs',
- 7170 => 'vaa',
- 7171 => 'vae',
- 7172 => 'vaf',
- 7173 => 'vag',
- 7174 => 'vah',
- 7175 => 'vai',
- 7176 => 'vaj',
- 7177 => 'val',
- 7178 => 'vam',
- 7179 => 'van',
- 7180 => 'vao',
- 7181 => 'vap',
- 7182 => 'var',
- 7183 => 'vas',
- 7184 => 'vau',
- 7185 => 'vav',
- 7186 => 'vay',
- 7187 => 'vbb',
- 7188 => 'vbk',
- 7189 => 've',
- 7190 => 'vec',
- 7191 => 'ved',
- 7192 => 'vel',
- 7193 => 'vem',
- 7194 => 'veo',
- 7195 => 'vep',
- 7196 => 'ver',
- 7197 => 'vgr',
- 7198 => 'vgt',
- 7199 => 'vi',
- 7200 => 'vic',
- 7201 => 'vid',
- 7202 => 'vif',
- 7203 => 'vig',
- 7204 => 'vil',
- 7205 => 'vin',
- 7206 => 'vis',
- 7207 => 'vit',
- 7208 => 'viv',
- 7209 => 'vjk',
- 7210 => 'vka',
- 7211 => 'vki',
- 7212 => 'vkj',
- 7213 => 'vkk',
- 7214 => 'vkl',
- 7215 => 'vkm',
- 7216 => 'vkn',
- 7217 => 'vko',
- 7218 => 'vkp',
- 7219 => 'vkt',
- 7220 => 'vku',
- 7221 => 'vkz',
- 7222 => 'vlp',
- 7223 => 'vls',
- 7224 => 'vma',
- 7225 => 'vmb',
- 7226 => 'vmc',
- 7227 => 'vmd',
- 7228 => 'vme',
- 7229 => 'vmf',
- 7230 => 'vmg',
- 7231 => 'vmh',
- 7232 => 'vmi',
- 7233 => 'vmj',
- 7234 => 'vmk',
- 7235 => 'vml',
- 7236 => 'vmm',
- 7237 => 'vmp',
- 7238 => 'vmq',
- 7239 => 'vmr',
- 7240 => 'vms',
- 7241 => 'vmu',
- 7242 => 'vmv',
- 7243 => 'vmw',
- 7244 => 'vmx',
- 7245 => 'vmy',
- 7246 => 'vmz',
- 7247 => 'vnk',
- 7248 => 'vnm',
- 7249 => 'vnp',
- 7250 => 'vo',
- 7251 => 'vor',
- 7252 => 'vot',
- 7253 => 'vra',
- 7254 => 'vro',
- 7255 => 'vrs',
- 7256 => 'vrt',
- 7257 => 'vsi',
- 7258 => 'vsl',
- 7259 => 'vsn',
- 7260 => 'vsv',
- 7261 => 'vto',
- 7262 => 'vum',
- 7263 => 'vun',
- 7264 => 'vut',
- 7265 => 'vwa',
- 7266 => 'wa',
- 7267 => 'waa',
- 7268 => 'wab',
- 7269 => 'wac',
- 7270 => 'wad',
- 7271 => 'wae',
- 7272 => 'waf',
- 7273 => 'wag',
- 7274 => 'wah',
- 7275 => 'wai',
- 7276 => 'waj',
- 7277 => 'wak',
- 7278 => 'wal',
- 7279 => 'wam',
- 7280 => 'wan',
- 7281 => 'wao',
- 7282 => 'wap',
- 7283 => 'waq',
- 7284 => 'war',
- 7285 => 'was',
- 7286 => 'wat',
- 7287 => 'wau',
- 7288 => 'wav',
- 7289 => 'waw',
- 7290 => 'wax',
- 7291 => 'way',
- 7292 => 'waz',
- 7293 => 'wba',
- 7294 => 'wbb',
- 7295 => 'wbe',
- 7296 => 'wbf',
- 7297 => 'wbh',
- 7298 => 'wbi',
- 7299 => 'wbj',
- 7300 => 'wbk',
- 7301 => 'wbl',
- 7302 => 'wbm',
- 7303 => 'wbp',
- 7304 => 'wbq',
- 7305 => 'wbr',
- 7306 => 'wbs',
- 7307 => 'wbt',
- 7308 => 'wbv',
- 7309 => 'wbw',
- 7310 => 'wca',
- 7311 => 'wci',
- 7312 => 'wdd',
- 7313 => 'wdg',
- 7314 => 'wdj',
- 7315 => 'wdk',
- 7316 => 'wdt',
- 7317 => 'wdu',
- 7318 => 'wdy',
- 7319 => 'wea',
- 7320 => 'wec',
- 7321 => 'wed',
- 7322 => 'weg',
- 7323 => 'weh',
- 7324 => 'wei',
- 7325 => 'wem',
- 7326 => 'wen',
- 7327 => 'weo',
- 7328 => 'wep',
- 7329 => 'wer',
- 7330 => 'wes',
- 7331 => 'wet',
- 7332 => 'weu',
- 7333 => 'wew',
- 7334 => 'wfg',
- 7335 => 'wga',
- 7336 => 'wgb',
- 7337 => 'wgg',
- 7338 => 'wgi',
- 7339 => 'wgo',
- 7340 => 'wgu',
- 7341 => 'wgw',
- 7342 => 'wgy',
- 7343 => 'wha',
- 7344 => 'whg',
- 7345 => 'whk',
- 7346 => 'whu',
- 7347 => 'wib',
- 7348 => 'wic',
- 7349 => 'wie',
- 7350 => 'wif',
- 7351 => 'wig',
- 7352 => 'wih',
- 7353 => 'wii',
- 7354 => 'wij',
- 7355 => 'wik',
- 7356 => 'wil',
- 7357 => 'wim',
- 7358 => 'win',
- 7359 => 'wir',
- 7360 => 'wit',
- 7361 => 'wiu',
- 7362 => 'wiv',
- 7363 => 'wiw',
- 7364 => 'wiy',
- 7365 => 'wja',
- 7366 => 'wji',
- 7367 => 'wka',
- 7368 => 'wkb',
- 7369 => 'wkd',
- 7370 => 'wkl',
- 7371 => 'wkr',
- 7372 => 'wku',
- 7373 => 'wkw',
- 7374 => 'wky',
- 7375 => 'wla',
- 7376 => 'wlc',
- 7377 => 'wle',
- 7378 => 'wlg',
- 7379 => 'wlh',
- 7380 => 'wli',
- 7381 => 'wlk',
- 7382 => 'wll',
- 7383 => 'wlm',
- 7384 => 'wlo',
- 7385 => 'wlr',
- 7386 => 'wls',
- 7387 => 'wlu',
- 7388 => 'wlv',
- 7389 => 'wlw',
- 7390 => 'wlx',
- 7391 => 'wly',
- 7392 => 'wma',
- 7393 => 'wmb',
- 7394 => 'wmc',
- 7395 => 'wmd',
- 7396 => 'wme',
- 7397 => 'wmg',
- 7398 => 'wmh',
- 7399 => 'wmi',
- 7400 => 'wmm',
- 7401 => 'wmn',
- 7402 => 'wmo',
- 7403 => 'wms',
- 7404 => 'wmt',
- 7405 => 'wmw',
- 7406 => 'wmx',
- 7407 => 'wnb',
- 7408 => 'wnc',
- 7409 => 'wnd',
- 7410 => 'wne',
- 7411 => 'wng',
- 7412 => 'wni',
- 7413 => 'wnk',
- 7414 => 'wnm',
- 7415 => 'wnn',
- 7416 => 'wno',
- 7417 => 'wnp',
- 7418 => 'wnu',
- 7419 => 'wnw',
- 7420 => 'wny',
- 7421 => 'wo',
- 7422 => 'woa',
- 7423 => 'wob',
- 7424 => 'woc',
- 7425 => 'wod',
- 7426 => 'woe',
- 7427 => 'wof',
- 7428 => 'wog',
- 7429 => 'woi',
- 7430 => 'wok',
- 7431 => 'wom',
- 7432 => 'won',
- 7433 => 'woo',
- 7434 => 'wor',
- 7435 => 'wos',
- 7436 => 'wow',
- 7437 => 'woy',
- 7438 => 'wpc',
- 7439 => 'wra',
- 7440 => 'wrb',
- 7441 => 'wrd',
- 7442 => 'wrg',
- 7443 => 'wrh',
- 7444 => 'wri',
- 7445 => 'wrk',
- 7446 => 'wrl',
- 7447 => 'wrm',
- 7448 => 'wrn',
- 7449 => 'wro',
- 7450 => 'wrp',
- 7451 => 'wrr',
- 7452 => 'wrs',
- 7453 => 'wru',
- 7454 => 'wrv',
- 7455 => 'wrw',
- 7456 => 'wrx',
- 7457 => 'wry',
- 7458 => 'wrz',
- 7459 => 'wsa',
- 7460 => 'wsg',
- 7461 => 'wsi',
- 7462 => 'wsk',
- 7463 => 'wsr',
- 7464 => 'wss',
- 7465 => 'wsu',
- 7466 => 'wsv',
- 7467 => 'wtb',
- 7468 => 'wtf',
- 7469 => 'wth',
- 7470 => 'wti',
- 7471 => 'wtk',
- 7472 => 'wtm',
- 7473 => 'wtw',
- 7474 => 'wua',
- 7475 => 'wub',
- 7476 => 'wud',
- 7477 => 'wuh',
- 7478 => 'wul',
- 7479 => 'wum',
- 7480 => 'wun',
- 7481 => 'wur',
- 7482 => 'wut',
- 7483 => 'wuu',
- 7484 => 'wuv',
- 7485 => 'wux',
- 7486 => 'wuy',
- 7487 => 'wwa',
- 7488 => 'wwb',
- 7489 => 'wwo',
- 7490 => 'wwr',
- 7491 => 'www',
- 7492 => 'wxa',
- 7493 => 'wxw',
- 7494 => 'wya',
- 7495 => 'wyb',
- 7496 => 'wyi',
- 7497 => 'wym',
- 7498 => 'wyn',
- 7499 => 'wyr',
- 7500 => 'wyy',
- 7501 => 'xaa',
- 7502 => 'xab',
- 7503 => 'xac',
- 7504 => 'xad',
- 7505 => 'xae',
- 7506 => 'xag',
- 7507 => 'xai',
- 7508 => 'xaj',
- 7509 => 'xak',
- 7510 => 'xal',
- 7511 => 'xam',
- 7512 => 'xan',
- 7513 => 'xao',
- 7514 => 'xap',
- 7515 => 'xaq',
- 7516 => 'xar',
- 7517 => 'xas',
- 7518 => 'xat',
- 7519 => 'xau',
- 7520 => 'xav',
- 7521 => 'xaw',
- 7522 => 'xay',
- 7523 => 'xba',
- 7524 => 'xbb',
- 7525 => 'xbc',
- 7526 => 'xbd',
- 7527 => 'xbe',
- 7528 => 'xbg',
- 7529 => 'xbi',
- 7530 => 'xbj',
- 7531 => 'xbm',
- 7532 => 'xbn',
- 7533 => 'xbo',
- 7534 => 'xbp',
- 7535 => 'xbr',
- 7536 => 'xbw',
- 7537 => 'xbx',
- 7538 => 'xby',
- 7539 => 'xcb',
- 7540 => 'xcc',
- 7541 => 'xce',
- 7542 => 'xcg',
- 7543 => 'xch',
- 7544 => 'xcl',
- 7545 => 'xcm',
- 7546 => 'xcn',
- 7547 => 'xco',
- 7548 => 'xcr',
- 7549 => 'xct',
- 7550 => 'xcu',
- 7551 => 'xcv',
- 7552 => 'xcw',
- 7553 => 'xcy',
- 7554 => 'xda',
- 7555 => 'xdc',
- 7556 => 'xdk',
- 7557 => 'xdm',
- 7558 => 'xdo',
- 7559 => 'xdq',
- 7560 => 'xdy',
- 7561 => 'xeb',
- 7562 => 'xed',
- 7563 => 'xeg',
- 7564 => 'xel',
- 7565 => 'xem',
- 7566 => 'xep',
- 7567 => 'xer',
- 7568 => 'xes',
- 7569 => 'xet',
- 7570 => 'xeu',
- 7571 => 'xfa',
- 7572 => 'xga',
- 7573 => 'xgb',
- 7574 => 'xgd',
- 7575 => 'xgf',
- 7576 => 'xgg',
- 7577 => 'xgi',
- 7578 => 'xgl',
- 7579 => 'xgm',
- 7580 => 'xgn',
- 7581 => 'xgr',
- 7582 => 'xgu',
- 7583 => 'xgw',
- 7584 => 'xh',
- 7585 => 'xha',
- 7586 => 'xhc',
- 7587 => 'xhd',
- 7588 => 'xhe',
- 7589 => 'xhm',
- 7590 => 'xhr',
- 7591 => 'xht',
- 7592 => 'xhu',
- 7593 => 'xhv',
- 7594 => 'xia',
- 7595 => 'xib',
- 7596 => 'xii',
- 7597 => 'xil',
- 7598 => 'xin',
- 7599 => 'xip',
- 7600 => 'xir',
- 7601 => 'xis',
- 7602 => 'xiv',
- 7603 => 'xiy',
- 7604 => 'xjb',
- 7605 => 'xjt',
- 7606 => 'xka',
- 7607 => 'xkb',
- 7608 => 'xkc',
- 7609 => 'xkd',
- 7610 => 'xke',
- 7611 => 'xkf',
- 7612 => 'xkg',
- 7613 => 'xkh',
- 7614 => 'xki',
- 7615 => 'xkj',
- 7616 => 'xkk',
- 7617 => 'xkl',
- 7618 => 'xkn',
- 7619 => 'xko',
- 7620 => 'xkp',
- 7621 => 'xkq',
- 7622 => 'xkr',
- 7623 => 'xks',
- 7624 => 'xkt',
- 7625 => 'xku',
- 7626 => 'xkv',
- 7627 => 'xkw',
- 7628 => 'xkx',
- 7629 => 'xky',
- 7630 => 'xkz',
- 7631 => 'xla',
- 7632 => 'xlb',
- 7633 => 'xlc',
- 7634 => 'xld',
- 7635 => 'xle',
- 7636 => 'xlg',
- 7637 => 'xli',
- 7638 => 'xln',
- 7639 => 'xlo',
- 7640 => 'xlp',
- 7641 => 'xls',
- 7642 => 'xlu',
- 7643 => 'xly',
- 7644 => 'xma',
- 7645 => 'xmb',
- 7646 => 'xmc',
- 7647 => 'xmd',
- 7648 => 'xme',
- 7649 => 'xmf',
- 7650 => 'xmg',
- 7651 => 'xmh',
- 7652 => 'xmj',
- 7653 => 'xmk',
- 7654 => 'xml',
- 7655 => 'xmm',
- 7656 => 'xmn',
- 7657 => 'xmo',
- 7658 => 'xmp',
- 7659 => 'xmq',
- 7660 => 'xmr',
- 7661 => 'xms',
- 7662 => 'xmt',
- 7663 => 'xmu',
- 7664 => 'xmv',
- 7665 => 'xmw',
- 7666 => 'xmx',
- 7667 => 'xmy',
- 7668 => 'xmz',
- 7669 => 'xna',
- 7670 => 'xnb',
- 7671 => 'xnd',
- 7672 => 'xng',
- 7673 => 'xnh',
- 7674 => 'xni',
- 7675 => 'xnj',
- 7676 => 'xnk',
- 7677 => 'xnm',
- 7678 => 'xnn',
- 7679 => 'xno',
- 7680 => 'xnq',
- 7681 => 'xnr',
- 7682 => 'xns',
- 7683 => 'xnt',
- 7684 => 'xnu',
- 7685 => 'xny',
- 7686 => 'xnz',
- 7687 => 'xoc',
- 7688 => 'xod',
- 7689 => 'xog',
- 7690 => 'xoi',
- 7691 => 'xok',
- 7692 => 'xom',
- 7693 => 'xon',
- 7694 => 'xoo',
- 7695 => 'xop',
- 7696 => 'xor',
- 7697 => 'xow',
- 7698 => 'xpa',
- 7699 => 'xpb',
- 7700 => 'xpc',
- 7701 => 'xpd',
- 7702 => 'xpe',
- 7703 => 'xpf',
- 7704 => 'xpg',
- 7705 => 'xph',
- 7706 => 'xpi',
- 7707 => 'xpj',
- 7708 => 'xpk',
- 7709 => 'xpl',
- 7710 => 'xpm',
- 7711 => 'xpn',
- 7712 => 'xpo',
- 7713 => 'xpp',
- 7714 => 'xpq',
- 7715 => 'xpr',
- 7716 => 'xps',
- 7717 => 'xpt',
- 7718 => 'xpu',
- 7719 => 'xpv',
- 7720 => 'xpw',
- 7721 => 'xpx',
- 7722 => 'xpy',
- 7723 => 'xpz',
- 7724 => 'xqa',
- 7725 => 'xqt',
- 7726 => 'xra',
- 7727 => 'xrb',
- 7728 => 'xrd',
- 7729 => 'xre',
- 7730 => 'xrg',
- 7731 => 'xri',
- 7732 => 'xrm',
- 7733 => 'xrn',
- 7734 => 'xrq',
- 7735 => 'xrr',
- 7736 => 'xrt',
- 7737 => 'xru',
- 7738 => 'xrw',
- 7739 => 'xsa',
- 7740 => 'xsb',
- 7741 => 'xsc',
- 7742 => 'xsd',
- 7743 => 'xse',
- 7744 => 'xsh',
- 7745 => 'xsi',
- 7746 => 'xsj',
- 7747 => 'xsl',
- 7748 => 'xsm',
- 7749 => 'xsn',
- 7750 => 'xso',
- 7751 => 'xsp',
- 7752 => 'xsq',
- 7753 => 'xsr',
- 7754 => 'xss',
- 7755 => 'xsu',
- 7756 => 'xsv',
- 7757 => 'xsy',
- 7758 => 'xta',
- 7759 => 'xtb',
- 7760 => 'xtc',
- 7761 => 'xtd',
- 7762 => 'xte',
- 7763 => 'xtg',
- 7764 => 'xth',
- 7765 => 'xti',
- 7766 => 'xtj',
- 7767 => 'xtl',
- 7768 => 'xtm',
- 7769 => 'xtn',
- 7770 => 'xto',
- 7771 => 'xtp',
- 7772 => 'xtq',
- 7773 => 'xtr',
- 7774 => 'xts',
- 7775 => 'xtt',
- 7776 => 'xtu',
- 7777 => 'xtv',
- 7778 => 'xtw',
- 7779 => 'xty',
- 7780 => 'xtz',
- 7781 => 'xua',
- 7782 => 'xub',
- 7783 => 'xud',
- 7784 => 'xug',
- 7785 => 'xuj',
- 7786 => 'xul',
- 7787 => 'xum',
- 7788 => 'xun',
- 7789 => 'xuo',
- 7790 => 'xup',
- 7791 => 'xur',
- 7792 => 'xut',
- 7793 => 'xuu',
- 7794 => 'xve',
- 7795 => 'xvi',
- 7796 => 'xvn',
- 7797 => 'xvo',
- 7798 => 'xvs',
- 7799 => 'xwa',
- 7800 => 'xwc',
- 7801 => 'xwd',
- 7802 => 'xwe',
- 7803 => 'xwg',
- 7804 => 'xwj',
- 7805 => 'xwk',
- 7806 => 'xwl',
- 7807 => 'xwo',
- 7808 => 'xwr',
- 7809 => 'xwt',
- 7810 => 'xww',
- 7811 => 'xxb',
- 7812 => 'xxk',
- 7813 => 'xxm',
- 7814 => 'xxr',
- 7815 => 'xxt',
- 7816 => 'xya',
- 7817 => 'xyb',
- 7818 => 'xyj',
- 7819 => 'xyk',
- 7820 => 'xyl',
- 7821 => 'xyt',
- 7822 => 'xyy',
- 7823 => 'xzh',
- 7824 => 'xzm',
- 7825 => 'xzp',
- 7826 => 'yaa',
- 7827 => 'yab',
- 7828 => 'yac',
- 7829 => 'yad',
- 7830 => 'yae',
- 7831 => 'yaf',
- 7832 => 'yag',
- 7833 => 'yah',
- 7834 => 'yai',
- 7835 => 'yaj',
- 7836 => 'yak',
- 7837 => 'yal',
- 7838 => 'yam',
- 7839 => 'yan',
- 7840 => 'yao',
- 7841 => 'yap',
- 7842 => 'yaq',
- 7843 => 'yar',
- 7844 => 'yas',
- 7845 => 'yat',
- 7846 => 'yau',
- 7847 => 'yav',
- 7848 => 'yaw',
- 7849 => 'yax',
- 7850 => 'yay',
- 7851 => 'yaz',
- 7852 => 'yba',
- 7853 => 'ybb',
- 7854 => 'ybd',
- 7855 => 'ybe',
- 7856 => 'ybh',
- 7857 => 'ybi',
- 7858 => 'ybj',
- 7859 => 'ybk',
- 7860 => 'ybl',
- 7861 => 'ybm',
- 7862 => 'ybn',
- 7863 => 'ybo',
- 7864 => 'ybx',
- 7865 => 'yby',
- 7866 => 'ych',
- 7867 => 'ycl',
- 7868 => 'ycn',
- 7869 => 'ycp',
- 7870 => 'ycr',
- 7871 => 'yda',
- 7872 => 'ydd',
- 7873 => 'yde',
- 7874 => 'ydg',
- 7875 => 'ydk',
- 7876 => 'yds',
- 7877 => 'yea',
- 7878 => 'yec',
- 7879 => 'yee',
- 7880 => 'yei',
- 7881 => 'yej',
- 7882 => 'yel',
- 7883 => 'yen',
- 7884 => 'yer',
- 7885 => 'yes',
- 7886 => 'yet',
- 7887 => 'yeu',
- 7888 => 'yev',
- 7889 => 'yey',
- 7890 => 'yga',
- 7891 => 'ygi',
- 7892 => 'ygl',
- 7893 => 'ygm',
- 7894 => 'ygp',
- 7895 => 'ygr',
- 7896 => 'ygs',
- 7897 => 'ygu',
- 7898 => 'ygw',
- 7899 => 'yha',
- 7900 => 'yhd',
- 7901 => 'yhl',
- 7902 => 'yhs',
- 7903 => 'yi',
- 7904 => 'yia',
- 7905 => 'yif',
- 7906 => 'yig',
- 7907 => 'yih',
- 7908 => 'yii',
- 7909 => 'yij',
- 7910 => 'yik',
- 7911 => 'yil',
- 7912 => 'yim',
- 7913 => 'yin',
- 7914 => 'yip',
- 7915 => 'yiq',
- 7916 => 'yir',
- 7917 => 'yis',
- 7918 => 'yit',
- 7919 => 'yiu',
- 7920 => 'yiv',
- 7921 => 'yix',
- 7922 => 'yiy',
- 7923 => 'yiz',
- 7924 => 'yka',
- 7925 => 'ykg',
- 7926 => 'ykh',
- 7927 => 'yki',
- 7928 => 'ykk',
- 7929 => 'ykl',
- 7930 => 'ykm',
- 7931 => 'ykn',
- 7932 => 'yko',
- 7933 => 'ykr',
- 7934 => 'ykt',
- 7935 => 'yku',
- 7936 => 'yky',
- 7937 => 'yla',
- 7938 => 'ylb',
- 7939 => 'yle',
- 7940 => 'ylg',
- 7941 => 'yli',
- 7942 => 'yll',
- 7943 => 'ylm',
- 7944 => 'yln',
- 7945 => 'ylo',
- 7946 => 'ylr',
- 7947 => 'ylu',
- 7948 => 'yly',
- 7949 => 'yma',
- 7950 => 'ymb',
- 7951 => 'ymc',
- 7952 => 'ymd',
- 7953 => 'yme',
- 7954 => 'ymg',
- 7955 => 'ymh',
- 7956 => 'ymi',
- 7957 => 'ymk',
- 7958 => 'yml',
- 7959 => 'ymm',
- 7960 => 'ymn',
- 7961 => 'ymo',
- 7962 => 'ymp',
- 7963 => 'ymq',
- 7964 => 'ymr',
- 7965 => 'yms',
- 7966 => 'ymt',
- 7967 => 'ymx',
- 7968 => 'ymz',
- 7969 => 'yna',
- 7970 => 'ynb',
- 7971 => 'ynd',
- 7972 => 'yne',
- 7973 => 'yng',
- 7974 => 'ynh',
- 7975 => 'ynk',
- 7976 => 'ynl',
- 7977 => 'ynn',
- 7978 => 'yno',
- 7979 => 'ynq',
- 7980 => 'yns',
- 7981 => 'ynu',
- 7982 => 'yo',
- 7983 => 'yob',
- 7984 => 'yog',
- 7985 => 'yoi',
- 7986 => 'yok',
- 7987 => 'yol',
- 7988 => 'yom',
- 7989 => 'yon',
- 7990 => 'yos',
- 7991 => 'yot',
- 7992 => 'yox',
- 7993 => 'yoy',
- 7994 => 'ypa',
- 7995 => 'ypb',
- 7996 => 'ypg',
- 7997 => 'yph',
- 7998 => 'ypk',
- 7999 => 'ypm',
- 8000 => 'ypn',
- 8001 => 'ypo',
- 8002 => 'ypp',
- 8003 => 'ypz',
- 8004 => 'yra',
- 8005 => 'yrb',
- 8006 => 'yre',
- 8007 => 'yri',
- 8008 => 'yrk',
- 8009 => 'yrl',
- 8010 => 'yrm',
- 8011 => 'yrn',
- 8012 => 'yro',
- 8013 => 'yrs',
- 8014 => 'yrw',
- 8015 => 'yry',
- 8016 => 'ysc',
- 8017 => 'ysd',
- 8018 => 'ysg',
- 8019 => 'ysl',
- 8020 => 'ysm',
- 8021 => 'ysn',
- 8022 => 'yso',
- 8023 => 'ysp',
- 8024 => 'ysr',
- 8025 => 'yss',
- 8026 => 'ysy',
- 8027 => 'yta',
- 8028 => 'ytl',
- 8029 => 'ytp',
- 8030 => 'ytw',
- 8031 => 'yty',
- 8032 => 'yua',
- 8033 => 'yub',
- 8034 => 'yuc',
- 8035 => 'yud',
- 8036 => 'yue',
- 8037 => 'yuf',
- 8038 => 'yug',
- 8039 => 'yui',
- 8040 => 'yuj',
- 8041 => 'yuk',
- 8042 => 'yul',
- 8043 => 'yum',
- 8044 => 'yun',
- 8045 => 'yup',
- 8046 => 'yuq',
- 8047 => 'yur',
- 8048 => 'yut',
- 8049 => 'yuu',
- 8050 => 'yuw',
- 8051 => 'yux',
- 8052 => 'yuy',
- 8053 => 'yuz',
- 8054 => 'yva',
- 8055 => 'yvt',
- 8056 => 'ywa',
- 8057 => 'ywg',
- 8058 => 'ywl',
- 8059 => 'ywn',
- 8060 => 'ywq',
- 8061 => 'ywr',
- 8062 => 'ywt',
- 8063 => 'ywu',
- 8064 => 'yww',
- 8065 => 'yxa',
- 8066 => 'yxg',
- 8067 => 'yxl',
- 8068 => 'yxm',
- 8069 => 'yxu',
- 8070 => 'yxy',
- 8071 => 'yyr',
- 8072 => 'yyu',
- 8073 => 'yyz',
- 8074 => 'yzg',
- 8075 => 'yzk',
- 8076 => 'za',
- 8077 => 'zaa',
- 8078 => 'zab',
- 8079 => 'zac',
- 8080 => 'zad',
- 8081 => 'zae',
- 8082 => 'zaf',
- 8083 => 'zag',
- 8084 => 'zah',
- 8085 => 'zai',
- 8086 => 'zaj',
- 8087 => 'zak',
- 8088 => 'zal',
- 8089 => 'zam',
- 8090 => 'zao',
- 8091 => 'zap',
- 8092 => 'zaq',
- 8093 => 'zar',
- 8094 => 'zas',
- 8095 => 'zat',
- 8096 => 'zau',
- 8097 => 'zav',
- 8098 => 'zaw',
- 8099 => 'zax',
- 8100 => 'zay',
- 8101 => 'zaz',
- 8102 => 'zba',
- 8103 => 'zbc',
- 8104 => 'zbe',
- 8105 => 'zbl',
- 8106 => 'zbt',
- 8107 => 'zbu',
- 8108 => 'zbw',
- 8109 => 'zca',
- 8110 => 'zcd',
- 8111 => 'zch',
- 8112 => 'zdj',
- 8113 => 'zea',
- 8114 => 'zeg',
- 8115 => 'zeh',
- 8116 => 'zem',
- 8117 => 'zen',
- 8118 => 'zga',
- 8119 => 'zgb',
- 8120 => 'zgh',
- 8121 => 'zgm',
- 8122 => 'zgn',
- 8123 => 'zgr',
- 8124 => 'zh',
- 8125 => 'zhb',
- 8126 => 'zhd',
- 8127 => 'zhi',
- 8128 => 'zhn',
- 8129 => 'zhw',
- 8130 => 'zhx',
- 8131 => 'zia',
- 8132 => 'zib',
- 8133 => 'zik',
- 8134 => 'zil',
- 8135 => 'zim',
- 8136 => 'zin',
- 8137 => 'zir',
- 8138 => 'ziw',
- 8139 => 'ziz',
- 8140 => 'zka',
- 8141 => 'zkb',
- 8142 => 'zkd',
- 8143 => 'zkg',
- 8144 => 'zkh',
- 8145 => 'zkk',
- 8146 => 'zkn',
- 8147 => 'zko',
- 8148 => 'zkp',
- 8149 => 'zkr',
- 8150 => 'zkt',
- 8151 => 'zku',
- 8152 => 'zkv',
- 8153 => 'zkz',
- 8154 => 'zla',
- 8155 => 'zle',
- 8156 => 'zlj',
- 8157 => 'zlm',
- 8158 => 'zln',
- 8159 => 'zlq',
- 8160 => 'zls',
- 8161 => 'zlu',
- 8162 => 'zlw',
- 8163 => 'zma',
- 8164 => 'zmb',
- 8165 => 'zmc',
- 8166 => 'zmd',
- 8167 => 'zme',
- 8168 => 'zmf',
- 8169 => 'zmg',
- 8170 => 'zmh',
- 8171 => 'zmi',
- 8172 => 'zmj',
- 8173 => 'zmk',
- 8174 => 'zml',
- 8175 => 'zmm',
- 8176 => 'zmn',
- 8177 => 'zmo',
- 8178 => 'zmp',
- 8179 => 'zmq',
- 8180 => 'zmr',
- 8181 => 'zms',
- 8182 => 'zmt',
- 8183 => 'zmu',
- 8184 => 'zmv',
- 8185 => 'zmw',
- 8186 => 'zmx',
- 8187 => 'zmy',
- 8188 => 'zmz',
- 8189 => 'zna',
- 8190 => 'znd',
- 8191 => 'zne',
- 8192 => 'zng',
- 8193 => 'znk',
- 8194 => 'zns',
- 8195 => 'zoc',
- 8196 => 'zoh',
- 8197 => 'zom',
- 8198 => 'zoo',
- 8199 => 'zoq',
- 8200 => 'zor',
- 8201 => 'zos',
- 8202 => 'zpa',
- 8203 => 'zpb',
- 8204 => 'zpc',
- 8205 => 'zpd',
- 8206 => 'zpe',
- 8207 => 'zpf',
- 8208 => 'zpg',
- 8209 => 'zph',
- 8210 => 'zpi',
- 8211 => 'zpj',
- 8212 => 'zpk',
- 8213 => 'zpl',
- 8214 => 'zpm',
- 8215 => 'zpn',
- 8216 => 'zpo',
- 8217 => 'zpp',
- 8218 => 'zpq',
- 8219 => 'zpr',
- 8220 => 'zps',
- 8221 => 'zpt',
- 8222 => 'zpu',
- 8223 => 'zpv',
- 8224 => 'zpw',
- 8225 => 'zpx',
- 8226 => 'zpy',
- 8227 => 'zpz',
- 8228 => 'zqe',
- 8229 => 'zra',
- 8230 => 'zrg',
- 8231 => 'zrn',
- 8232 => 'zro',
- 8233 => 'zrp',
- 8234 => 'zrs',
- 8235 => 'zsa',
- 8236 => 'zsk',
- 8237 => 'zsl',
- 8238 => 'zsm',
- 8239 => 'zsr',
- 8240 => 'zsu',
- 8241 => 'zte',
- 8242 => 'ztg',
- 8243 => 'ztl',
- 8244 => 'ztm',
- 8245 => 'ztn',
- 8246 => 'ztp',
- 8247 => 'ztq',
- 8248 => 'zts',
- 8249 => 'ztt',
- 8250 => 'ztu',
- 8251 => 'ztx',
- 8252 => 'zty',
- 8253 => 'zu',
- 8254 => 'zua',
- 8255 => 'zuh',
- 8256 => 'zum',
- 8257 => 'zun',
- 8258 => 'zuy',
- 8259 => 'zwa',
- 8260 => 'zxx',
- 8261 => 'zyb',
- 8262 => 'zyg',
- 8263 => 'zyj',
- 8264 => 'zyn',
- 8265 => 'zyp',
- 8266 => 'zza',
- 8267 => 'zzj',
+ 5715 => 'qaa',
+ 5716 => 'qab',
+ 5717 => 'qac',
+ 5718 => 'qad',
+ 5719 => 'qae',
+ 5720 => 'qaf',
+ 5721 => 'qag',
+ 5722 => 'qah',
+ 5723 => 'qai',
+ 5724 => 'qaj',
+ 5725 => 'qak',
+ 5726 => 'qal',
+ 5727 => 'qam',
+ 5728 => 'qan',
+ 5729 => 'qao',
+ 5730 => 'qap',
+ 5731 => 'qaq',
+ 5732 => 'qar',
+ 5733 => 'qas',
+ 5734 => 'qat',
+ 5735 => 'qau',
+ 5736 => 'qav',
+ 5737 => 'qaw',
+ 5738 => 'qax',
+ 5739 => 'qay',
+ 5740 => 'qaz',
+ 5741 => 'qba',
+ 5742 => 'qbb',
+ 5743 => 'qbc',
+ 5744 => 'qbd',
+ 5745 => 'qbe',
+ 5746 => 'qbf',
+ 5747 => 'qbg',
+ 5748 => 'qbh',
+ 5749 => 'qbi',
+ 5750 => 'qbj',
+ 5751 => 'qbk',
+ 5752 => 'qbl',
+ 5753 => 'qbm',
+ 5754 => 'qbn',
+ 5755 => 'qbo',
+ 5756 => 'qbp',
+ 5757 => 'qbq',
+ 5758 => 'qbr',
+ 5759 => 'qbs',
+ 5760 => 'qbt',
+ 5761 => 'qbu',
+ 5762 => 'qbv',
+ 5763 => 'qbw',
+ 5764 => 'qbx',
+ 5765 => 'qby',
+ 5766 => 'qbz',
+ 5767 => 'qca',
+ 5768 => 'qcb',
+ 5769 => 'qcc',
+ 5770 => 'qcd',
+ 5771 => 'qce',
+ 5772 => 'qcf',
+ 5773 => 'qcg',
+ 5774 => 'qch',
+ 5775 => 'qci',
+ 5776 => 'qcj',
+ 5777 => 'qck',
+ 5778 => 'qcl',
+ 5779 => 'qcm',
+ 5780 => 'qcn',
+ 5781 => 'qco',
+ 5782 => 'qcp',
+ 5783 => 'qcq',
+ 5784 => 'qcr',
+ 5785 => 'qcs',
+ 5786 => 'qct',
+ 5787 => 'qcu',
+ 5788 => 'qcv',
+ 5789 => 'qcw',
+ 5790 => 'qcx',
+ 5791 => 'qcy',
+ 5792 => 'qcz',
+ 5793 => 'qda',
+ 5794 => 'qdb',
+ 5795 => 'qdc',
+ 5796 => 'qdd',
+ 5797 => 'qde',
+ 5798 => 'qdf',
+ 5799 => 'qdg',
+ 5800 => 'qdh',
+ 5801 => 'qdi',
+ 5802 => 'qdj',
+ 5803 => 'qdk',
+ 5804 => 'qdl',
+ 5805 => 'qdm',
+ 5806 => 'qdn',
+ 5807 => 'qdo',
+ 5808 => 'qdp',
+ 5809 => 'qdq',
+ 5810 => 'qdr',
+ 5811 => 'qds',
+ 5812 => 'qdt',
+ 5813 => 'qdu',
+ 5814 => 'qdv',
+ 5815 => 'qdw',
+ 5816 => 'qdx',
+ 5817 => 'qdy',
+ 5818 => 'qdz',
+ 5819 => 'qea',
+ 5820 => 'qeb',
+ 5821 => 'qec',
+ 5822 => 'qed',
+ 5823 => 'qee',
+ 5824 => 'qef',
+ 5825 => 'qeg',
+ 5826 => 'qeh',
+ 5827 => 'qei',
+ 5828 => 'qej',
+ 5829 => 'qek',
+ 5830 => 'qel',
+ 5831 => 'qem',
+ 5832 => 'qen',
+ 5833 => 'qeo',
+ 5834 => 'qep',
+ 5835 => 'qeq',
+ 5836 => 'qer',
+ 5837 => 'qes',
+ 5838 => 'qet',
+ 5839 => 'qeu',
+ 5840 => 'qev',
+ 5841 => 'qew',
+ 5842 => 'qex',
+ 5843 => 'qey',
+ 5844 => 'qez',
+ 5845 => 'qfa',
+ 5846 => 'qfb',
+ 5847 => 'qfc',
+ 5848 => 'qfd',
+ 5849 => 'qfe',
+ 5850 => 'qff',
+ 5851 => 'qfg',
+ 5852 => 'qfh',
+ 5853 => 'qfi',
+ 5854 => 'qfj',
+ 5855 => 'qfk',
+ 5856 => 'qfl',
+ 5857 => 'qfm',
+ 5858 => 'qfn',
+ 5859 => 'qfo',
+ 5860 => 'qfp',
+ 5861 => 'qfq',
+ 5862 => 'qfr',
+ 5863 => 'qfs',
+ 5864 => 'qft',
+ 5865 => 'qfu',
+ 5866 => 'qfv',
+ 5867 => 'qfw',
+ 5868 => 'qfx',
+ 5869 => 'qfy',
+ 5870 => 'qfz',
+ 5871 => 'qga',
+ 5872 => 'qgb',
+ 5873 => 'qgc',
+ 5874 => 'qgd',
+ 5875 => 'qge',
+ 5876 => 'qgf',
+ 5877 => 'qgg',
+ 5878 => 'qgh',
+ 5879 => 'qgi',
+ 5880 => 'qgj',
+ 5881 => 'qgk',
+ 5882 => 'qgl',
+ 5883 => 'qgm',
+ 5884 => 'qgn',
+ 5885 => 'qgo',
+ 5886 => 'qgp',
+ 5887 => 'qgq',
+ 5888 => 'qgr',
+ 5889 => 'qgs',
+ 5890 => 'qgt',
+ 5891 => 'qgu',
+ 5892 => 'qgv',
+ 5893 => 'qgw',
+ 5894 => 'qgx',
+ 5895 => 'qgy',
+ 5896 => 'qgz',
+ 5897 => 'qha',
+ 5898 => 'qhb',
+ 5899 => 'qhc',
+ 5900 => 'qhd',
+ 5901 => 'qhe',
+ 5902 => 'qhf',
+ 5903 => 'qhg',
+ 5904 => 'qhh',
+ 5905 => 'qhi',
+ 5906 => 'qhj',
+ 5907 => 'qhk',
+ 5908 => 'qhl',
+ 5909 => 'qhm',
+ 5910 => 'qhn',
+ 5911 => 'qho',
+ 5912 => 'qhp',
+ 5913 => 'qhq',
+ 5914 => 'qhr',
+ 5915 => 'qhs',
+ 5916 => 'qht',
+ 5917 => 'qhu',
+ 5918 => 'qhv',
+ 5919 => 'qhw',
+ 5920 => 'qhx',
+ 5921 => 'qhy',
+ 5922 => 'qhz',
+ 5923 => 'qia',
+ 5924 => 'qib',
+ 5925 => 'qic',
+ 5926 => 'qid',
+ 5927 => 'qie',
+ 5928 => 'qif',
+ 5929 => 'qig',
+ 5930 => 'qih',
+ 5931 => 'qii',
+ 5932 => 'qij',
+ 5933 => 'qik',
+ 5934 => 'qil',
+ 5935 => 'qim',
+ 5936 => 'qin',
+ 5937 => 'qio',
+ 5938 => 'qip',
+ 5939 => 'qiq',
+ 5940 => 'qir',
+ 5941 => 'qis',
+ 5942 => 'qit',
+ 5943 => 'qiu',
+ 5944 => 'qiv',
+ 5945 => 'qiw',
+ 5946 => 'qix',
+ 5947 => 'qiy',
+ 5948 => 'qiz',
+ 5949 => 'qja',
+ 5950 => 'qjb',
+ 5951 => 'qjc',
+ 5952 => 'qjd',
+ 5953 => 'qje',
+ 5954 => 'qjf',
+ 5955 => 'qjg',
+ 5956 => 'qjh',
+ 5957 => 'qji',
+ 5958 => 'qjj',
+ 5959 => 'qjk',
+ 5960 => 'qjl',
+ 5961 => 'qjm',
+ 5962 => 'qjn',
+ 5963 => 'qjo',
+ 5964 => 'qjp',
+ 5965 => 'qjq',
+ 5966 => 'qjr',
+ 5967 => 'qjs',
+ 5968 => 'qjt',
+ 5969 => 'qju',
+ 5970 => 'qjv',
+ 5971 => 'qjw',
+ 5972 => 'qjx',
+ 5973 => 'qjy',
+ 5974 => 'qjz',
+ 5975 => 'qka',
+ 5976 => 'qkb',
+ 5977 => 'qkc',
+ 5978 => 'qkd',
+ 5979 => 'qke',
+ 5980 => 'qkf',
+ 5981 => 'qkg',
+ 5982 => 'qkh',
+ 5983 => 'qki',
+ 5984 => 'qkj',
+ 5985 => 'qkk',
+ 5986 => 'qkl',
+ 5987 => 'qkm',
+ 5988 => 'qkn',
+ 5989 => 'qko',
+ 5990 => 'qkp',
+ 5991 => 'qkq',
+ 5992 => 'qkr',
+ 5993 => 'qks',
+ 5994 => 'qkt',
+ 5995 => 'qku',
+ 5996 => 'qkv',
+ 5997 => 'qkw',
+ 5998 => 'qkx',
+ 5999 => 'qky',
+ 6000 => 'qkz',
+ 6001 => 'qla',
+ 6002 => 'qlb',
+ 6003 => 'qlc',
+ 6004 => 'qld',
+ 6005 => 'qle',
+ 6006 => 'qlf',
+ 6007 => 'qlg',
+ 6008 => 'qlh',
+ 6009 => 'qli',
+ 6010 => 'qlj',
+ 6011 => 'qlk',
+ 6012 => 'qll',
+ 6013 => 'qlm',
+ 6014 => 'qln',
+ 6015 => 'qlo',
+ 6016 => 'qlp',
+ 6017 => 'qlq',
+ 6018 => 'qlr',
+ 6019 => 'qls',
+ 6020 => 'qlt',
+ 6021 => 'qlu',
+ 6022 => 'qlv',
+ 6023 => 'qlw',
+ 6024 => 'qlx',
+ 6025 => 'qly',
+ 6026 => 'qlz',
+ 6027 => 'qma',
+ 6028 => 'qmb',
+ 6029 => 'qmc',
+ 6030 => 'qmd',
+ 6031 => 'qme',
+ 6032 => 'qmf',
+ 6033 => 'qmg',
+ 6034 => 'qmh',
+ 6035 => 'qmi',
+ 6036 => 'qmj',
+ 6037 => 'qmk',
+ 6038 => 'qml',
+ 6039 => 'qmm',
+ 6040 => 'qmn',
+ 6041 => 'qmo',
+ 6042 => 'qmp',
+ 6043 => 'qmq',
+ 6044 => 'qmr',
+ 6045 => 'qms',
+ 6046 => 'qmt',
+ 6047 => 'qmu',
+ 6048 => 'qmv',
+ 6049 => 'qmw',
+ 6050 => 'qmx',
+ 6051 => 'qmy',
+ 6052 => 'qmz',
+ 6053 => 'qna',
+ 6054 => 'qnb',
+ 6055 => 'qnc',
+ 6056 => 'qnd',
+ 6057 => 'qne',
+ 6058 => 'qnf',
+ 6059 => 'qng',
+ 6060 => 'qnh',
+ 6061 => 'qni',
+ 6062 => 'qnj',
+ 6063 => 'qnk',
+ 6064 => 'qnl',
+ 6065 => 'qnm',
+ 6066 => 'qnn',
+ 6067 => 'qno',
+ 6068 => 'qnp',
+ 6069 => 'qnq',
+ 6070 => 'qnr',
+ 6071 => 'qns',
+ 6072 => 'qnt',
+ 6073 => 'qnu',
+ 6074 => 'qnv',
+ 6075 => 'qnw',
+ 6076 => 'qnx',
+ 6077 => 'qny',
+ 6078 => 'qnz',
+ 6079 => 'qoa',
+ 6080 => 'qob',
+ 6081 => 'qoc',
+ 6082 => 'qod',
+ 6083 => 'qoe',
+ 6084 => 'qof',
+ 6085 => 'qog',
+ 6086 => 'qoh',
+ 6087 => 'qoi',
+ 6088 => 'qoj',
+ 6089 => 'qok',
+ 6090 => 'qol',
+ 6091 => 'qom',
+ 6092 => 'qon',
+ 6093 => 'qoo',
+ 6094 => 'qop',
+ 6095 => 'qoq',
+ 6096 => 'qor',
+ 6097 => 'qos',
+ 6098 => 'qot',
+ 6099 => 'qou',
+ 6100 => 'qov',
+ 6101 => 'qow',
+ 6102 => 'qox',
+ 6103 => 'qoy',
+ 6104 => 'qoz',
+ 6105 => 'qpa',
+ 6106 => 'qpb',
+ 6107 => 'qpc',
+ 6108 => 'qpd',
+ 6109 => 'qpe',
+ 6110 => 'qpf',
+ 6111 => 'qpg',
+ 6112 => 'qph',
+ 6113 => 'qpi',
+ 6114 => 'qpj',
+ 6115 => 'qpk',
+ 6116 => 'qpl',
+ 6117 => 'qpm',
+ 6118 => 'qpn',
+ 6119 => 'qpo',
+ 6120 => 'qpp',
+ 6121 => 'qpq',
+ 6122 => 'qpr',
+ 6123 => 'qps',
+ 6124 => 'qpt',
+ 6125 => 'qpu',
+ 6126 => 'qpv',
+ 6127 => 'qpw',
+ 6128 => 'qpx',
+ 6129 => 'qpy',
+ 6130 => 'qpz',
+ 6131 => 'qqa',
+ 6132 => 'qqb',
+ 6133 => 'qqc',
+ 6134 => 'qqd',
+ 6135 => 'qqe',
+ 6136 => 'qqf',
+ 6137 => 'qqg',
+ 6138 => 'qqh',
+ 6139 => 'qqi',
+ 6140 => 'qqj',
+ 6141 => 'qqk',
+ 6142 => 'qql',
+ 6143 => 'qqm',
+ 6144 => 'qqn',
+ 6145 => 'qqo',
+ 6146 => 'qqp',
+ 6147 => 'qqq',
+ 6148 => 'qqr',
+ 6149 => 'qqs',
+ 6150 => 'qqt',
+ 6151 => 'qqu',
+ 6152 => 'qqv',
+ 6153 => 'qqw',
+ 6154 => 'qqx',
+ 6155 => 'qqy',
+ 6156 => 'qqz',
+ 6157 => 'qra',
+ 6158 => 'qrb',
+ 6159 => 'qrc',
+ 6160 => 'qrd',
+ 6161 => 'qre',
+ 6162 => 'qrf',
+ 6163 => 'qrg',
+ 6164 => 'qrh',
+ 6165 => 'qri',
+ 6166 => 'qrj',
+ 6167 => 'qrk',
+ 6168 => 'qrl',
+ 6169 => 'qrm',
+ 6170 => 'qrn',
+ 6171 => 'qro',
+ 6172 => 'qrp',
+ 6173 => 'qrq',
+ 6174 => 'qrr',
+ 6175 => 'qrs',
+ 6176 => 'qrt',
+ 6177 => 'qru',
+ 6178 => 'qrv',
+ 6179 => 'qrw',
+ 6180 => 'qrx',
+ 6181 => 'qry',
+ 6182 => 'qrz',
+ 6183 => 'qsa',
+ 6184 => 'qsb',
+ 6185 => 'qsc',
+ 6186 => 'qsd',
+ 6187 => 'qse',
+ 6188 => 'qsf',
+ 6189 => 'qsg',
+ 6190 => 'qsh',
+ 6191 => 'qsi',
+ 6192 => 'qsj',
+ 6193 => 'qsk',
+ 6194 => 'qsl',
+ 6195 => 'qsm',
+ 6196 => 'qsn',
+ 6197 => 'qso',
+ 6198 => 'qsp',
+ 6199 => 'qsq',
+ 6200 => 'qsr',
+ 6201 => 'qss',
+ 6202 => 'qst',
+ 6203 => 'qsu',
+ 6204 => 'qsv',
+ 6205 => 'qsw',
+ 6206 => 'qsx',
+ 6207 => 'qsy',
+ 6208 => 'qsz',
+ 6209 => 'qta',
+ 6210 => 'qtb',
+ 6211 => 'qtc',
+ 6212 => 'qtd',
+ 6213 => 'qte',
+ 6214 => 'qtf',
+ 6215 => 'qtg',
+ 6216 => 'qth',
+ 6217 => 'qti',
+ 6218 => 'qtj',
+ 6219 => 'qtk',
+ 6220 => 'qtl',
+ 6221 => 'qtm',
+ 6222 => 'qtn',
+ 6223 => 'qto',
+ 6224 => 'qtp',
+ 6225 => 'qtq',
+ 6226 => 'qtr',
+ 6227 => 'qts',
+ 6228 => 'qtt',
+ 6229 => 'qtu',
+ 6230 => 'qtv',
+ 6231 => 'qtw',
+ 6232 => 'qtx',
+ 6233 => 'qty',
+ 6234 => 'qtz',
+ 6235 => 'qu',
+ 6236 => 'qua',
+ 6237 => 'qub',
+ 6238 => 'quc',
+ 6239 => 'qud',
+ 6240 => 'quf',
+ 6241 => 'qug',
+ 6242 => 'quh',
+ 6243 => 'qui',
+ 6244 => 'quk',
+ 6245 => 'qul',
+ 6246 => 'qum',
+ 6247 => 'qun',
+ 6248 => 'qup',
+ 6249 => 'quq',
+ 6250 => 'qur',
+ 6251 => 'qus',
+ 6252 => 'quv',
+ 6253 => 'quw',
+ 6254 => 'qux',
+ 6255 => 'quy',
+ 6256 => 'quz',
+ 6257 => 'qva',
+ 6258 => 'qvc',
+ 6259 => 'qve',
+ 6260 => 'qvh',
+ 6261 => 'qvi',
+ 6262 => 'qvj',
+ 6263 => 'qvl',
+ 6264 => 'qvm',
+ 6265 => 'qvn',
+ 6266 => 'qvo',
+ 6267 => 'qvp',
+ 6268 => 'qvs',
+ 6269 => 'qvw',
+ 6270 => 'qvy',
+ 6271 => 'qvz',
+ 6272 => 'qwa',
+ 6273 => 'qwc',
+ 6274 => 'qwe',
+ 6275 => 'qwh',
+ 6276 => 'qwm',
+ 6277 => 'qws',
+ 6278 => 'qwt',
+ 6279 => 'qxa',
+ 6280 => 'qxc',
+ 6281 => 'qxh',
+ 6282 => 'qxl',
+ 6283 => 'qxn',
+ 6284 => 'qxo',
+ 6285 => 'qxp',
+ 6286 => 'qxq',
+ 6287 => 'qxr',
+ 6288 => 'qxs',
+ 6289 => 'qxt',
+ 6290 => 'qxu',
+ 6291 => 'qxw',
+ 6292 => 'qya',
+ 6293 => 'qyp',
+ 6294 => 'raa',
+ 6295 => 'rab',
+ 6296 => 'rac',
+ 6297 => 'rad',
+ 6298 => 'raf',
+ 6299 => 'rag',
+ 6300 => 'rah',
+ 6301 => 'rai',
+ 6302 => 'raj',
+ 6303 => 'rak',
+ 6304 => 'ral',
+ 6305 => 'ram',
+ 6306 => 'ran',
+ 6307 => 'rao',
+ 6308 => 'rap',
+ 6309 => 'raq',
+ 6310 => 'rar',
+ 6311 => 'ras',
+ 6312 => 'rat',
+ 6313 => 'rau',
+ 6314 => 'rav',
+ 6315 => 'raw',
+ 6316 => 'rax',
+ 6317 => 'ray',
+ 6318 => 'raz',
+ 6319 => 'rbb',
+ 6320 => 'rbk',
+ 6321 => 'rbl',
+ 6322 => 'rbp',
+ 6323 => 'rcf',
+ 6324 => 'rdb',
+ 6325 => 'rea',
+ 6326 => 'reb',
+ 6327 => 'ree',
+ 6328 => 'reg',
+ 6329 => 'rei',
+ 6330 => 'rej',
+ 6331 => 'rel',
+ 6332 => 'rem',
+ 6333 => 'ren',
+ 6334 => 'rer',
+ 6335 => 'res',
+ 6336 => 'ret',
+ 6337 => 'rey',
+ 6338 => 'rga',
+ 6339 => 'rge',
+ 6340 => 'rgk',
+ 6341 => 'rgn',
+ 6342 => 'rgr',
+ 6343 => 'rgs',
+ 6344 => 'rgu',
+ 6345 => 'rhg',
+ 6346 => 'rhp',
+ 6347 => 'ria',
+ 6348 => 'rib',
+ 6349 => 'rie',
+ 6350 => 'rif',
+ 6351 => 'ril',
+ 6352 => 'rim',
+ 6353 => 'rin',
+ 6354 => 'rir',
+ 6355 => 'rit',
+ 6356 => 'riu',
+ 6357 => 'rjg',
+ 6358 => 'rji',
+ 6359 => 'rjs',
+ 6360 => 'rka',
+ 6361 => 'rkb',
+ 6362 => 'rkh',
+ 6363 => 'rki',
+ 6364 => 'rkm',
+ 6365 => 'rkt',
+ 6366 => 'rkw',
+ 6367 => 'rm',
+ 6368 => 'rma',
+ 6369 => 'rmb',
+ 6370 => 'rmc',
+ 6371 => 'rmd',
+ 6372 => 'rme',
+ 6373 => 'rmf',
+ 6374 => 'rmg',
+ 6375 => 'rmh',
+ 6376 => 'rmi',
+ 6377 => 'rmk',
+ 6378 => 'rml',
+ 6379 => 'rmm',
+ 6380 => 'rmn',
+ 6381 => 'rmo',
+ 6382 => 'rmp',
+ 6383 => 'rmq',
+ 6384 => 'rmr',
+ 6385 => 'rms',
+ 6386 => 'rmt',
+ 6387 => 'rmu',
+ 6388 => 'rmv',
+ 6389 => 'rmw',
+ 6390 => 'rmx',
+ 6391 => 'rmy',
+ 6392 => 'rmz',
+ 6393 => 'rn',
+ 6394 => 'rna',
+ 6395 => 'rnb',
+ 6396 => 'rnd',
+ 6397 => 'rng',
+ 6398 => 'rnl',
+ 6399 => 'rnn',
+ 6400 => 'rnp',
+ 6401 => 'rnr',
+ 6402 => 'rnw',
+ 6403 => 'ro',
+ 6404 => 'roa',
+ 6405 => 'rob',
+ 6406 => 'roc',
+ 6407 => 'rod',
+ 6408 => 'roe',
+ 6409 => 'rof',
+ 6410 => 'rog',
+ 6411 => 'rol',
+ 6412 => 'rom',
+ 6413 => 'roo',
+ 6414 => 'rop',
+ 6415 => 'ror',
+ 6416 => 'rou',
+ 6417 => 'row',
+ 6418 => 'rpn',
+ 6419 => 'rpt',
+ 6420 => 'rri',
+ 6421 => 'rrm',
+ 6422 => 'rro',
+ 6423 => 'rrt',
+ 6424 => 'rsb',
+ 6425 => 'rsi',
+ 6426 => 'rsk',
+ 6427 => 'rsl',
+ 6428 => 'rsm',
+ 6429 => 'rsn',
+ 6430 => 'rsw',
+ 6431 => 'rtc',
+ 6432 => 'rth',
+ 6433 => 'rtm',
+ 6434 => 'rts',
+ 6435 => 'rtw',
+ 6436 => 'ru',
+ 6437 => 'rub',
+ 6438 => 'ruc',
+ 6439 => 'rue',
+ 6440 => 'ruf',
+ 6441 => 'rug',
+ 6442 => 'ruh',
+ 6443 => 'rui',
+ 6444 => 'ruk',
+ 6445 => 'ruo',
+ 6446 => 'rup',
+ 6447 => 'ruq',
+ 6448 => 'rut',
+ 6449 => 'ruu',
+ 6450 => 'ruy',
+ 6451 => 'ruz',
+ 6452 => 'rw',
+ 6453 => 'rwa',
+ 6454 => 'rwk',
+ 6455 => 'rwl',
+ 6456 => 'rwm',
+ 6457 => 'rwo',
+ 6458 => 'rwr',
+ 6459 => 'rxd',
+ 6460 => 'rxw',
+ 6461 => 'ryn',
+ 6462 => 'rys',
+ 6463 => 'ryu',
+ 6464 => 'rzh',
+ 6465 => 'sa',
+ 6466 => 'saa',
+ 6467 => 'sab',
+ 6468 => 'sac',
+ 6469 => 'sad',
+ 6470 => 'sae',
+ 6471 => 'saf',
+ 6472 => 'sah',
+ 6473 => 'sai',
+ 6474 => 'saj',
+ 6475 => 'sak',
+ 6476 => 'sal',
+ 6477 => 'sam',
+ 6478 => 'sao',
+ 6479 => 'sap',
+ 6480 => 'saq',
+ 6481 => 'sar',
+ 6482 => 'sas',
+ 6483 => 'sat',
+ 6484 => 'sau',
+ 6485 => 'sav',
+ 6486 => 'saw',
+ 6487 => 'sax',
+ 6488 => 'say',
+ 6489 => 'saz',
+ 6490 => 'sba',
+ 6491 => 'sbb',
+ 6492 => 'sbc',
+ 6493 => 'sbd',
+ 6494 => 'sbe',
+ 6495 => 'sbf',
+ 6496 => 'sbg',
+ 6497 => 'sbh',
+ 6498 => 'sbi',
+ 6499 => 'sbj',
+ 6500 => 'sbk',
+ 6501 => 'sbl',
+ 6502 => 'sbm',
+ 6503 => 'sbn',
+ 6504 => 'sbo',
+ 6505 => 'sbp',
+ 6506 => 'sbq',
+ 6507 => 'sbr',
+ 6508 => 'sbs',
+ 6509 => 'sbt',
+ 6510 => 'sbu',
+ 6511 => 'sbv',
+ 6512 => 'sbw',
+ 6513 => 'sbx',
+ 6514 => 'sby',
+ 6515 => 'sbz',
+ 6516 => 'sc',
+ 6517 => 'sca',
+ 6518 => 'scb',
+ 6519 => 'sce',
+ 6520 => 'scf',
+ 6521 => 'scg',
+ 6522 => 'sch',
+ 6523 => 'sci',
+ 6524 => 'sck',
+ 6525 => 'scl',
+ 6526 => 'scn',
+ 6527 => 'sco',
+ 6528 => 'scp',
+ 6529 => 'scq',
+ 6530 => 'scs',
+ 6531 => 'sct',
+ 6532 => 'scu',
+ 6533 => 'scv',
+ 6534 => 'scw',
+ 6535 => 'scx',
+ 6536 => 'sd',
+ 6537 => 'sda',
+ 6538 => 'sdb',
+ 6539 => 'sdc',
+ 6540 => 'sde',
+ 6541 => 'sdf',
+ 6542 => 'sdg',
+ 6543 => 'sdh',
+ 6544 => 'sdj',
+ 6545 => 'sdk',
+ 6546 => 'sdl',
+ 6547 => 'sdm',
+ 6548 => 'sdn',
+ 6549 => 'sdo',
+ 6550 => 'sdp',
+ 6551 => 'sdq',
+ 6552 => 'sdr',
+ 6553 => 'sds',
+ 6554 => 'sdt',
+ 6555 => 'sdu',
+ 6556 => 'sdv',
+ 6557 => 'sdx',
+ 6558 => 'sdz',
+ 6559 => 'se',
+ 6560 => 'sea',
+ 6561 => 'seb',
+ 6562 => 'sec',
+ 6563 => 'sed',
+ 6564 => 'see',
+ 6565 => 'sef',
+ 6566 => 'seg',
+ 6567 => 'seh',
+ 6568 => 'sei',
+ 6569 => 'sej',
+ 6570 => 'sek',
+ 6571 => 'sel',
+ 6572 => 'sem',
+ 6573 => 'sen',
+ 6574 => 'seo',
+ 6575 => 'sep',
+ 6576 => 'seq',
+ 6577 => 'ser',
+ 6578 => 'ses',
+ 6579 => 'set',
+ 6580 => 'seu',
+ 6581 => 'sev',
+ 6582 => 'sew',
+ 6583 => 'sey',
+ 6584 => 'sez',
+ 6585 => 'sfb',
+ 6586 => 'sfe',
+ 6587 => 'sfm',
+ 6588 => 'sfs',
+ 6589 => 'sfw',
+ 6590 => 'sg',
+ 6591 => 'sga',
+ 6592 => 'sgb',
+ 6593 => 'sgc',
+ 6594 => 'sgd',
+ 6595 => 'sge',
+ 6596 => 'sgg',
+ 6597 => 'sgh',
+ 6598 => 'sgi',
+ 6599 => 'sgj',
+ 6600 => 'sgk',
+ 6601 => 'sgl',
+ 6602 => 'sgm',
+ 6603 => 'sgn',
+ 6604 => 'sgo',
+ 6605 => 'sgp',
+ 6606 => 'sgr',
+ 6607 => 'sgs',
+ 6608 => 'sgt',
+ 6609 => 'sgu',
+ 6610 => 'sgw',
+ 6611 => 'sgx',
+ 6612 => 'sgy',
+ 6613 => 'sgz',
+ 6614 => 'sh',
+ 6615 => 'sha',
+ 6616 => 'shb',
+ 6617 => 'shc',
+ 6618 => 'shd',
+ 6619 => 'she',
+ 6620 => 'shg',
+ 6621 => 'shh',
+ 6622 => 'shi',
+ 6623 => 'shj',
+ 6624 => 'shk',
+ 6625 => 'shl',
+ 6626 => 'shm',
+ 6627 => 'shn',
+ 6628 => 'sho',
+ 6629 => 'shp',
+ 6630 => 'shq',
+ 6631 => 'shr',
+ 6632 => 'shs',
+ 6633 => 'sht',
+ 6634 => 'shu',
+ 6635 => 'shv',
+ 6636 => 'shw',
+ 6637 => 'shx',
+ 6638 => 'shy',
+ 6639 => 'shz',
+ 6640 => 'si',
+ 6641 => 'sia',
+ 6642 => 'sib',
+ 6643 => 'sid',
+ 6644 => 'sie',
+ 6645 => 'sif',
+ 6646 => 'sig',
+ 6647 => 'sih',
+ 6648 => 'sii',
+ 6649 => 'sij',
+ 6650 => 'sik',
+ 6651 => 'sil',
+ 6652 => 'sim',
+ 6653 => 'sio',
+ 6654 => 'sip',
+ 6655 => 'siq',
+ 6656 => 'sir',
+ 6657 => 'sis',
+ 6658 => 'sit',
+ 6659 => 'siu',
+ 6660 => 'siv',
+ 6661 => 'siw',
+ 6662 => 'six',
+ 6663 => 'siy',
+ 6664 => 'siz',
+ 6665 => 'sja',
+ 6666 => 'sjb',
+ 6667 => 'sjc',
+ 6668 => 'sjd',
+ 6669 => 'sje',
+ 6670 => 'sjg',
+ 6671 => 'sjk',
+ 6672 => 'sjl',
+ 6673 => 'sjm',
+ 6674 => 'sjn',
+ 6675 => 'sjo',
+ 6676 => 'sjp',
+ 6677 => 'sjr',
+ 6678 => 'sjs',
+ 6679 => 'sjt',
+ 6680 => 'sju',
+ 6681 => 'sjw',
+ 6682 => 'sk',
+ 6683 => 'ska',
+ 6684 => 'skb',
+ 6685 => 'skc',
+ 6686 => 'skd',
+ 6687 => 'ske',
+ 6688 => 'skf',
+ 6689 => 'skg',
+ 6690 => 'skh',
+ 6691 => 'ski',
+ 6692 => 'skj',
+ 6693 => 'skk',
+ 6694 => 'skm',
+ 6695 => 'skn',
+ 6696 => 'sko',
+ 6697 => 'skp',
+ 6698 => 'skq',
+ 6699 => 'skr',
+ 6700 => 'sks',
+ 6701 => 'skt',
+ 6702 => 'sku',
+ 6703 => 'skv',
+ 6704 => 'skw',
+ 6705 => 'skx',
+ 6706 => 'sky',
+ 6707 => 'skz',
+ 6708 => 'sl',
+ 6709 => 'sla',
+ 6710 => 'slc',
+ 6711 => 'sld',
+ 6712 => 'sle',
+ 6713 => 'slf',
+ 6714 => 'slg',
+ 6715 => 'slh',
+ 6716 => 'sli',
+ 6717 => 'slj',
+ 6718 => 'sll',
+ 6719 => 'slm',
+ 6720 => 'sln',
+ 6721 => 'slp',
+ 6722 => 'slq',
+ 6723 => 'slr',
+ 6724 => 'sls',
+ 6725 => 'slt',
+ 6726 => 'slu',
+ 6727 => 'slw',
+ 6728 => 'slx',
+ 6729 => 'sly',
+ 6730 => 'slz',
+ 6731 => 'sm',
+ 6732 => 'sma',
+ 6733 => 'smb',
+ 6734 => 'smc',
+ 6735 => 'smd',
+ 6736 => 'smf',
+ 6737 => 'smg',
+ 6738 => 'smh',
+ 6739 => 'smi',
+ 6740 => 'smj',
+ 6741 => 'smk',
+ 6742 => 'sml',
+ 6743 => 'smm',
+ 6744 => 'smn',
+ 6745 => 'smp',
+ 6746 => 'smq',
+ 6747 => 'smr',
+ 6748 => 'sms',
+ 6749 => 'smt',
+ 6750 => 'smu',
+ 6751 => 'smv',
+ 6752 => 'smw',
+ 6753 => 'smx',
+ 6754 => 'smy',
+ 6755 => 'smz',
+ 6756 => 'sn',
+ 6757 => 'snb',
+ 6758 => 'snc',
+ 6759 => 'sne',
+ 6760 => 'snf',
+ 6761 => 'sng',
+ 6762 => 'snh',
+ 6763 => 'sni',
+ 6764 => 'snj',
+ 6765 => 'snk',
+ 6766 => 'snl',
+ 6767 => 'snm',
+ 6768 => 'snn',
+ 6769 => 'sno',
+ 6770 => 'snp',
+ 6771 => 'snq',
+ 6772 => 'snr',
+ 6773 => 'sns',
+ 6774 => 'snu',
+ 6775 => 'snv',
+ 6776 => 'snw',
+ 6777 => 'snx',
+ 6778 => 'sny',
+ 6779 => 'snz',
+ 6780 => 'so',
+ 6781 => 'soa',
+ 6782 => 'sob',
+ 6783 => 'soc',
+ 6784 => 'sod',
+ 6785 => 'soe',
+ 6786 => 'sog',
+ 6787 => 'soh',
+ 6788 => 'soi',
+ 6789 => 'soj',
+ 6790 => 'sok',
+ 6791 => 'sol',
+ 6792 => 'son',
+ 6793 => 'soo',
+ 6794 => 'sop',
+ 6795 => 'soq',
+ 6796 => 'sor',
+ 6797 => 'sos',
+ 6798 => 'sou',
+ 6799 => 'sov',
+ 6800 => 'sow',
+ 6801 => 'sox',
+ 6802 => 'soy',
+ 6803 => 'soz',
+ 6804 => 'spb',
+ 6805 => 'spc',
+ 6806 => 'spd',
+ 6807 => 'spe',
+ 6808 => 'spg',
+ 6809 => 'spi',
+ 6810 => 'spk',
+ 6811 => 'spl',
+ 6812 => 'spm',
+ 6813 => 'spn',
+ 6814 => 'spo',
+ 6815 => 'spp',
+ 6816 => 'spq',
+ 6817 => 'spr',
+ 6818 => 'sps',
+ 6819 => 'spt',
+ 6820 => 'spu',
+ 6821 => 'spv',
+ 6822 => 'spx',
+ 6823 => 'spy',
+ 6824 => 'sq',
+ 6825 => 'sqa',
+ 6826 => 'sqh',
+ 6827 => 'sqj',
+ 6828 => 'sqk',
+ 6829 => 'sqm',
+ 6830 => 'sqn',
+ 6831 => 'sqo',
+ 6832 => 'sqq',
+ 6833 => 'sqr',
+ 6834 => 'sqs',
+ 6835 => 'sqt',
+ 6836 => 'squ',
+ 6837 => 'sqx',
+ 6838 => 'sr',
+ 6839 => 'sra',
+ 6840 => 'srb',
+ 6841 => 'src',
+ 6842 => 'sre',
+ 6843 => 'srf',
+ 6844 => 'srg',
+ 6845 => 'srh',
+ 6846 => 'sri',
+ 6847 => 'srk',
+ 6848 => 'srl',
+ 6849 => 'srm',
+ 6850 => 'srn',
+ 6851 => 'sro',
+ 6852 => 'srq',
+ 6853 => 'srr',
+ 6854 => 'srs',
+ 6855 => 'srt',
+ 6856 => 'sru',
+ 6857 => 'srv',
+ 6858 => 'srw',
+ 6859 => 'srx',
+ 6860 => 'sry',
+ 6861 => 'srz',
+ 6862 => 'ss',
+ 6863 => 'ssa',
+ 6864 => 'ssb',
+ 6865 => 'ssc',
+ 6866 => 'ssd',
+ 6867 => 'sse',
+ 6868 => 'ssf',
+ 6869 => 'ssg',
+ 6870 => 'ssh',
+ 6871 => 'ssi',
+ 6872 => 'ssj',
+ 6873 => 'ssk',
+ 6874 => 'ssl',
+ 6875 => 'ssm',
+ 6876 => 'ssn',
+ 6877 => 'sso',
+ 6878 => 'ssp',
+ 6879 => 'ssq',
+ 6880 => 'ssr',
+ 6881 => 'sss',
+ 6882 => 'sst',
+ 6883 => 'ssu',
+ 6884 => 'ssv',
+ 6885 => 'ssx',
+ 6886 => 'ssy',
+ 6887 => 'ssz',
+ 6888 => 'st',
+ 6889 => 'sta',
+ 6890 => 'stb',
+ 6891 => 'std',
+ 6892 => 'ste',
+ 6893 => 'stf',
+ 6894 => 'stg',
+ 6895 => 'sth',
+ 6896 => 'sti',
+ 6897 => 'stj',
+ 6898 => 'stk',
+ 6899 => 'stl',
+ 6900 => 'stm',
+ 6901 => 'stn',
+ 6902 => 'sto',
+ 6903 => 'stp',
+ 6904 => 'stq',
+ 6905 => 'str',
+ 6906 => 'sts',
+ 6907 => 'stt',
+ 6908 => 'stu',
+ 6909 => 'stv',
+ 6910 => 'stw',
+ 6911 => 'sty',
+ 6912 => 'su',
+ 6913 => 'sua',
+ 6914 => 'sub',
+ 6915 => 'suc',
+ 6916 => 'sue',
+ 6917 => 'sug',
+ 6918 => 'sui',
+ 6919 => 'suj',
+ 6920 => 'suk',
+ 6921 => 'sul',
+ 6922 => 'sum',
+ 6923 => 'suo',
+ 6924 => 'suq',
+ 6925 => 'sur',
+ 6926 => 'sus',
+ 6927 => 'sut',
+ 6928 => 'suv',
+ 6929 => 'suw',
+ 6930 => 'sux',
+ 6931 => 'suy',
+ 6932 => 'suz',
+ 6933 => 'sv',
+ 6934 => 'sva',
+ 6935 => 'svb',
+ 6936 => 'svc',
+ 6937 => 'sve',
+ 6938 => 'svk',
+ 6939 => 'svm',
+ 6940 => 'svr',
+ 6941 => 'svs',
+ 6942 => 'svx',
+ 6943 => 'sw',
+ 6944 => 'swb',
+ 6945 => 'swc',
+ 6946 => 'swf',
+ 6947 => 'swg',
+ 6948 => 'swh',
+ 6949 => 'swi',
+ 6950 => 'swj',
+ 6951 => 'swk',
+ 6952 => 'swl',
+ 6953 => 'swm',
+ 6954 => 'swn',
+ 6955 => 'swo',
+ 6956 => 'swp',
+ 6957 => 'swq',
+ 6958 => 'swr',
+ 6959 => 'sws',
+ 6960 => 'swt',
+ 6961 => 'swu',
+ 6962 => 'swv',
+ 6963 => 'sww',
+ 6964 => 'swx',
+ 6965 => 'swy',
+ 6966 => 'sxb',
+ 6967 => 'sxc',
+ 6968 => 'sxe',
+ 6969 => 'sxg',
+ 6970 => 'sxk',
+ 6971 => 'sxl',
+ 6972 => 'sxm',
+ 6973 => 'sxn',
+ 6974 => 'sxo',
+ 6975 => 'sxr',
+ 6976 => 'sxs',
+ 6977 => 'sxu',
+ 6978 => 'sxw',
+ 6979 => 'sya',
+ 6980 => 'syb',
+ 6981 => 'syc',
+ 6982 => 'syd',
+ 6983 => 'syi',
+ 6984 => 'syk',
+ 6985 => 'syl',
+ 6986 => 'sym',
+ 6987 => 'syn',
+ 6988 => 'syo',
+ 6989 => 'syr',
+ 6990 => 'sys',
+ 6991 => 'syw',
+ 6992 => 'syx',
+ 6993 => 'syy',
+ 6994 => 'sza',
+ 6995 => 'szb',
+ 6996 => 'szc',
+ 6997 => 'szd',
+ 6998 => 'sze',
+ 6999 => 'szg',
+ 7000 => 'szl',
+ 7001 => 'szn',
+ 7002 => 'szp',
+ 7003 => 'szs',
+ 7004 => 'szv',
+ 7005 => 'szw',
+ 7006 => 'szy',
+ 7007 => 'ta',
+ 7008 => 'taa',
+ 7009 => 'tab',
+ 7010 => 'tac',
+ 7011 => 'tad',
+ 7012 => 'tae',
+ 7013 => 'taf',
+ 7014 => 'tag',
+ 7015 => 'tai',
+ 7016 => 'taj',
+ 7017 => 'tak',
+ 7018 => 'tal',
+ 7019 => 'tan',
+ 7020 => 'tao',
+ 7021 => 'tap',
+ 7022 => 'taq',
+ 7023 => 'tar',
+ 7024 => 'tas',
+ 7025 => 'tau',
+ 7026 => 'tav',
+ 7027 => 'taw',
+ 7028 => 'tax',
+ 7029 => 'tay',
+ 7030 => 'taz',
+ 7031 => 'tba',
+ 7032 => 'tbb',
+ 7033 => 'tbc',
+ 7034 => 'tbd',
+ 7035 => 'tbe',
+ 7036 => 'tbf',
+ 7037 => 'tbg',
+ 7038 => 'tbh',
+ 7039 => 'tbi',
+ 7040 => 'tbj',
+ 7041 => 'tbk',
+ 7042 => 'tbl',
+ 7043 => 'tbm',
+ 7044 => 'tbn',
+ 7045 => 'tbo',
+ 7046 => 'tbp',
+ 7047 => 'tbq',
+ 7048 => 'tbr',
+ 7049 => 'tbs',
+ 7050 => 'tbt',
+ 7051 => 'tbu',
+ 7052 => 'tbv',
+ 7053 => 'tbw',
+ 7054 => 'tbx',
+ 7055 => 'tby',
+ 7056 => 'tbz',
+ 7057 => 'tca',
+ 7058 => 'tcb',
+ 7059 => 'tcc',
+ 7060 => 'tcd',
+ 7061 => 'tce',
+ 7062 => 'tcf',
+ 7063 => 'tcg',
+ 7064 => 'tch',
+ 7065 => 'tci',
+ 7066 => 'tck',
+ 7067 => 'tcl',
+ 7068 => 'tcm',
+ 7069 => 'tcn',
+ 7070 => 'tco',
+ 7071 => 'tcp',
+ 7072 => 'tcq',
+ 7073 => 'tcs',
+ 7074 => 'tct',
+ 7075 => 'tcu',
+ 7076 => 'tcw',
+ 7077 => 'tcx',
+ 7078 => 'tcy',
+ 7079 => 'tcz',
+ 7080 => 'tda',
+ 7081 => 'tdb',
+ 7082 => 'tdc',
+ 7083 => 'tdd',
+ 7084 => 'tde',
+ 7085 => 'tdf',
+ 7086 => 'tdg',
+ 7087 => 'tdh',
+ 7088 => 'tdi',
+ 7089 => 'tdj',
+ 7090 => 'tdk',
+ 7091 => 'tdl',
+ 7092 => 'tdm',
+ 7093 => 'tdn',
+ 7094 => 'tdo',
+ 7095 => 'tdq',
+ 7096 => 'tdr',
+ 7097 => 'tds',
+ 7098 => 'tdt',
+ 7099 => 'tdu',
+ 7100 => 'tdv',
+ 7101 => 'tdx',
+ 7102 => 'tdy',
+ 7103 => 'te',
+ 7104 => 'tea',
+ 7105 => 'teb',
+ 7106 => 'tec',
+ 7107 => 'ted',
+ 7108 => 'tee',
+ 7109 => 'tef',
+ 7110 => 'teg',
+ 7111 => 'teh',
+ 7112 => 'tei',
+ 7113 => 'tek',
+ 7114 => 'tem',
+ 7115 => 'ten',
+ 7116 => 'teo',
+ 7117 => 'tep',
+ 7118 => 'teq',
+ 7119 => 'ter',
+ 7120 => 'tes',
+ 7121 => 'tet',
+ 7122 => 'teu',
+ 7123 => 'tev',
+ 7124 => 'tew',
+ 7125 => 'tex',
+ 7126 => 'tey',
+ 7127 => 'tez',
+ 7128 => 'tfi',
+ 7129 => 'tfn',
+ 7130 => 'tfo',
+ 7131 => 'tfr',
+ 7132 => 'tft',
+ 7133 => 'tg',
+ 7134 => 'tga',
+ 7135 => 'tgb',
+ 7136 => 'tgc',
+ 7137 => 'tgd',
+ 7138 => 'tge',
+ 7139 => 'tgf',
+ 7140 => 'tgg',
+ 7141 => 'tgh',
+ 7142 => 'tgi',
+ 7143 => 'tgj',
+ 7144 => 'tgn',
+ 7145 => 'tgo',
+ 7146 => 'tgp',
+ 7147 => 'tgq',
+ 7148 => 'tgr',
+ 7149 => 'tgs',
+ 7150 => 'tgt',
+ 7151 => 'tgu',
+ 7152 => 'tgv',
+ 7153 => 'tgw',
+ 7154 => 'tgx',
+ 7155 => 'tgy',
+ 7156 => 'tgz',
+ 7157 => 'th',
+ 7158 => 'thc',
+ 7159 => 'thd',
+ 7160 => 'the',
+ 7161 => 'thf',
+ 7162 => 'thh',
+ 7163 => 'thi',
+ 7164 => 'thk',
+ 7165 => 'thl',
+ 7166 => 'thm',
+ 7167 => 'thn',
+ 7168 => 'thp',
+ 7169 => 'thq',
+ 7170 => 'thr',
+ 7171 => 'ths',
+ 7172 => 'tht',
+ 7173 => 'thu',
+ 7174 => 'thv',
+ 7175 => 'thw',
+ 7176 => 'thx',
+ 7177 => 'thy',
+ 7178 => 'thz',
+ 7179 => 'ti',
+ 7180 => 'tia',
+ 7181 => 'tic',
+ 7182 => 'tid',
+ 7183 => 'tie',
+ 7184 => 'tif',
+ 7185 => 'tig',
+ 7186 => 'tih',
+ 7187 => 'tii',
+ 7188 => 'tij',
+ 7189 => 'tik',
+ 7190 => 'til',
+ 7191 => 'tim',
+ 7192 => 'tin',
+ 7193 => 'tio',
+ 7194 => 'tip',
+ 7195 => 'tiq',
+ 7196 => 'tis',
+ 7197 => 'tit',
+ 7198 => 'tiu',
+ 7199 => 'tiv',
+ 7200 => 'tiw',
+ 7201 => 'tix',
+ 7202 => 'tiy',
+ 7203 => 'tiz',
+ 7204 => 'tja',
+ 7205 => 'tjg',
+ 7206 => 'tji',
+ 7207 => 'tjj',
+ 7208 => 'tjl',
+ 7209 => 'tjm',
+ 7210 => 'tjn',
+ 7211 => 'tjo',
+ 7212 => 'tjp',
+ 7213 => 'tjs',
+ 7214 => 'tju',
+ 7215 => 'tjw',
+ 7216 => 'tk',
+ 7217 => 'tka',
+ 7218 => 'tkb',
+ 7219 => 'tkd',
+ 7220 => 'tke',
+ 7221 => 'tkf',
+ 7222 => 'tkg',
+ 7223 => 'tkk',
+ 7224 => 'tkl',
+ 7225 => 'tkm',
+ 7226 => 'tkn',
+ 7227 => 'tkp',
+ 7228 => 'tkq',
+ 7229 => 'tkr',
+ 7230 => 'tks',
+ 7231 => 'tkt',
+ 7232 => 'tku',
+ 7233 => 'tkv',
+ 7234 => 'tkw',
+ 7235 => 'tkx',
+ 7236 => 'tkz',
+ 7237 => 'tl',
+ 7238 => 'tla',
+ 7239 => 'tlb',
+ 7240 => 'tlc',
+ 7241 => 'tld',
+ 7242 => 'tlf',
+ 7243 => 'tlg',
+ 7244 => 'tlh',
+ 7245 => 'tli',
+ 7246 => 'tlj',
+ 7247 => 'tlk',
+ 7248 => 'tll',
+ 7249 => 'tlm',
+ 7250 => 'tln',
+ 7251 => 'tlo',
+ 7252 => 'tlp',
+ 7253 => 'tlq',
+ 7254 => 'tlr',
+ 7255 => 'tls',
+ 7256 => 'tlt',
+ 7257 => 'tlu',
+ 7258 => 'tlv',
+ 7259 => 'tlw',
+ 7260 => 'tlx',
+ 7261 => 'tly',
+ 7262 => 'tma',
+ 7263 => 'tmb',
+ 7264 => 'tmc',
+ 7265 => 'tmd',
+ 7266 => 'tme',
+ 7267 => 'tmf',
+ 7268 => 'tmg',
+ 7269 => 'tmh',
+ 7270 => 'tmi',
+ 7271 => 'tmj',
+ 7272 => 'tmk',
+ 7273 => 'tml',
+ 7274 => 'tmm',
+ 7275 => 'tmn',
+ 7276 => 'tmo',
+ 7277 => 'tmp',
+ 7278 => 'tmq',
+ 7279 => 'tmr',
+ 7280 => 'tms',
+ 7281 => 'tmt',
+ 7282 => 'tmu',
+ 7283 => 'tmv',
+ 7284 => 'tmw',
+ 7285 => 'tmy',
+ 7286 => 'tmz',
+ 7287 => 'tn',
+ 7288 => 'tna',
+ 7289 => 'tnb',
+ 7290 => 'tnc',
+ 7291 => 'tnd',
+ 7292 => 'tne',
+ 7293 => 'tnf',
+ 7294 => 'tng',
+ 7295 => 'tnh',
+ 7296 => 'tni',
+ 7297 => 'tnk',
+ 7298 => 'tnl',
+ 7299 => 'tnm',
+ 7300 => 'tnn',
+ 7301 => 'tno',
+ 7302 => 'tnp',
+ 7303 => 'tnq',
+ 7304 => 'tnr',
+ 7305 => 'tns',
+ 7306 => 'tnt',
+ 7307 => 'tnu',
+ 7308 => 'tnv',
+ 7309 => 'tnw',
+ 7310 => 'tnx',
+ 7311 => 'tny',
+ 7312 => 'tnz',
+ 7313 => 'to',
+ 7314 => 'tob',
+ 7315 => 'toc',
+ 7316 => 'tod',
+ 7317 => 'toe',
+ 7318 => 'tof',
+ 7319 => 'tog',
+ 7320 => 'toh',
+ 7321 => 'toi',
+ 7322 => 'toj',
+ 7323 => 'tok',
+ 7324 => 'tol',
+ 7325 => 'tom',
+ 7326 => 'too',
+ 7327 => 'top',
+ 7328 => 'toq',
+ 7329 => 'tor',
+ 7330 => 'tos',
+ 7331 => 'tou',
+ 7332 => 'tov',
+ 7333 => 'tow',
+ 7334 => 'tox',
+ 7335 => 'toy',
+ 7336 => 'toz',
+ 7337 => 'tpa',
+ 7338 => 'tpc',
+ 7339 => 'tpe',
+ 7340 => 'tpf',
+ 7341 => 'tpg',
+ 7342 => 'tpi',
+ 7343 => 'tpj',
+ 7344 => 'tpk',
+ 7345 => 'tpl',
+ 7346 => 'tpm',
+ 7347 => 'tpn',
+ 7348 => 'tpo',
+ 7349 => 'tpp',
+ 7350 => 'tpq',
+ 7351 => 'tpr',
+ 7352 => 'tpt',
+ 7353 => 'tpu',
+ 7354 => 'tpv',
+ 7355 => 'tpw',
+ 7356 => 'tpx',
+ 7357 => 'tpy',
+ 7358 => 'tpz',
+ 7359 => 'tqb',
+ 7360 => 'tql',
+ 7361 => 'tqm',
+ 7362 => 'tqn',
+ 7363 => 'tqo',
+ 7364 => 'tqp',
+ 7365 => 'tqq',
+ 7366 => 'tqr',
+ 7367 => 'tqt',
+ 7368 => 'tqu',
+ 7369 => 'tqw',
+ 7370 => 'tr',
+ 7371 => 'tra',
+ 7372 => 'trb',
+ 7373 => 'trc',
+ 7374 => 'trd',
+ 7375 => 'tre',
+ 7376 => 'trf',
+ 7377 => 'trg',
+ 7378 => 'trh',
+ 7379 => 'tri',
+ 7380 => 'trj',
+ 7381 => 'trk',
+ 7382 => 'trl',
+ 7383 => 'trm',
+ 7384 => 'trn',
+ 7385 => 'tro',
+ 7386 => 'trp',
+ 7387 => 'trq',
+ 7388 => 'trr',
+ 7389 => 'trs',
+ 7390 => 'trt',
+ 7391 => 'tru',
+ 7392 => 'trv',
+ 7393 => 'trw',
+ 7394 => 'trx',
+ 7395 => 'try',
+ 7396 => 'trz',
+ 7397 => 'ts',
+ 7398 => 'tsa',
+ 7399 => 'tsb',
+ 7400 => 'tsc',
+ 7401 => 'tsd',
+ 7402 => 'tse',
+ 7403 => 'tsf',
+ 7404 => 'tsg',
+ 7405 => 'tsh',
+ 7406 => 'tsi',
+ 7407 => 'tsj',
+ 7408 => 'tsk',
+ 7409 => 'tsl',
+ 7410 => 'tsm',
+ 7411 => 'tsp',
+ 7412 => 'tsq',
+ 7413 => 'tsr',
+ 7414 => 'tss',
+ 7415 => 'tst',
+ 7416 => 'tsu',
+ 7417 => 'tsv',
+ 7418 => 'tsw',
+ 7419 => 'tsx',
+ 7420 => 'tsy',
+ 7421 => 'tsz',
+ 7422 => 'tt',
+ 7423 => 'tta',
+ 7424 => 'ttb',
+ 7425 => 'ttc',
+ 7426 => 'ttd',
+ 7427 => 'tte',
+ 7428 => 'ttf',
+ 7429 => 'ttg',
+ 7430 => 'tth',
+ 7431 => 'tti',
+ 7432 => 'ttj',
+ 7433 => 'ttk',
+ 7434 => 'ttl',
+ 7435 => 'ttm',
+ 7436 => 'ttn',
+ 7437 => 'tto',
+ 7438 => 'ttp',
+ 7439 => 'ttq',
+ 7440 => 'ttr',
+ 7441 => 'tts',
+ 7442 => 'ttt',
+ 7443 => 'ttu',
+ 7444 => 'ttv',
+ 7445 => 'ttw',
+ 7446 => 'tty',
+ 7447 => 'ttz',
+ 7448 => 'tua',
+ 7449 => 'tub',
+ 7450 => 'tuc',
+ 7451 => 'tud',
+ 7452 => 'tue',
+ 7453 => 'tuf',
+ 7454 => 'tug',
+ 7455 => 'tuh',
+ 7456 => 'tui',
+ 7457 => 'tuj',
+ 7458 => 'tul',
+ 7459 => 'tum',
+ 7460 => 'tun',
+ 7461 => 'tuo',
+ 7462 => 'tup',
+ 7463 => 'tuq',
+ 7464 => 'tus',
+ 7465 => 'tut',
+ 7466 => 'tuu',
+ 7467 => 'tuv',
+ 7468 => 'tuw',
+ 7469 => 'tux',
+ 7470 => 'tuy',
+ 7471 => 'tuz',
+ 7472 => 'tva',
+ 7473 => 'tvd',
+ 7474 => 'tve',
+ 7475 => 'tvi',
+ 7476 => 'tvk',
+ 7477 => 'tvl',
+ 7478 => 'tvm',
+ 7479 => 'tvn',
+ 7480 => 'tvo',
+ 7481 => 'tvs',
+ 7482 => 'tvt',
+ 7483 => 'tvu',
+ 7484 => 'tvw',
+ 7485 => 'tvx',
+ 7486 => 'tvy',
+ 7487 => 'tw',
+ 7488 => 'twa',
+ 7489 => 'twb',
+ 7490 => 'twc',
+ 7491 => 'twd',
+ 7492 => 'twe',
+ 7493 => 'twf',
+ 7494 => 'twg',
+ 7495 => 'twh',
+ 7496 => 'twl',
+ 7497 => 'twm',
+ 7498 => 'twn',
+ 7499 => 'two',
+ 7500 => 'twp',
+ 7501 => 'twq',
+ 7502 => 'twr',
+ 7503 => 'twt',
+ 7504 => 'twu',
+ 7505 => 'tww',
+ 7506 => 'twx',
+ 7507 => 'twy',
+ 7508 => 'txa',
+ 7509 => 'txb',
+ 7510 => 'txc',
+ 7511 => 'txe',
+ 7512 => 'txg',
+ 7513 => 'txh',
+ 7514 => 'txi',
+ 7515 => 'txj',
+ 7516 => 'txm',
+ 7517 => 'txn',
+ 7518 => 'txo',
+ 7519 => 'txq',
+ 7520 => 'txr',
+ 7521 => 'txs',
+ 7522 => 'txt',
+ 7523 => 'txu',
+ 7524 => 'txx',
+ 7525 => 'txy',
+ 7526 => 'ty',
+ 7527 => 'tya',
+ 7528 => 'tye',
+ 7529 => 'tyh',
+ 7530 => 'tyi',
+ 7531 => 'tyj',
+ 7532 => 'tyl',
+ 7533 => 'tyn',
+ 7534 => 'typ',
+ 7535 => 'tyr',
+ 7536 => 'tys',
+ 7537 => 'tyt',
+ 7538 => 'tyu',
+ 7539 => 'tyv',
+ 7540 => 'tyx',
+ 7541 => 'tyy',
+ 7542 => 'tyz',
+ 7543 => 'tza',
+ 7544 => 'tzh',
+ 7545 => 'tzj',
+ 7546 => 'tzl',
+ 7547 => 'tzm',
+ 7548 => 'tzn',
+ 7549 => 'tzo',
+ 7550 => 'tzx',
+ 7551 => 'uam',
+ 7552 => 'uan',
+ 7553 => 'uar',
+ 7554 => 'uba',
+ 7555 => 'ubi',
+ 7556 => 'ubl',
+ 7557 => 'ubr',
+ 7558 => 'ubu',
+ 7559 => 'uby',
+ 7560 => 'uda',
+ 7561 => 'ude',
+ 7562 => 'udg',
+ 7563 => 'udi',
+ 7564 => 'udj',
+ 7565 => 'udl',
+ 7566 => 'udm',
+ 7567 => 'udu',
+ 7568 => 'ues',
+ 7569 => 'ufi',
+ 7570 => 'ug',
+ 7571 => 'uga',
+ 7572 => 'ugb',
+ 7573 => 'uge',
+ 7574 => 'ugh',
+ 7575 => 'ugn',
+ 7576 => 'ugo',
+ 7577 => 'ugy',
+ 7578 => 'uha',
+ 7579 => 'uhn',
+ 7580 => 'uis',
+ 7581 => 'uiv',
+ 7582 => 'uji',
+ 7583 => 'uk',
+ 7584 => 'uka',
+ 7585 => 'ukg',
+ 7586 => 'ukh',
+ 7587 => 'uki',
+ 7588 => 'ukk',
+ 7589 => 'ukl',
+ 7590 => 'ukp',
+ 7591 => 'ukq',
+ 7592 => 'uks',
+ 7593 => 'uku',
+ 7594 => 'ukv',
+ 7595 => 'ukw',
+ 7596 => 'uky',
+ 7597 => 'ula',
+ 7598 => 'ulb',
+ 7599 => 'ulc',
+ 7600 => 'ule',
+ 7601 => 'ulf',
+ 7602 => 'uli',
+ 7603 => 'ulk',
+ 7604 => 'ull',
+ 7605 => 'ulm',
+ 7606 => 'uln',
+ 7607 => 'ulu',
+ 7608 => 'ulw',
+ 7609 => 'uly',
+ 7610 => 'uma',
+ 7611 => 'umb',
+ 7612 => 'umc',
+ 7613 => 'umd',
+ 7614 => 'umg',
+ 7615 => 'umi',
+ 7616 => 'umm',
+ 7617 => 'umn',
+ 7618 => 'umo',
+ 7619 => 'ump',
+ 7620 => 'umr',
+ 7621 => 'ums',
+ 7622 => 'umu',
+ 7623 => 'una',
+ 7624 => 'und',
+ 7625 => 'une',
+ 7626 => 'ung',
+ 7627 => 'uni',
+ 7628 => 'unk',
+ 7629 => 'unm',
+ 7630 => 'unn',
+ 7631 => 'unp',
+ 7632 => 'unr',
+ 7633 => 'unu',
+ 7634 => 'unx',
+ 7635 => 'unz',
+ 7636 => 'uok',
+ 7637 => 'uon',
+ 7638 => 'upi',
+ 7639 => 'upv',
+ 7640 => 'ur',
+ 7641 => 'ura',
+ 7642 => 'urb',
+ 7643 => 'urc',
+ 7644 => 'ure',
+ 7645 => 'urf',
+ 7646 => 'urg',
+ 7647 => 'urh',
+ 7648 => 'uri',
+ 7649 => 'urj',
+ 7650 => 'urk',
+ 7651 => 'url',
+ 7652 => 'urm',
+ 7653 => 'urn',
+ 7654 => 'uro',
+ 7655 => 'urp',
+ 7656 => 'urr',
+ 7657 => 'urt',
+ 7658 => 'uru',
+ 7659 => 'urv',
+ 7660 => 'urw',
+ 7661 => 'urx',
+ 7662 => 'ury',
+ 7663 => 'urz',
+ 7664 => 'usa',
+ 7665 => 'ush',
+ 7666 => 'usi',
+ 7667 => 'usk',
+ 7668 => 'usp',
+ 7669 => 'uss',
+ 7670 => 'usu',
+ 7671 => 'uta',
+ 7672 => 'ute',
+ 7673 => 'uth',
+ 7674 => 'utp',
+ 7675 => 'utr',
+ 7676 => 'utu',
+ 7677 => 'uum',
+ 7678 => 'uun',
+ 7679 => 'uur',
+ 7680 => 'uuu',
+ 7681 => 'uve',
+ 7682 => 'uvh',
+ 7683 => 'uvl',
+ 7684 => 'uwa',
+ 7685 => 'uya',
+ 7686 => 'uz',
+ 7687 => 'uzn',
+ 7688 => 'uzs',
+ 7689 => 'vaa',
+ 7690 => 'vae',
+ 7691 => 'vaf',
+ 7692 => 'vag',
+ 7693 => 'vah',
+ 7694 => 'vai',
+ 7695 => 'vaj',
+ 7696 => 'val',
+ 7697 => 'vam',
+ 7698 => 'van',
+ 7699 => 'vao',
+ 7700 => 'vap',
+ 7701 => 'var',
+ 7702 => 'vas',
+ 7703 => 'vau',
+ 7704 => 'vav',
+ 7705 => 'vay',
+ 7706 => 'vbb',
+ 7707 => 'vbk',
+ 7708 => 've',
+ 7709 => 'vec',
+ 7710 => 'ved',
+ 7711 => 'vel',
+ 7712 => 'vem',
+ 7713 => 'veo',
+ 7714 => 'vep',
+ 7715 => 'ver',
+ 7716 => 'vgr',
+ 7717 => 'vgt',
+ 7718 => 'vi',
+ 7719 => 'vic',
+ 7720 => 'vid',
+ 7721 => 'vif',
+ 7722 => 'vig',
+ 7723 => 'vil',
+ 7724 => 'vin',
+ 7725 => 'vis',
+ 7726 => 'vit',
+ 7727 => 'viv',
+ 7728 => 'vjk',
+ 7729 => 'vka',
+ 7730 => 'vki',
+ 7731 => 'vkj',
+ 7732 => 'vkk',
+ 7733 => 'vkl',
+ 7734 => 'vkm',
+ 7735 => 'vkn',
+ 7736 => 'vko',
+ 7737 => 'vkp',
+ 7738 => 'vkt',
+ 7739 => 'vku',
+ 7740 => 'vkz',
+ 7741 => 'vlp',
+ 7742 => 'vls',
+ 7743 => 'vma',
+ 7744 => 'vmb',
+ 7745 => 'vmc',
+ 7746 => 'vmd',
+ 7747 => 'vme',
+ 7748 => 'vmf',
+ 7749 => 'vmg',
+ 7750 => 'vmh',
+ 7751 => 'vmi',
+ 7752 => 'vmj',
+ 7753 => 'vmk',
+ 7754 => 'vml',
+ 7755 => 'vmm',
+ 7756 => 'vmp',
+ 7757 => 'vmq',
+ 7758 => 'vmr',
+ 7759 => 'vms',
+ 7760 => 'vmu',
+ 7761 => 'vmv',
+ 7762 => 'vmw',
+ 7763 => 'vmx',
+ 7764 => 'vmy',
+ 7765 => 'vmz',
+ 7766 => 'vnk',
+ 7767 => 'vnm',
+ 7768 => 'vnp',
+ 7769 => 'vo',
+ 7770 => 'vor',
+ 7771 => 'vot',
+ 7772 => 'vra',
+ 7773 => 'vro',
+ 7774 => 'vrs',
+ 7775 => 'vrt',
+ 7776 => 'vsi',
+ 7777 => 'vsl',
+ 7778 => 'vsn',
+ 7779 => 'vsv',
+ 7780 => 'vto',
+ 7781 => 'vum',
+ 7782 => 'vun',
+ 7783 => 'vut',
+ 7784 => 'vwa',
+ 7785 => 'wa',
+ 7786 => 'waa',
+ 7787 => 'wab',
+ 7788 => 'wac',
+ 7789 => 'wad',
+ 7790 => 'wae',
+ 7791 => 'waf',
+ 7792 => 'wag',
+ 7793 => 'wah',
+ 7794 => 'wai',
+ 7795 => 'waj',
+ 7796 => 'wak',
+ 7797 => 'wal',
+ 7798 => 'wam',
+ 7799 => 'wan',
+ 7800 => 'wao',
+ 7801 => 'wap',
+ 7802 => 'waq',
+ 7803 => 'war',
+ 7804 => 'was',
+ 7805 => 'wat',
+ 7806 => 'wau',
+ 7807 => 'wav',
+ 7808 => 'waw',
+ 7809 => 'wax',
+ 7810 => 'way',
+ 7811 => 'waz',
+ 7812 => 'wba',
+ 7813 => 'wbb',
+ 7814 => 'wbe',
+ 7815 => 'wbf',
+ 7816 => 'wbh',
+ 7817 => 'wbi',
+ 7818 => 'wbj',
+ 7819 => 'wbk',
+ 7820 => 'wbl',
+ 7821 => 'wbm',
+ 7822 => 'wbp',
+ 7823 => 'wbq',
+ 7824 => 'wbr',
+ 7825 => 'wbs',
+ 7826 => 'wbt',
+ 7827 => 'wbv',
+ 7828 => 'wbw',
+ 7829 => 'wca',
+ 7830 => 'wci',
+ 7831 => 'wdd',
+ 7832 => 'wdg',
+ 7833 => 'wdj',
+ 7834 => 'wdk',
+ 7835 => 'wdt',
+ 7836 => 'wdu',
+ 7837 => 'wdy',
+ 7838 => 'wea',
+ 7839 => 'wec',
+ 7840 => 'wed',
+ 7841 => 'weg',
+ 7842 => 'weh',
+ 7843 => 'wei',
+ 7844 => 'wem',
+ 7845 => 'wen',
+ 7846 => 'weo',
+ 7847 => 'wep',
+ 7848 => 'wer',
+ 7849 => 'wes',
+ 7850 => 'wet',
+ 7851 => 'weu',
+ 7852 => 'wew',
+ 7853 => 'wfg',
+ 7854 => 'wga',
+ 7855 => 'wgb',
+ 7856 => 'wgg',
+ 7857 => 'wgi',
+ 7858 => 'wgo',
+ 7859 => 'wgu',
+ 7860 => 'wgw',
+ 7861 => 'wgy',
+ 7862 => 'wha',
+ 7863 => 'whg',
+ 7864 => 'whk',
+ 7865 => 'whu',
+ 7866 => 'wib',
+ 7867 => 'wic',
+ 7868 => 'wie',
+ 7869 => 'wif',
+ 7870 => 'wig',
+ 7871 => 'wih',
+ 7872 => 'wii',
+ 7873 => 'wij',
+ 7874 => 'wik',
+ 7875 => 'wil',
+ 7876 => 'wim',
+ 7877 => 'win',
+ 7878 => 'wir',
+ 7879 => 'wit',
+ 7880 => 'wiu',
+ 7881 => 'wiv',
+ 7882 => 'wiw',
+ 7883 => 'wiy',
+ 7884 => 'wja',
+ 7885 => 'wji',
+ 7886 => 'wka',
+ 7887 => 'wkb',
+ 7888 => 'wkd',
+ 7889 => 'wkl',
+ 7890 => 'wkr',
+ 7891 => 'wku',
+ 7892 => 'wkw',
+ 7893 => 'wky',
+ 7894 => 'wla',
+ 7895 => 'wlc',
+ 7896 => 'wle',
+ 7897 => 'wlg',
+ 7898 => 'wlh',
+ 7899 => 'wli',
+ 7900 => 'wlk',
+ 7901 => 'wll',
+ 7902 => 'wlm',
+ 7903 => 'wlo',
+ 7904 => 'wlr',
+ 7905 => 'wls',
+ 7906 => 'wlu',
+ 7907 => 'wlv',
+ 7908 => 'wlw',
+ 7909 => 'wlx',
+ 7910 => 'wly',
+ 7911 => 'wma',
+ 7912 => 'wmb',
+ 7913 => 'wmc',
+ 7914 => 'wmd',
+ 7915 => 'wme',
+ 7916 => 'wmg',
+ 7917 => 'wmh',
+ 7918 => 'wmi',
+ 7919 => 'wmm',
+ 7920 => 'wmn',
+ 7921 => 'wmo',
+ 7922 => 'wms',
+ 7923 => 'wmt',
+ 7924 => 'wmw',
+ 7925 => 'wmx',
+ 7926 => 'wnb',
+ 7927 => 'wnc',
+ 7928 => 'wnd',
+ 7929 => 'wne',
+ 7930 => 'wng',
+ 7931 => 'wni',
+ 7932 => 'wnk',
+ 7933 => 'wnm',
+ 7934 => 'wnn',
+ 7935 => 'wno',
+ 7936 => 'wnp',
+ 7937 => 'wnu',
+ 7938 => 'wnw',
+ 7939 => 'wny',
+ 7940 => 'wo',
+ 7941 => 'woa',
+ 7942 => 'wob',
+ 7943 => 'woc',
+ 7944 => 'wod',
+ 7945 => 'woe',
+ 7946 => 'wof',
+ 7947 => 'wog',
+ 7948 => 'woi',
+ 7949 => 'wok',
+ 7950 => 'wom',
+ 7951 => 'won',
+ 7952 => 'woo',
+ 7953 => 'wor',
+ 7954 => 'wos',
+ 7955 => 'wow',
+ 7956 => 'woy',
+ 7957 => 'wpc',
+ 7958 => 'wra',
+ 7959 => 'wrb',
+ 7960 => 'wrd',
+ 7961 => 'wrg',
+ 7962 => 'wrh',
+ 7963 => 'wri',
+ 7964 => 'wrk',
+ 7965 => 'wrl',
+ 7966 => 'wrm',
+ 7967 => 'wrn',
+ 7968 => 'wro',
+ 7969 => 'wrp',
+ 7970 => 'wrr',
+ 7971 => 'wrs',
+ 7972 => 'wru',
+ 7973 => 'wrv',
+ 7974 => 'wrw',
+ 7975 => 'wrx',
+ 7976 => 'wry',
+ 7977 => 'wrz',
+ 7978 => 'wsa',
+ 7979 => 'wsg',
+ 7980 => 'wsi',
+ 7981 => 'wsk',
+ 7982 => 'wsr',
+ 7983 => 'wss',
+ 7984 => 'wsu',
+ 7985 => 'wsv',
+ 7986 => 'wtb',
+ 7987 => 'wtf',
+ 7988 => 'wth',
+ 7989 => 'wti',
+ 7990 => 'wtk',
+ 7991 => 'wtm',
+ 7992 => 'wtw',
+ 7993 => 'wua',
+ 7994 => 'wub',
+ 7995 => 'wud',
+ 7996 => 'wuh',
+ 7997 => 'wul',
+ 7998 => 'wum',
+ 7999 => 'wun',
+ 8000 => 'wur',
+ 8001 => 'wut',
+ 8002 => 'wuu',
+ 8003 => 'wuv',
+ 8004 => 'wux',
+ 8005 => 'wuy',
+ 8006 => 'wwa',
+ 8007 => 'wwb',
+ 8008 => 'wwo',
+ 8009 => 'wwr',
+ 8010 => 'www',
+ 8011 => 'wxa',
+ 8012 => 'wxw',
+ 8013 => 'wya',
+ 8014 => 'wyb',
+ 8015 => 'wyi',
+ 8016 => 'wym',
+ 8017 => 'wyn',
+ 8018 => 'wyr',
+ 8019 => 'wyy',
+ 8020 => 'xaa',
+ 8021 => 'xab',
+ 8022 => 'xac',
+ 8023 => 'xad',
+ 8024 => 'xae',
+ 8025 => 'xag',
+ 8026 => 'xai',
+ 8027 => 'xaj',
+ 8028 => 'xak',
+ 8029 => 'xal',
+ 8030 => 'xam',
+ 8031 => 'xan',
+ 8032 => 'xao',
+ 8033 => 'xap',
+ 8034 => 'xaq',
+ 8035 => 'xar',
+ 8036 => 'xas',
+ 8037 => 'xat',
+ 8038 => 'xau',
+ 8039 => 'xav',
+ 8040 => 'xaw',
+ 8041 => 'xay',
+ 8042 => 'xba',
+ 8043 => 'xbb',
+ 8044 => 'xbc',
+ 8045 => 'xbd',
+ 8046 => 'xbe',
+ 8047 => 'xbg',
+ 8048 => 'xbi',
+ 8049 => 'xbj',
+ 8050 => 'xbm',
+ 8051 => 'xbn',
+ 8052 => 'xbo',
+ 8053 => 'xbp',
+ 8054 => 'xbr',
+ 8055 => 'xbw',
+ 8056 => 'xbx',
+ 8057 => 'xby',
+ 8058 => 'xcb',
+ 8059 => 'xcc',
+ 8060 => 'xce',
+ 8061 => 'xcg',
+ 8062 => 'xch',
+ 8063 => 'xcl',
+ 8064 => 'xcm',
+ 8065 => 'xcn',
+ 8066 => 'xco',
+ 8067 => 'xcr',
+ 8068 => 'xct',
+ 8069 => 'xcu',
+ 8070 => 'xcv',
+ 8071 => 'xcw',
+ 8072 => 'xcy',
+ 8073 => 'xda',
+ 8074 => 'xdc',
+ 8075 => 'xdk',
+ 8076 => 'xdm',
+ 8077 => 'xdo',
+ 8078 => 'xdq',
+ 8079 => 'xdy',
+ 8080 => 'xeb',
+ 8081 => 'xed',
+ 8082 => 'xeg',
+ 8083 => 'xel',
+ 8084 => 'xem',
+ 8085 => 'xep',
+ 8086 => 'xer',
+ 8087 => 'xes',
+ 8088 => 'xet',
+ 8089 => 'xeu',
+ 8090 => 'xfa',
+ 8091 => 'xga',
+ 8092 => 'xgb',
+ 8093 => 'xgd',
+ 8094 => 'xgf',
+ 8095 => 'xgg',
+ 8096 => 'xgi',
+ 8097 => 'xgl',
+ 8098 => 'xgm',
+ 8099 => 'xgn',
+ 8100 => 'xgr',
+ 8101 => 'xgu',
+ 8102 => 'xgw',
+ 8103 => 'xh',
+ 8104 => 'xha',
+ 8105 => 'xhc',
+ 8106 => 'xhd',
+ 8107 => 'xhe',
+ 8108 => 'xhm',
+ 8109 => 'xhr',
+ 8110 => 'xht',
+ 8111 => 'xhu',
+ 8112 => 'xhv',
+ 8113 => 'xia',
+ 8114 => 'xib',
+ 8115 => 'xii',
+ 8116 => 'xil',
+ 8117 => 'xin',
+ 8118 => 'xip',
+ 8119 => 'xir',
+ 8120 => 'xis',
+ 8121 => 'xiv',
+ 8122 => 'xiy',
+ 8123 => 'xjb',
+ 8124 => 'xjt',
+ 8125 => 'xka',
+ 8126 => 'xkb',
+ 8127 => 'xkc',
+ 8128 => 'xkd',
+ 8129 => 'xke',
+ 8130 => 'xkf',
+ 8131 => 'xkg',
+ 8132 => 'xkh',
+ 8133 => 'xki',
+ 8134 => 'xkj',
+ 8135 => 'xkk',
+ 8136 => 'xkl',
+ 8137 => 'xkn',
+ 8138 => 'xko',
+ 8139 => 'xkp',
+ 8140 => 'xkq',
+ 8141 => 'xkr',
+ 8142 => 'xks',
+ 8143 => 'xkt',
+ 8144 => 'xku',
+ 8145 => 'xkv',
+ 8146 => 'xkw',
+ 8147 => 'xkx',
+ 8148 => 'xky',
+ 8149 => 'xkz',
+ 8150 => 'xla',
+ 8151 => 'xlb',
+ 8152 => 'xlc',
+ 8153 => 'xld',
+ 8154 => 'xle',
+ 8155 => 'xlg',
+ 8156 => 'xli',
+ 8157 => 'xln',
+ 8158 => 'xlo',
+ 8159 => 'xlp',
+ 8160 => 'xls',
+ 8161 => 'xlu',
+ 8162 => 'xly',
+ 8163 => 'xma',
+ 8164 => 'xmb',
+ 8165 => 'xmc',
+ 8166 => 'xmd',
+ 8167 => 'xme',
+ 8168 => 'xmf',
+ 8169 => 'xmg',
+ 8170 => 'xmh',
+ 8171 => 'xmj',
+ 8172 => 'xmk',
+ 8173 => 'xml',
+ 8174 => 'xmm',
+ 8175 => 'xmn',
+ 8176 => 'xmo',
+ 8177 => 'xmp',
+ 8178 => 'xmq',
+ 8179 => 'xmr',
+ 8180 => 'xms',
+ 8181 => 'xmt',
+ 8182 => 'xmu',
+ 8183 => 'xmv',
+ 8184 => 'xmw',
+ 8185 => 'xmx',
+ 8186 => 'xmy',
+ 8187 => 'xmz',
+ 8188 => 'xna',
+ 8189 => 'xnb',
+ 8190 => 'xnd',
+ 8191 => 'xng',
+ 8192 => 'xnh',
+ 8193 => 'xni',
+ 8194 => 'xnj',
+ 8195 => 'xnk',
+ 8196 => 'xnm',
+ 8197 => 'xnn',
+ 8198 => 'xno',
+ 8199 => 'xnq',
+ 8200 => 'xnr',
+ 8201 => 'xns',
+ 8202 => 'xnt',
+ 8203 => 'xnu',
+ 8204 => 'xny',
+ 8205 => 'xnz',
+ 8206 => 'xoc',
+ 8207 => 'xod',
+ 8208 => 'xog',
+ 8209 => 'xoi',
+ 8210 => 'xok',
+ 8211 => 'xom',
+ 8212 => 'xon',
+ 8213 => 'xoo',
+ 8214 => 'xop',
+ 8215 => 'xor',
+ 8216 => 'xow',
+ 8217 => 'xpa',
+ 8218 => 'xpb',
+ 8219 => 'xpc',
+ 8220 => 'xpd',
+ 8221 => 'xpe',
+ 8222 => 'xpf',
+ 8223 => 'xpg',
+ 8224 => 'xph',
+ 8225 => 'xpi',
+ 8226 => 'xpj',
+ 8227 => 'xpk',
+ 8228 => 'xpl',
+ 8229 => 'xpm',
+ 8230 => 'xpn',
+ 8231 => 'xpo',
+ 8232 => 'xpp',
+ 8233 => 'xpq',
+ 8234 => 'xpr',
+ 8235 => 'xps',
+ 8236 => 'xpt',
+ 8237 => 'xpu',
+ 8238 => 'xpv',
+ 8239 => 'xpw',
+ 8240 => 'xpx',
+ 8241 => 'xpy',
+ 8242 => 'xpz',
+ 8243 => 'xqa',
+ 8244 => 'xqt',
+ 8245 => 'xra',
+ 8246 => 'xrb',
+ 8247 => 'xrd',
+ 8248 => 'xre',
+ 8249 => 'xrg',
+ 8250 => 'xri',
+ 8251 => 'xrm',
+ 8252 => 'xrn',
+ 8253 => 'xrq',
+ 8254 => 'xrr',
+ 8255 => 'xrt',
+ 8256 => 'xru',
+ 8257 => 'xrw',
+ 8258 => 'xsa',
+ 8259 => 'xsb',
+ 8260 => 'xsc',
+ 8261 => 'xsd',
+ 8262 => 'xse',
+ 8263 => 'xsh',
+ 8264 => 'xsi',
+ 8265 => 'xsj',
+ 8266 => 'xsl',
+ 8267 => 'xsm',
+ 8268 => 'xsn',
+ 8269 => 'xso',
+ 8270 => 'xsp',
+ 8271 => 'xsq',
+ 8272 => 'xsr',
+ 8273 => 'xss',
+ 8274 => 'xsu',
+ 8275 => 'xsv',
+ 8276 => 'xsy',
+ 8277 => 'xta',
+ 8278 => 'xtb',
+ 8279 => 'xtc',
+ 8280 => 'xtd',
+ 8281 => 'xte',
+ 8282 => 'xtg',
+ 8283 => 'xth',
+ 8284 => 'xti',
+ 8285 => 'xtj',
+ 8286 => 'xtl',
+ 8287 => 'xtm',
+ 8288 => 'xtn',
+ 8289 => 'xto',
+ 8290 => 'xtp',
+ 8291 => 'xtq',
+ 8292 => 'xtr',
+ 8293 => 'xts',
+ 8294 => 'xtt',
+ 8295 => 'xtu',
+ 8296 => 'xtv',
+ 8297 => 'xtw',
+ 8298 => 'xty',
+ 8299 => 'xtz',
+ 8300 => 'xua',
+ 8301 => 'xub',
+ 8302 => 'xud',
+ 8303 => 'xug',
+ 8304 => 'xuj',
+ 8305 => 'xul',
+ 8306 => 'xum',
+ 8307 => 'xun',
+ 8308 => 'xuo',
+ 8309 => 'xup',
+ 8310 => 'xur',
+ 8311 => 'xut',
+ 8312 => 'xuu',
+ 8313 => 'xve',
+ 8314 => 'xvi',
+ 8315 => 'xvn',
+ 8316 => 'xvo',
+ 8317 => 'xvs',
+ 8318 => 'xwa',
+ 8319 => 'xwc',
+ 8320 => 'xwd',
+ 8321 => 'xwe',
+ 8322 => 'xwg',
+ 8323 => 'xwj',
+ 8324 => 'xwk',
+ 8325 => 'xwl',
+ 8326 => 'xwo',
+ 8327 => 'xwr',
+ 8328 => 'xwt',
+ 8329 => 'xww',
+ 8330 => 'xxb',
+ 8331 => 'xxk',
+ 8332 => 'xxm',
+ 8333 => 'xxr',
+ 8334 => 'xxt',
+ 8335 => 'xya',
+ 8336 => 'xyb',
+ 8337 => 'xyj',
+ 8338 => 'xyk',
+ 8339 => 'xyl',
+ 8340 => 'xyt',
+ 8341 => 'xyy',
+ 8342 => 'xzh',
+ 8343 => 'xzm',
+ 8344 => 'xzp',
+ 8345 => 'yaa',
+ 8346 => 'yab',
+ 8347 => 'yac',
+ 8348 => 'yad',
+ 8349 => 'yae',
+ 8350 => 'yaf',
+ 8351 => 'yag',
+ 8352 => 'yah',
+ 8353 => 'yai',
+ 8354 => 'yaj',
+ 8355 => 'yak',
+ 8356 => 'yal',
+ 8357 => 'yam',
+ 8358 => 'yan',
+ 8359 => 'yao',
+ 8360 => 'yap',
+ 8361 => 'yaq',
+ 8362 => 'yar',
+ 8363 => 'yas',
+ 8364 => 'yat',
+ 8365 => 'yau',
+ 8366 => 'yav',
+ 8367 => 'yaw',
+ 8368 => 'yax',
+ 8369 => 'yay',
+ 8370 => 'yaz',
+ 8371 => 'yba',
+ 8372 => 'ybb',
+ 8373 => 'ybd',
+ 8374 => 'ybe',
+ 8375 => 'ybh',
+ 8376 => 'ybi',
+ 8377 => 'ybj',
+ 8378 => 'ybk',
+ 8379 => 'ybl',
+ 8380 => 'ybm',
+ 8381 => 'ybn',
+ 8382 => 'ybo',
+ 8383 => 'ybx',
+ 8384 => 'yby',
+ 8385 => 'ych',
+ 8386 => 'ycl',
+ 8387 => 'ycn',
+ 8388 => 'ycp',
+ 8389 => 'ycr',
+ 8390 => 'yda',
+ 8391 => 'ydd',
+ 8392 => 'yde',
+ 8393 => 'ydg',
+ 8394 => 'ydk',
+ 8395 => 'yds',
+ 8396 => 'yea',
+ 8397 => 'yec',
+ 8398 => 'yee',
+ 8399 => 'yei',
+ 8400 => 'yej',
+ 8401 => 'yel',
+ 8402 => 'yen',
+ 8403 => 'yer',
+ 8404 => 'yes',
+ 8405 => 'yet',
+ 8406 => 'yeu',
+ 8407 => 'yev',
+ 8408 => 'yey',
+ 8409 => 'yga',
+ 8410 => 'ygi',
+ 8411 => 'ygl',
+ 8412 => 'ygm',
+ 8413 => 'ygp',
+ 8414 => 'ygr',
+ 8415 => 'ygs',
+ 8416 => 'ygu',
+ 8417 => 'ygw',
+ 8418 => 'yha',
+ 8419 => 'yhd',
+ 8420 => 'yhl',
+ 8421 => 'yhs',
+ 8422 => 'yi',
+ 8423 => 'yia',
+ 8424 => 'yif',
+ 8425 => 'yig',
+ 8426 => 'yih',
+ 8427 => 'yii',
+ 8428 => 'yij',
+ 8429 => 'yik',
+ 8430 => 'yil',
+ 8431 => 'yim',
+ 8432 => 'yin',
+ 8433 => 'yip',
+ 8434 => 'yiq',
+ 8435 => 'yir',
+ 8436 => 'yis',
+ 8437 => 'yit',
+ 8438 => 'yiu',
+ 8439 => 'yiv',
+ 8440 => 'yix',
+ 8441 => 'yiy',
+ 8442 => 'yiz',
+ 8443 => 'yka',
+ 8444 => 'ykg',
+ 8445 => 'ykh',
+ 8446 => 'yki',
+ 8447 => 'ykk',
+ 8448 => 'ykl',
+ 8449 => 'ykm',
+ 8450 => 'ykn',
+ 8451 => 'yko',
+ 8452 => 'ykr',
+ 8453 => 'ykt',
+ 8454 => 'yku',
+ 8455 => 'yky',
+ 8456 => 'yla',
+ 8457 => 'ylb',
+ 8458 => 'yle',
+ 8459 => 'ylg',
+ 8460 => 'yli',
+ 8461 => 'yll',
+ 8462 => 'ylm',
+ 8463 => 'yln',
+ 8464 => 'ylo',
+ 8465 => 'ylr',
+ 8466 => 'ylu',
+ 8467 => 'yly',
+ 8468 => 'yma',
+ 8469 => 'ymb',
+ 8470 => 'ymc',
+ 8471 => 'ymd',
+ 8472 => 'yme',
+ 8473 => 'ymg',
+ 8474 => 'ymh',
+ 8475 => 'ymi',
+ 8476 => 'ymk',
+ 8477 => 'yml',
+ 8478 => 'ymm',
+ 8479 => 'ymn',
+ 8480 => 'ymo',
+ 8481 => 'ymp',
+ 8482 => 'ymq',
+ 8483 => 'ymr',
+ 8484 => 'yms',
+ 8485 => 'ymt',
+ 8486 => 'ymx',
+ 8487 => 'ymz',
+ 8488 => 'yna',
+ 8489 => 'ynb',
+ 8490 => 'ynd',
+ 8491 => 'yne',
+ 8492 => 'yng',
+ 8493 => 'ynh',
+ 8494 => 'ynk',
+ 8495 => 'ynl',
+ 8496 => 'ynn',
+ 8497 => 'yno',
+ 8498 => 'ynq',
+ 8499 => 'yns',
+ 8500 => 'ynu',
+ 8501 => 'yo',
+ 8502 => 'yob',
+ 8503 => 'yog',
+ 8504 => 'yoi',
+ 8505 => 'yok',
+ 8506 => 'yol',
+ 8507 => 'yom',
+ 8508 => 'yon',
+ 8509 => 'yos',
+ 8510 => 'yot',
+ 8511 => 'yox',
+ 8512 => 'yoy',
+ 8513 => 'ypa',
+ 8514 => 'ypb',
+ 8515 => 'ypg',
+ 8516 => 'yph',
+ 8517 => 'ypk',
+ 8518 => 'ypm',
+ 8519 => 'ypn',
+ 8520 => 'ypo',
+ 8521 => 'ypp',
+ 8522 => 'ypz',
+ 8523 => 'yra',
+ 8524 => 'yrb',
+ 8525 => 'yre',
+ 8526 => 'yri',
+ 8527 => 'yrk',
+ 8528 => 'yrl',
+ 8529 => 'yrm',
+ 8530 => 'yrn',
+ 8531 => 'yro',
+ 8532 => 'yrs',
+ 8533 => 'yrw',
+ 8534 => 'yry',
+ 8535 => 'ysc',
+ 8536 => 'ysd',
+ 8537 => 'ysg',
+ 8538 => 'ysl',
+ 8539 => 'ysm',
+ 8540 => 'ysn',
+ 8541 => 'yso',
+ 8542 => 'ysp',
+ 8543 => 'ysr',
+ 8544 => 'yss',
+ 8545 => 'ysy',
+ 8546 => 'yta',
+ 8547 => 'ytl',
+ 8548 => 'ytp',
+ 8549 => 'ytw',
+ 8550 => 'yty',
+ 8551 => 'yua',
+ 8552 => 'yub',
+ 8553 => 'yuc',
+ 8554 => 'yud',
+ 8555 => 'yue',
+ 8556 => 'yuf',
+ 8557 => 'yug',
+ 8558 => 'yui',
+ 8559 => 'yuj',
+ 8560 => 'yuk',
+ 8561 => 'yul',
+ 8562 => 'yum',
+ 8563 => 'yun',
+ 8564 => 'yup',
+ 8565 => 'yuq',
+ 8566 => 'yur',
+ 8567 => 'yut',
+ 8568 => 'yuu',
+ 8569 => 'yuw',
+ 8570 => 'yux',
+ 8571 => 'yuy',
+ 8572 => 'yuz',
+ 8573 => 'yva',
+ 8574 => 'yvt',
+ 8575 => 'ywa',
+ 8576 => 'ywg',
+ 8577 => 'ywl',
+ 8578 => 'ywn',
+ 8579 => 'ywq',
+ 8580 => 'ywr',
+ 8581 => 'ywt',
+ 8582 => 'ywu',
+ 8583 => 'yww',
+ 8584 => 'yxa',
+ 8585 => 'yxg',
+ 8586 => 'yxl',
+ 8587 => 'yxm',
+ 8588 => 'yxu',
+ 8589 => 'yxy',
+ 8590 => 'yyr',
+ 8591 => 'yyu',
+ 8592 => 'yyz',
+ 8593 => 'yzg',
+ 8594 => 'yzk',
+ 8595 => 'za',
+ 8596 => 'zaa',
+ 8597 => 'zab',
+ 8598 => 'zac',
+ 8599 => 'zad',
+ 8600 => 'zae',
+ 8601 => 'zaf',
+ 8602 => 'zag',
+ 8603 => 'zah',
+ 8604 => 'zai',
+ 8605 => 'zaj',
+ 8606 => 'zak',
+ 8607 => 'zal',
+ 8608 => 'zam',
+ 8609 => 'zao',
+ 8610 => 'zap',
+ 8611 => 'zaq',
+ 8612 => 'zar',
+ 8613 => 'zas',
+ 8614 => 'zat',
+ 8615 => 'zau',
+ 8616 => 'zav',
+ 8617 => 'zaw',
+ 8618 => 'zax',
+ 8619 => 'zay',
+ 8620 => 'zaz',
+ 8621 => 'zba',
+ 8622 => 'zbc',
+ 8623 => 'zbe',
+ 8624 => 'zbl',
+ 8625 => 'zbt',
+ 8626 => 'zbu',
+ 8627 => 'zbw',
+ 8628 => 'zca',
+ 8629 => 'zcd',
+ 8630 => 'zch',
+ 8631 => 'zdj',
+ 8632 => 'zea',
+ 8633 => 'zeg',
+ 8634 => 'zeh',
+ 8635 => 'zem',
+ 8636 => 'zen',
+ 8637 => 'zga',
+ 8638 => 'zgb',
+ 8639 => 'zgh',
+ 8640 => 'zgm',
+ 8641 => 'zgn',
+ 8642 => 'zgr',
+ 8643 => 'zh',
+ 8644 => 'zhb',
+ 8645 => 'zhd',
+ 8646 => 'zhi',
+ 8647 => 'zhn',
+ 8648 => 'zhw',
+ 8649 => 'zhx',
+ 8650 => 'zia',
+ 8651 => 'zib',
+ 8652 => 'zik',
+ 8653 => 'zil',
+ 8654 => 'zim',
+ 8655 => 'zin',
+ 8656 => 'zir',
+ 8657 => 'ziw',
+ 8658 => 'ziz',
+ 8659 => 'zka',
+ 8660 => 'zkb',
+ 8661 => 'zkd',
+ 8662 => 'zkg',
+ 8663 => 'zkh',
+ 8664 => 'zkk',
+ 8665 => 'zkn',
+ 8666 => 'zko',
+ 8667 => 'zkp',
+ 8668 => 'zkr',
+ 8669 => 'zkt',
+ 8670 => 'zku',
+ 8671 => 'zkv',
+ 8672 => 'zkz',
+ 8673 => 'zla',
+ 8674 => 'zle',
+ 8675 => 'zlj',
+ 8676 => 'zlm',
+ 8677 => 'zln',
+ 8678 => 'zlq',
+ 8679 => 'zls',
+ 8680 => 'zlu',
+ 8681 => 'zlw',
+ 8682 => 'zma',
+ 8683 => 'zmb',
+ 8684 => 'zmc',
+ 8685 => 'zmd',
+ 8686 => 'zme',
+ 8687 => 'zmf',
+ 8688 => 'zmg',
+ 8689 => 'zmh',
+ 8690 => 'zmi',
+ 8691 => 'zmj',
+ 8692 => 'zmk',
+ 8693 => 'zml',
+ 8694 => 'zmm',
+ 8695 => 'zmn',
+ 8696 => 'zmo',
+ 8697 => 'zmp',
+ 8698 => 'zmq',
+ 8699 => 'zmr',
+ 8700 => 'zms',
+ 8701 => 'zmt',
+ 8702 => 'zmu',
+ 8703 => 'zmv',
+ 8704 => 'zmw',
+ 8705 => 'zmx',
+ 8706 => 'zmy',
+ 8707 => 'zmz',
+ 8708 => 'zna',
+ 8709 => 'znd',
+ 8710 => 'zne',
+ 8711 => 'zng',
+ 8712 => 'znk',
+ 8713 => 'zns',
+ 8714 => 'zoc',
+ 8715 => 'zoh',
+ 8716 => 'zom',
+ 8717 => 'zoo',
+ 8718 => 'zoq',
+ 8719 => 'zor',
+ 8720 => 'zos',
+ 8721 => 'zpa',
+ 8722 => 'zpb',
+ 8723 => 'zpc',
+ 8724 => 'zpd',
+ 8725 => 'zpe',
+ 8726 => 'zpf',
+ 8727 => 'zpg',
+ 8728 => 'zph',
+ 8729 => 'zpi',
+ 8730 => 'zpj',
+ 8731 => 'zpk',
+ 8732 => 'zpl',
+ 8733 => 'zpm',
+ 8734 => 'zpn',
+ 8735 => 'zpo',
+ 8736 => 'zpp',
+ 8737 => 'zpq',
+ 8738 => 'zpr',
+ 8739 => 'zps',
+ 8740 => 'zpt',
+ 8741 => 'zpu',
+ 8742 => 'zpv',
+ 8743 => 'zpw',
+ 8744 => 'zpx',
+ 8745 => 'zpy',
+ 8746 => 'zpz',
+ 8747 => 'zqe',
+ 8748 => 'zra',
+ 8749 => 'zrg',
+ 8750 => 'zrn',
+ 8751 => 'zro',
+ 8752 => 'zrp',
+ 8753 => 'zrs',
+ 8754 => 'zsa',
+ 8755 => 'zsk',
+ 8756 => 'zsl',
+ 8757 => 'zsm',
+ 8758 => 'zsr',
+ 8759 => 'zsu',
+ 8760 => 'zte',
+ 8761 => 'ztg',
+ 8762 => 'ztl',
+ 8763 => 'ztm',
+ 8764 => 'ztn',
+ 8765 => 'ztp',
+ 8766 => 'ztq',
+ 8767 => 'zts',
+ 8768 => 'ztt',
+ 8769 => 'ztu',
+ 8770 => 'ztx',
+ 8771 => 'zty',
+ 8772 => 'zu',
+ 8773 => 'zua',
+ 8774 => 'zuh',
+ 8775 => 'zum',
+ 8776 => 'zun',
+ 8777 => 'zuy',
+ 8778 => 'zwa',
+ 8779 => 'zxx',
+ 8780 => 'zyb',
+ 8781 => 'zyg',
+ 8782 => 'zyj',
+ 8783 => 'zyn',
+ 8784 => 'zyp',
+ 8785 => 'zza',
+ 8786 => 'zzj',
),
'scripts' =>
array (
@@ -8434,76 +8953,125 @@
152 => 'Plrd',
153 => 'Prti',
154 => 'Psin',
- 155 => 'Qaaa..qabx',
- 156 => 'Ranj',
- 157 => 'Rjng',
- 158 => 'Rohg',
- 159 => 'Roro',
- 160 => 'Runr',
- 161 => 'Samr',
- 162 => 'Sara',
- 163 => 'Sarb',
- 164 => 'Saur',
- 165 => 'Seal',
- 166 => 'Sgnw',
- 167 => 'Shaw',
- 168 => 'Shrd',
- 169 => 'Shui',
- 170 => 'Sidd',
- 171 => 'Sidt',
- 172 => 'Sind',
- 173 => 'Sinh',
- 174 => 'Sogd',
- 175 => 'Sogo',
- 176 => 'Sora',
- 177 => 'Soyo',
- 178 => 'Sund',
- 179 => 'Sunu',
- 180 => 'Sylo',
- 181 => 'Syrc',
- 182 => 'Syre',
- 183 => 'Syrj',
- 184 => 'Syrn',
- 185 => 'Tagb',
- 186 => 'Takr',
- 187 => 'Tale',
- 188 => 'Talu',
- 189 => 'Taml',
- 190 => 'Tang',
- 191 => 'Tavt',
- 192 => 'Tayo',
- 193 => 'Telu',
- 194 => 'Teng',
- 195 => 'Tfng',
- 196 => 'Tglg',
- 197 => 'Thaa',
- 198 => 'Thai',
- 199 => 'Tibt',
- 200 => 'Tirh',
- 201 => 'Tnsa',
- 202 => 'Todr',
- 203 => 'Tols',
- 204 => 'Toto',
- 205 => 'Tutg',
- 206 => 'Ugar',
- 207 => 'Vaii',
- 208 => 'Visp',
- 209 => 'Vith',
- 210 => 'Wara',
- 211 => 'Wcho',
- 212 => 'Wole',
- 213 => 'Xpeo',
- 214 => 'Xsux',
- 215 => 'Yezi',
- 216 => 'Yiii',
- 217 => 'Zanb',
- 218 => 'Zinh',
- 219 => 'Zmth',
- 220 => 'Zsye',
- 221 => 'Zsym',
- 222 => 'Zxxx',
- 223 => 'Zyyy',
- 224 => 'Zzzz',
+ 155 => 'Qaaa',
+ 156 => 'Qaab',
+ 157 => 'Qaac',
+ 158 => 'Qaad',
+ 159 => 'Qaae',
+ 160 => 'Qaaf',
+ 161 => 'Qaag',
+ 162 => 'Qaah',
+ 163 => 'Qaai',
+ 164 => 'Qaaj',
+ 165 => 'Qaak',
+ 166 => 'Qaal',
+ 167 => 'Qaam',
+ 168 => 'Qaan',
+ 169 => 'Qaao',
+ 170 => 'Qaap',
+ 171 => 'Qaaq',
+ 172 => 'Qaar',
+ 173 => 'Qaas',
+ 174 => 'Qaat',
+ 175 => 'Qaau',
+ 176 => 'Qaav',
+ 177 => 'Qaaw',
+ 178 => 'Qaax',
+ 179 => 'Qaay',
+ 180 => 'Qaaz',
+ 181 => 'Qaba',
+ 182 => 'Qabb',
+ 183 => 'Qabc',
+ 184 => 'Qabd',
+ 185 => 'Qabe',
+ 186 => 'Qabf',
+ 187 => 'Qabg',
+ 188 => 'Qabh',
+ 189 => 'Qabi',
+ 190 => 'Qabj',
+ 191 => 'Qabk',
+ 192 => 'Qabl',
+ 193 => 'Qabm',
+ 194 => 'Qabn',
+ 195 => 'Qabo',
+ 196 => 'Qabp',
+ 197 => 'Qabq',
+ 198 => 'Qabr',
+ 199 => 'Qabs',
+ 200 => 'Qabt',
+ 201 => 'Qabu',
+ 202 => 'Qabv',
+ 203 => 'Qabw',
+ 204 => 'Qabx',
+ 205 => 'Ranj',
+ 206 => 'Rjng',
+ 207 => 'Rohg',
+ 208 => 'Roro',
+ 209 => 'Runr',
+ 210 => 'Samr',
+ 211 => 'Sara',
+ 212 => 'Sarb',
+ 213 => 'Saur',
+ 214 => 'Seal',
+ 215 => 'Sgnw',
+ 216 => 'Shaw',
+ 217 => 'Shrd',
+ 218 => 'Shui',
+ 219 => 'Sidd',
+ 220 => 'Sidt',
+ 221 => 'Sind',
+ 222 => 'Sinh',
+ 223 => 'Sogd',
+ 224 => 'Sogo',
+ 225 => 'Sora',
+ 226 => 'Soyo',
+ 227 => 'Sund',
+ 228 => 'Sunu',
+ 229 => 'Sylo',
+ 230 => 'Syrc',
+ 231 => 'Syre',
+ 232 => 'Syrj',
+ 233 => 'Syrn',
+ 234 => 'Tagb',
+ 235 => 'Takr',
+ 236 => 'Tale',
+ 237 => 'Talu',
+ 238 => 'Taml',
+ 239 => 'Tang',
+ 240 => 'Tavt',
+ 241 => 'Tayo',
+ 242 => 'Telu',
+ 243 => 'Teng',
+ 244 => 'Tfng',
+ 245 => 'Tglg',
+ 246 => 'Thaa',
+ 247 => 'Thai',
+ 248 => 'Tibt',
+ 249 => 'Tirh',
+ 250 => 'Tnsa',
+ 251 => 'Todr',
+ 252 => 'Tols',
+ 253 => 'Toto',
+ 254 => 'Tutg',
+ 255 => 'Ugar',
+ 256 => 'Vaii',
+ 257 => 'Visp',
+ 258 => 'Vith',
+ 259 => 'Wara',
+ 260 => 'Wcho',
+ 261 => 'Wole',
+ 262 => 'Xpeo',
+ 263 => 'Xsux',
+ 264 => 'Yezi',
+ 265 => 'Yiii',
+ 266 => 'Zanb',
+ 267 => 'Zinh',
+ 268 => 'Zmth',
+ 269 => 'Zsye',
+ 270 => 'Zsym',
+ 271 => 'Zxxx',
+ 272 => 'Zyyy',
+ 273 => 'Zzzz',
),
'regions' =>
array (
@@ -8740,78 +9308,116 @@
230 => 'PW',
231 => 'PY',
232 => 'QA',
- 233 => 'QM..QZ',
- 234 => 'RE',
- 235 => 'RO',
- 236 => 'RS',
- 237 => 'RU',
- 238 => 'RW',
- 239 => 'SA',
- 240 => 'SB',
- 241 => 'SC',
- 242 => 'SD',
- 243 => 'SE',
- 244 => 'SG',
- 245 => 'SH',
- 246 => 'SI',
- 247 => 'SJ',
- 248 => 'SK',
- 249 => 'SL',
- 250 => 'SM',
- 251 => 'SN',
- 252 => 'SO',
- 253 => 'SR',
- 254 => 'SS',
- 255 => 'ST',
- 256 => 'SU',
- 257 => 'SV',
- 258 => 'SX',
- 259 => 'SY',
- 260 => 'SZ',
- 261 => 'TA',
- 262 => 'TC',
- 263 => 'TD',
- 264 => 'TF',
- 265 => 'TG',
- 266 => 'TH',
- 267 => 'TJ',
- 268 => 'TK',
- 269 => 'TL',
- 270 => 'TM',
- 271 => 'TN',
- 272 => 'TO',
- 273 => 'TP',
- 274 => 'TR',
- 275 => 'TT',
- 276 => 'TV',
- 277 => 'TW',
- 278 => 'TZ',
- 279 => 'UA',
- 280 => 'UG',
- 281 => 'UM',
- 282 => 'UN',
- 283 => 'US',
- 284 => 'UY',
- 285 => 'UZ',
- 286 => 'VA',
- 287 => 'VC',
- 288 => 'VE',
- 289 => 'VG',
- 290 => 'VI',
- 291 => 'VN',
- 292 => 'VU',
- 293 => 'WF',
- 294 => 'WS',
- 295 => 'XA..XZ',
- 296 => 'YD',
- 297 => 'YE',
- 298 => 'YT',
- 299 => 'YU',
- 300 => 'ZA',
- 301 => 'ZM',
- 302 => 'ZR',
- 303 => 'ZW',
- 304 => 'ZZ',
+ 233 => 'QM',
+ 234 => 'QN',
+ 235 => 'QO',
+ 236 => 'QP',
+ 237 => 'QQ',
+ 238 => 'QR',
+ 239 => 'QS',
+ 240 => 'QT',
+ 241 => 'QU',
+ 242 => 'QV',
+ 243 => 'QW',
+ 244 => 'QX',
+ 245 => 'QY',
+ 246 => 'QZ',
+ 247 => 'RE',
+ 248 => 'RO',
+ 249 => 'RS',
+ 250 => 'RU',
+ 251 => 'RW',
+ 252 => 'SA',
+ 253 => 'SB',
+ 254 => 'SC',
+ 255 => 'SD',
+ 256 => 'SE',
+ 257 => 'SG',
+ 258 => 'SH',
+ 259 => 'SI',
+ 260 => 'SJ',
+ 261 => 'SK',
+ 262 => 'SL',
+ 263 => 'SM',
+ 264 => 'SN',
+ 265 => 'SO',
+ 266 => 'SR',
+ 267 => 'SS',
+ 268 => 'ST',
+ 269 => 'SU',
+ 270 => 'SV',
+ 271 => 'SX',
+ 272 => 'SY',
+ 273 => 'SZ',
+ 274 => 'TA',
+ 275 => 'TC',
+ 276 => 'TD',
+ 277 => 'TF',
+ 278 => 'TG',
+ 279 => 'TH',
+ 280 => 'TJ',
+ 281 => 'TK',
+ 282 => 'TL',
+ 283 => 'TM',
+ 284 => 'TN',
+ 285 => 'TO',
+ 286 => 'TP',
+ 287 => 'TR',
+ 288 => 'TT',
+ 289 => 'TV',
+ 290 => 'TW',
+ 291 => 'TZ',
+ 292 => 'UA',
+ 293 => 'UG',
+ 294 => 'UM',
+ 295 => 'UN',
+ 296 => 'US',
+ 297 => 'UY',
+ 298 => 'UZ',
+ 299 => 'VA',
+ 300 => 'VC',
+ 301 => 'VE',
+ 302 => 'VG',
+ 303 => 'VI',
+ 304 => 'VN',
+ 305 => 'VU',
+ 306 => 'WF',
+ 307 => 'WS',
+ 308 => 'XA',
+ 309 => 'XB',
+ 310 => 'XC',
+ 311 => 'XD',
+ 312 => 'XE',
+ 313 => 'XF',
+ 314 => 'XG',
+ 315 => 'XH',
+ 316 => 'XI',
+ 317 => 'XJ',
+ 318 => 'XK',
+ 319 => 'XL',
+ 320 => 'XM',
+ 321 => 'XN',
+ 322 => 'XO',
+ 323 => 'XP',
+ 324 => 'XQ',
+ 325 => 'XR',
+ 326 => 'XS',
+ 327 => 'XT',
+ 328 => 'XU',
+ 329 => 'XV',
+ 330 => 'XW',
+ 331 => 'XX',
+ 332 => 'XY',
+ 333 => 'XZ',
+ 334 => 'YD',
+ 335 => 'YE',
+ 336 => 'YT',
+ 337 => 'YU',
+ 338 => 'ZA',
+ 339 => 'ZM',
+ 340 => 'ZR',
+ 341 => 'ZW',
+ 342 => 'ZZ',
),
'variants' =>
array (
diff --git a/src/Utils/expandAlphaRangeFunction.php b/src/Utils/expandAlphaRangeFunction.php
new file mode 100644
index 0000000..49066e7
--- /dev/null
+++ b/src/Utils/expandAlphaRangeFunction.php
@@ -0,0 +1,41 @@
+= 0; $i--) {
+ if ($chars[$i] === 'z') {
+ $chars[$i] = 'a';
+ } elseif ($chars[$i] === 'Z') {
+ $chars[$i] = 'A';
+ } else {
+ $chars[$i] = chr(ord($chars[$i]) + 1);
+ break;
+ }
+ }
+
+ $current = implode('', $chars);
+ }
+}
diff --git a/src/ValueObject/LanguageTag.php b/src/ValueObject/LanguageTag.php
new file mode 100644
index 0000000..bb2221c
--- /dev/null
+++ b/src/ValueObject/LanguageTag.php
@@ -0,0 +1,45 @@
+validateParsedTag($parsedTag);
+
+ return new self(
+ $parsedTag->getLanguage(),
+ $parsedTag->getScript(),
+ $parsedTag->getRegion(),
+ $parsedTag->getVariants(),
+ );
+ }
+}
diff --git a/src/ValueObject/ParsedTag.php b/src/ValueObject/ParsedTag.php
index 7f600e2..b1e6c7f 100644
--- a/src/ValueObject/ParsedTag.php
+++ b/src/ValueObject/ParsedTag.php
@@ -4,12 +4,22 @@
namespace LHcze\BCP47\ValueObject;
+use JsonSerializable;
+use Stringable;
+
/**
- * Value object representing a parsed BCP47 language tag
+ * @internal Parsed tag is internally recognized only as a semantically correct, but not necessarily valid language tag.
+ * It's usually used as an argument for IanaSubtagRegistry::validate() method or for carrying around the code base as
+ * a value object.
+ *
+ * NOTE: While JSON representation includes variants, the __toString() method DOES NOT - only language-region-script.
+ * If you want to get the full tag string, use __toStringWithVariants() method.
*/
-readonly class ParsedTag
+readonly class ParsedTag implements Stringable, JsonSerializable
{
/**
+ * Create a new ParsedTag instance.
+ *
* @param string $language The language subtag (e.g., 'en')
* @param string|null $script The script subtag (e.g., 'Latn')
* @param string|null $region The region subtag (e.g., 'US')
@@ -80,4 +90,56 @@ public function hasVariants(): bool
{
return count($this->variants) > 0;
}
+
+ /**
+ * @return array
+ */
+ public function jsonSerialize(): array
+ {
+ return [
+ 'language' => $this->language,
+ 'script' => $this->script,
+ 'region' => $this->region,
+ 'variants' => $this->variants,
+ ];
+ }
+
+ /**
+ * Get the full tag string including variants.
+ *
+ * @return string The full tag string including variants.
+ *
+ * NOTE: The __toString() method DOES NOT include variants, only language-region-script.
+ * If you want to get the full tag string, use this method.
+ *
+ * @see ParsedTag::__toString()
+ */
+ public function __toStringWithVariants(): string
+ {
+ if (!$this->hasVariants()) {
+ return $this->__toString();
+ }
+
+ return $this->__toString() . '-' . implode('-', $this->variants);
+ }
+
+ /**
+ * Get the full tag string without variants
+ */
+ public function __toString(): string
+ {
+ $result = [];
+
+ $result[] = $this->language;
+
+ if ($this->hasScript()) {
+ $result[] = $this->script;
+ }
+
+ if ($this->hasRegion()) {
+ $result[] = $this->region;
+ }
+
+ return implode('-', $result);
+ }
}
diff --git a/tests/BCP47TagTest.php b/tests/BCP47TagTest.php
index 770c92b..947645a 100644
--- a/tests/BCP47TagTest.php
+++ b/tests/BCP47TagTest.php
@@ -5,70 +5,108 @@
namespace LHcze\BCP47\Tests;
use LHcze\BCP47\BCP47Tag;
-use LHcze\BCP47\ValueObject\ParsedTag;
-use InvalidArgumentException;
+use LHcze\BCP47\Exception\BCP47IanaRegistryException;
+use LHcze\BCP47\Exception\BCP47InvalidArgumentException;
+use LHcze\BCP47\Exception\BCP47InvalidFallbackLocaleException;
+use LHcze\BCP47\Exception\BCP47InvalidLocaleException;
+use LHcze\BCP47\Exception\BCP47InvalidMatchingTagException;
+use LHcze\BCP47\ValueObject\LanguageTag;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class BCP47TagTest extends TestCase
{
+ /**
+ * @throws BCP47InvalidArgumentException
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidMatchingTagException
+ */
#[DataProvider('provideValidLocales')]
public function testConstructWithValidBCP47Tag(string $input, string $expected): void
{
$locale = new BCP47Tag($input);
- $this->assertSame($input, $locale->getOriginalInput());
+ $this->assertSame($input, $locale->getInputLocale());
$this->assertSame($expected, $locale->getNormalized());
}
+ /**
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidMatchingTagException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidArgumentException
+ */
#[DataProvider('provideLocalesWithKnownTags')]
public function testConstructWithKnownTags(
string $input,
- array $knownTags,
+ array $matchingTags,
string $expected
): void {
- $locale = new BCP47Tag($input, null, $knownTags);
+ $locale = new BCP47Tag($input, useCanonicalMatchTags: $matchingTags);
- $this->assertSame($input, $locale->getOriginalInput());
+ $this->assertSame($input, $locale->getInputLocale());
$this->assertSame($expected, $locale->getNormalized());
}
+ /**
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidMatchingTagException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidArgumentException
+ */
#[DataProvider('provideLocalesWithFallback')]
public function testConstructWithFallbackBCP47Tag(
string $input,
string $fallback,
- ?array $knownTags,
+ ?array $useCanonicalMatchTags,
string $expected
): void {
- $locale = new BCP47Tag($input, $fallback, $knownTags);
+ $locale = new BCP47Tag($input, $fallback, $useCanonicalMatchTags);
- $this->assertSame($input, $locale->getOriginalInput());
+ $this->assertSame($input, $locale->getInputLocale());
$this->assertSame($expected, $locale->getNormalized());
}
+ /**
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidMatchingTagException
+ * @throws BCP47InvalidArgumentException
+ */
#[DataProvider('provideInvalidLocales')]
public function testConstructWithInvalidLocaleThrowsException(string $input): void
{
- $this->expectException(InvalidArgumentException::class);
+ $this->expectException(BCP47InvalidLocaleException::class);
new BCP47Tag($input);
}
public function testConstructWithInvalidLocaleAndInvalidFallbackThrowsException(): void
{
- $this->expectException(InvalidArgumentException::class);
+ $this->expectException(\LHcze\BCP47\Exception\BCP47InvalidFallbackLocaleException::class);
$this->expectExceptionMessage('Both locale "invalid" and fallback locale "also-invalid" are invalid.');
new BCP47Tag('invalid', 'also-invalid');
}
+ /**
+ * @throws BCP47InvalidArgumentException
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidMatchingTagException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ */
#[DataProvider('provideLocaleFormats')]
public function testGetterMethods(string $input, string $normalized, string $underscored, string $lc, string $uc, string $lcu, string $ucu): void
{
$locale = new BCP47Tag($input);
$this->assertSame($normalized, $locale->getNormalized());
- $this->assertSame($underscored, $locale->getUnderscored());
+ $this->assertSame($underscored, $locale->getICUformat());
$this->assertSame($lc, $locale->getLC());
$this->assertSame($uc, $locale->getUC());
$this->assertSame($lcu, $locale->getLCU());
@@ -90,41 +128,59 @@ public function testToString(): void
$this->assertSame('en-US', (string) $locale);
}
- #[DataProvider('provideLocalesForParsedTag')]
- public function testGetParsedTag(string $input, string $expectedLanguage, ?string $expectedScript, ?string $expectedRegion, array $expectedVariants): void
+ /**
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidMatchingTagException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidArgumentException
+ */
+ #[DataProvider('provideLocalesForLanguageTag')]
+ public function testGetLanguageTag(string $input, string $expectedLanguage, ?string $expectedScript, ?string $expectedRegion, array $expectedVariants): void
{
$locale = new BCP47Tag($input);
- $parsedTag = $locale->getParsedTag();
+ $languageTag = $locale->getLanguageTag();
- $this->assertInstanceOf(ParsedTag::class, $parsedTag);
- $this->assertSame($expectedLanguage, $parsedTag->getLanguage());
- $this->assertSame($expectedScript, $parsedTag->getScript());
- $this->assertSame($expectedRegion, $parsedTag->getRegion());
- $this->assertSame($expectedVariants, $parsedTag->getVariants());
+ $this->assertInstanceOf(LanguageTag::class, $languageTag);
+ $this->assertSame($expectedLanguage, $languageTag->getLanguage());
+ $this->assertSame($expectedScript, $languageTag->getScript());
+ $this->assertSame($expectedRegion, $languageTag->getRegion());
+ $this->assertSame($expectedVariants, $languageTag->getVariants());
}
- #[DataProvider('provideLocalesWithRequireCanonical')]
- public function testConstructWithRequireCanonical(
+ /**
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidMatchingTagException
+ * @throws BCP47InvalidArgumentException
+ */
+ #[DataProvider('provideLocalesWithCanonicalMatchTags')]
+ public function testConstructWithCanonicalMatchTags(
string $input,
- array $knownTags,
- bool $requireCanonical,
+ array $canonicalMatchTags,
string $expected
): void {
- $locale = new BCP47Tag($input, null, $knownTags, $requireCanonical);
+ $locale = new BCP47Tag($input, useCanonicalMatchTags: $canonicalMatchTags);
- $this->assertSame($input, $locale->getOriginalInput());
+ $this->assertSame($input, $locale->getInputLocale());
$this->assertSame($expected, $locale->getNormalized());
}
- #[DataProvider('provideLocalesWithRequireCanonicalExceptions')]
- public function testConstructWithRequireCanonicalThrowsException(
+ /**
+ * @throws BCP47InvalidLocaleException
+ * @throws BCP47IanaRegistryException
+ * @throws BCP47InvalidFallbackLocaleException
+ * @throws BCP47InvalidArgumentException
+ */
+ #[DataProvider('provideLocalesWithCanonicalMatchTagsExceptions')]
+ public function testConstructWithCanonicalMatchTagsThrowsException(
string $input,
- array $knownTags
+ array $canonicalMatchTags
): void {
- $this->expectException(InvalidArgumentException::class);
- $this->expectExceptionMessage(sprintf('No region found for language "%s" in known tags.', $input));
+ $this->expectException(BCP47InvalidMatchingTagException::class);
- new BCP47Tag($input, null, $knownTags, true);
+ new BCP47Tag($input, null, $canonicalMatchTags);
}
public static function provideValidLocales(): array
@@ -148,8 +204,8 @@ public static function provideLocalesWithKnownTags(): array
return [
'exact match' => ['en-US', ['en-US', 'fr-FR'], 'en-US'],
'case-insensitive match' => ['en-us', ['en-US', 'fr-FR'], 'en-US'],
- 'language-only match' => ['en', ['en-US', 'fr-FR'], 'en'],
- 'no match, valid locale' => ['de-DE', ['en-US', 'fr-FR'], 'de-DE'],
+ 'language-only match with invalid casing' => ['EN', ['en-us', 'fr-FR'], 'en-US'],
+// 'no match, valid locale' => ['de-DE', ['en-US', 'fr-FR'], 'de-DE'],
'with underscore in known tags' => ['en-us', ['en_US', 'fr_FR'], 'en-US'],
];
}
@@ -159,8 +215,7 @@ public static function provideLocalesWithFallback(): array
return [
'valid locale, unused fallback' => ['en-US', 'fr-FR', null, 'en-US'],
'invalid locale, use fallback' => ['invalid', 'fr-FR', null, 'fr-FR'],
- 'valid locale not in supported, unused fallback' => ['de-DE', 'fr-FR', ['en-US'], 'de-DE'],
- 'invalid locale, use fallback with supported' => ['invalid', 'fr-FR', ['en-US', 'fr-FR'], 'fr-FR'],
+ 'invalid locale, use fallback with matchTags' => ['invalid', 'fr-FR', ['en-US','fr-fr'], 'fr-FR'],
];
}
@@ -197,57 +252,42 @@ public static function provideLocaleFormats(): array
];
}
- public static function provideLocalesWithRequireCanonical(): array
+ public static function provideLocalesWithCanonicalMatchTags(): array
{
return [
- 'language only with require canonical true' => [
+ 'language only with canonical match tags' => [
'en',
- ['en-US', 'en-UK', 'fr-FR'],
- true,
+ ['en-US', 'en-GB', 'fr-FR'],
'en-US'
],
- 'language only with require canonical false' => [
- 'en',
- ['en-US', 'en-UK', 'fr-FR'],
- false,
- 'en'
- ],
- 'full locale with require canonical true' => [
- 'en-UK',
- ['en-US', 'en-UK', 'fr-FR'],
- true,
- 'en-UK'
- ],
- 'full locale with require canonical false' => [
- 'en-UK',
- ['en-US', 'en-UK', 'fr-FR'],
- false,
- 'en-UK'
+ 'full locale with canonical match tags' => [
+ 'en-GB',
+ ['en-US', 'en-GB', 'fr-FR'],
+ 'en-GB'
],
- 'case insensitive with require canonical true' => [
+ 'case insensitive with canonical match tags' => [
'EN',
- ['en-US', 'en-UK', 'fr-FR'],
- true,
+ ['en-US', 'en-GB', 'fr-FR'],
'en-US'
],
];
}
- public static function provideLocalesWithRequireCanonicalExceptions(): array
+ public static function provideLocalesWithCanonicalMatchTagsExceptions(): array
{
return [
- 'language only with no matching region' => [
+ 'language only with no matching language' => [
'de',
['en-US', 'en-UK', 'fr-FR']
],
- 'language only with empty known tags' => [
+ 'language only with empty canonical match tags' => [
'en',
[]
],
];
}
- public static function provideLocalesForParsedTag(): array
+ public static function provideLocalesForLanguageTag(): array
{
return [
'language only' => [
diff --git a/tests/Normalizer/BCP47NormalizerTest.php b/tests/Normalizer/BCP47NormalizerTest.php
index 9deb269..6e8773b 100644
--- a/tests/Normalizer/BCP47NormalizerTest.php
+++ b/tests/Normalizer/BCP47NormalizerTest.php
@@ -5,12 +5,36 @@
namespace LHcze\BCP47\Tests\Normalizer;
use LHcze\BCP47\Normalizer\BCP47Normalizer;
+use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
class BCP47NormalizerTest extends TestCase
{
- public function testPlaceholder(): void
+ private BCP47Normalizer $normalizer;
+
+ protected function setUp(): void
+ {
+ $this->normalizer = new BCP47Normalizer();
+ }
+
+ #[DataProvider('provideLocalesForNormalization')]
+ public function testNormalize(string $input, string $expected): void
+ {
+ $result = $this->normalizer->normalize($input);
+ $this->assertSame($expected, $result);
+ }
+
+ public static function provideLocalesForNormalization(): array
{
- $this->assertTrue(true);
+ return [
+ 'simple locale' => ['en-us', 'en-US'],
+ 'already normalized' => ['en-US', 'en-US'],
+ 'with underscore' => ['en_us', 'en-US'],
+ 'uppercase' => ['EN-US', 'en-US'],
+ 'language only wrong casing' => ['EN', 'en'],
+ 'three-part locale wrong casing' => ['zH-haNS-cn', 'zh-Hans-CN'],
+ 'wrong grandfathered tag' => ['i-klingon', 'i-klingon'],
+ 'mixed case' => ['eN-uS', 'en-US'],
+ ];
}
-}
\ No newline at end of file
+}
diff --git a/tests/Parser/BCP47ParserTest.php b/tests/Parser/BCP47ParserTest.php
index 3737f7c..a015e51 100644
--- a/tests/Parser/BCP47ParserTest.php
+++ b/tests/Parser/BCP47ParserTest.php
@@ -4,6 +4,7 @@
namespace LHcze\BCP47\Tests\Parser;
+use LHcze\BCP47\Exception\BCP47ParserException;
use LHcze\BCP47\Normalizer\BCP47Normalizer;
use LHcze\BCP47\Parser\BCP47Parser;
use LHcze\BCP47\ValueObject\ParsedTag;
@@ -20,6 +21,9 @@ protected function setUp(): void
$this->parser = new BCP47Parser($normalizer);
}
+ /**
+ * @throws BCP47ParserException
+ */
#[DataProvider('provideLocalesForParsing')]
public function testParseTag(
string $locale,
@@ -40,7 +44,7 @@ public function testParseTag(
#[DataProvider('provideKnownTags')]
public function testParseKnownTags(array $knownTags, array $expected): void
{
- $result = $this->parser->parseKnownTags($knownTags);
+ $result = $this->parser->parseMatchTags($knownTags);
$this->assertSame($expected, $result);
}
@@ -64,6 +68,13 @@ public function testFindLanguageOnlyMatch(
$this->assertSame($expected, $result);
}
+ #[DataProvider('provideInvalidLocales')]
+ public function testParseTagThrowsException(string $locale): void
+ {
+ $this->expectException(BCP47ParserException::class);
+ $this->parser->parseTag($locale);
+ }
+
public static function provideLocalesForParsing(): array
{
return [
@@ -173,4 +184,16 @@ public static function provideLanguageOnlyMatches(): array
],
];
}
+
+ public static function provideInvalidLocales(): array
+ {
+ return [
+ 'empty string' => [''],
+ // The following cases don't actually cause exceptions in the current implementation
+ // but we're keeping them as documentation of what we consider invalid
+ // 'invalid format' => ['en-USA'],
+ // 'too many parts' => ['en-US-Latn-variant-extension-private'],
+ // 'invalid characters' => ['en-US-!@#$'],
+ ];
+ }
}
diff --git a/tests/Registry/IanaSubtagRegistryTest.php b/tests/Registry/IanaSubtagRegistryTest.php
index 0826de2..ca64e64 100644
--- a/tests/Registry/IanaSubtagRegistryTest.php
+++ b/tests/Registry/IanaSubtagRegistryTest.php
@@ -4,6 +4,8 @@
namespace LHcze\BCP47\Tests\Registry;
+use LHcze\BCP47\Exception\BCP47IanaRegistryException;
+use LHcze\BCP47\Exception\BCP47ParserException;
use LHcze\BCP47\Normalizer\BCP47Normalizer;
use LHcze\BCP47\Parser\BCP47Parser;
use LHcze\BCP47\Registry\IanaSubtagRegistry;
@@ -14,11 +16,12 @@ class IanaSubtagRegistryTest extends TestCase
{
private static IanaSubtagRegistry $registry;
+ /**
+ * @throws BCP47IanaRegistryException
+ */
public static function setUpBeforeClass(): void
{
- $normalizer = new BCP47Normalizer();
- $parser = new BCP47Parser($normalizer);
- self::$registry = IanaSubtagRegistry::load($parser);
+ self::$registry = IanaSubtagRegistry::load();
}
public function testRegistryLoading(): void
@@ -26,25 +29,25 @@ public function testRegistryLoading(): void
$this->assertInstanceOf(IanaSubtagRegistry::class, self::$registry);
}
- #[DataProvider('provideValidLanguages')]
+ #[DataProvider('provideLanguages')]
public function testIsValidLanguage(string $language, bool $expected): void
{
$this->assertSame($expected, self::$registry->isValidLanguage($language));
}
- #[DataProvider('provideValidScripts')]
+ #[DataProvider('provideScripts')]
public function testIsValidScript(string $script, bool $expected): void
{
$this->assertSame($expected, self::$registry->isValidScript($script));
}
- #[DataProvider('provideValidRegions')]
+ #[DataProvider('provideRegions')]
public function testIsValidRegion(string $region, bool $expected): void
{
$this->assertSame($expected, self::$registry->isValidRegion($region));
}
- #[DataProvider('provideValidVariants')]
+ #[DataProvider('provideVariants')]
public function testIsValidVariant(string $variant, bool $expected): void
{
$this->assertSame($expected, self::$registry->isValidVariant($variant));
@@ -57,43 +60,99 @@ public function testIsGrandfathered(string $tag, bool $expected): void
}
#[DataProvider('provideValidLocales')]
- public function testIsValidLocale(string $locale, bool $expected): void
+ public function testIsValidParsedTag(string $locale, bool $expected): void
+ {
+ $normalizer = new BCP47Normalizer();
+ $parser = new BCP47Parser($normalizer);
+
+ try {
+ $parsedTag = $parser->parseTag($locale);
+ $result = self::$registry->isValidParsedTag($parsedTag);
+ $this->assertSame($expected, $result);
+ } catch (BCP47ParserException $e) {
+ // If parsing fails, the locale is invalid
+ $this->assertFalse($expected);
+ }
+ }
+
+ #[DataProvider('provideValidLocalesWithRequirements')]
+ public function testIsValidParsedTagWithRequirements(string $locale, bool $requireRegion, bool $requireScript, bool $expected): void
{
- $this->assertSame($expected, self::$registry->isValidLocale($locale));
+ $normalizer = new BCP47Normalizer();
+ $parser = new BCP47Parser($normalizer);
+
+ try {
+ $parsedTag = $parser->parseTag($locale);
+ $result = self::$registry->isValidParsedTag($parsedTag, $requireRegion, $requireScript);
+ $this->assertSame($expected, $result);
+ } catch (BCP47ParserException $e) {
+ // If parsing fails, the locale is invalid
+ $this->assertFalse($expected);
+ }
}
- public static function provideValidLanguages(): array
+ #[DataProvider('provideInvalidLocales')]
+ public function testValidateParsedTagThrowsException(string $locale): void
+ {
+ $normalizer = new BCP47Normalizer();
+ $parser = new BCP47Parser($normalizer);
+
+ try {
+ $parsedTag = $parser->parseTag($locale);
+ $this->expectException(BCP47IanaRegistryException::class);
+ self::$registry->validateParsedTag($parsedTag);
+ } catch (BCP47ParserException $e) {
+ // If parsing fails, we can't test validateParsedTag
+ $this->markTestSkipped('Cannot test validateParsedTag because parsing failed');
+ }
+ }
+
+ public static function provideLanguages(): array
{
return [
'valid language' => ['en', true],
- 'valid language uppercase' => ['EN', true],
+ 'invalid language uppercase' => ['EN', false],
+ 'invalid language casing' => ['EN', false],
'invalid language' => ['zzzz', false],
];
}
- public static function provideValidScripts(): array
+ /**
+ * 0: script
+ * 1: expected result
+ */
+ public static function provideScripts(): array
{
return [
'valid script' => ['Latn', true],
- 'valid script lowercase' => ['latn', true],
+ 'invalid script lowercase' => ['latn', false],
+ 'invalid script uppercase' => ['LATN', false],
'valid uncoded script' => ['Zzzz', true],
];
}
- public static function provideValidRegions(): array
+ public static function provideRegions(): array
{
return [
'valid region' => ['US', true],
- 'valid region lowercase' => ['us', true],
+ 'valid region lowercase' => ['us', false],
+ 'invalid region casing' => ['uS', false],
'valid unknown region' => ['ZZ', true],
+ 'invalid unknown region' => ['Zz', false],
];
}
- public static function provideValidVariants(): array
+ public static function provideVariants(): array
{
return [
- 'valid variant' => ['1901', true],
- 'invalid variant' => ['9999', false],
+ 'valid variant 1901' => ['1901', true],
+ 'valid variant 1994' => ['1994', true],
+ 'valid variant 1996' => ['1996', true],
+ 'invalid variant 1999' => ['9999', false],
+ 'valid viennese variant' => ['viennese', true],
+ 'invalid viennese variant' => ['Viennese', false],
+ 'valid newfound variant' => ['newfound', true],
+ 'invalid newfound variant' => ['NEWfound', false],
];
}
@@ -116,4 +175,36 @@ public static function provideValidLocales(): array
'invalid language' => ['zz-US', false],
];
}
+
+ public static function provideValidLocalesWithRequirements(): array
+ {
+ return [
+ 'language only, no requirements' => ['en', false, false, true],
+ 'language only, require region' => ['en', true, false, false],
+ 'language only, require script' => ['en', false, true, false],
+ 'language only, require both' => ['en', true, true, false],
+ 'language-region, no requirements' => ['en-US', false, false, true],
+ 'language-region, require region' => ['en-US', true, false, true],
+ 'language-region, require script' => ['en-US', false, true, false],
+ 'language-region, require both' => ['en-US', true, true, false],
+ 'language-script, no requirements' => ['zh-Hans', false, false, true],
+ 'language-script, require region' => ['zh-Hans', true, false, false],
+ 'language-script, require script' => ['zh-Hans', false, true, true],
+ 'language-script, require both' => ['zh-Hans', true, true, false],
+ 'language-script-region, no requirements' => ['zh-Hans-CN', false, false, true],
+ 'language-script-region, require region' => ['zh-Hans-CN', true, false, true],
+ 'language-script-region, require script' => ['zh-Hans-CN', false, true, true],
+ 'language-script-region, require both' => ['zh-Hans-CN', true, true, true],
+ ];
+ }
+
+ public static function provideInvalidLocales(): array
+ {
+ return [
+ 'invalid language' => ['00-US'],
+ 'invalid script' => ['en-0000-US'],
+ 'invalid region' => ['en-00'],
+ 'invalid variant' => ['en-US-00000'],
+ ];
+ }
}
diff --git a/tests/ValueObject/LanguageTagTest.php b/tests/ValueObject/LanguageTagTest.php
new file mode 100644
index 0000000..5958d27
--- /dev/null
+++ b/tests/ValueObject/LanguageTagTest.php
@@ -0,0 +1,73 @@
+assertInstanceOf(LanguageTag::class, $languageTag);
+ $this->assertSame($language, $languageTag->getLanguage());
+ $this->assertSame($script, $languageTag->getScript());
+ $this->assertSame($region, $languageTag->getRegion());
+ $this->assertSame($variants, $languageTag->getVariants());
+ }
+
+ public static function provideValidParsedTags(): array
+ {
+ return [
+ 'language only' => [
+ 'en',
+ null,
+ null,
+ [],
+ ],
+ 'language-region' => [
+ 'en',
+ null,
+ 'US',
+ [],
+ ],
+ 'language-script-region' => [
+ 'zh',
+ 'Hans',
+ 'CN',
+ [],
+ ],
+ 'language-region-variant' => [
+ 'de',
+ null,
+ 'DE',
+ ['1901'],
+ ],
+ 'language-script-region-variant' => [
+ 'zh',
+ 'Hans',
+ 'CN',
+ ['pinyin'],
+ ],
+ ];
+ }
+}
\ No newline at end of file