From 2b84c34f41d583ae234bfe7181dd55c96c9008b9 Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Wed, 14 Oct 2026 08:32:36 +0000 Subject: [PATCH] Add region-key manifest (build:region-keys) + public/region-keys.json (v0.19 P1 of #16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deterministic -<4char> key per sub-region: name via NFKD strip + fold table (ə ø ð đ œ ł) + a-z0-9 collapse; 4-char from FNV-1a of the stable feature id, salted on within-slug collision so all 1,796 keys are unique. Builtins only (no @turf). Idempotent (byte-identical on re-run). --- package.json | 1 + public/region-keys.json | 1798 +++++++++++++++++++++++++++++++++ scripts/build-region-keys.mjs | 158 +++ 3 files changed, 1957 insertions(+) create mode 100644 public/region-keys.json create mode 100644 scripts/build-region-keys.mjs diff --git a/package.json b/package.json index 25bbe35..7589e5f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "cleanup:regions": "node scripts/cleanup-regions.mjs", "smooth:regions": "node scripts/smooth-regions.mjs", "fill:regions": "node scripts/fill-gaps.mjs", + "build:region-keys": "node scripts/build-region-keys.mjs", "typecheck": "tsc --noEmit", "lint": "eslint .", "e2e": "playwright test" diff --git a/public/region-keys.json b/public/region-keys.json new file mode 100644 index 0000000..aa388ff --- /dev/null +++ b/public/region-keys.json @@ -0,0 +1,1798 @@ +{ + "AF-BAL": "balkh-ckka", + "AF-BAM": "bamyan-mjkz", + "AF-BDG": "badghis-werz", + "AF-BDS": "badakhshan-qjrt", + "AF-BGL": "baghlan-wqdr", + "AF-FRA": "farah-dajq", + "AF-FYB": "faryab-ztoh", + "AF-GHA": "ghazni-nnab", + "AF-GHO": "ghor-bxar", + "AF-HEL": "hilmand-gmdm", + "AF-HER": "hirat-yddg", + "AF-JOW": "jawzjan-ibdk", + "AF-KAB": "kabul-agcw", + "AF-KAN": "kandahar-cacs", + "AF-NIM": "nimroz-eoll", + "AF-NUR": "nuristan-ofkf", + "AF-PIA": "paktika-wbrf", + "AF-PKA": "paktya-opvd", + "AF-SAM": "samangan-iybb", + "AF-SAR": "sari-pul-eubi", + "AF-TAK": "takhar-tbah", + "AF-URU": "uruzgan-ebhn", + "AF-URU-2": "uruzgan-unxj", + "AF-WAR": "wardak-wpjg", + "AF-ZAB": "zabul-ftpc", + "AO-BGO": "bengo-awxb", + "AO-BGU": "benguela-ifxx", + "AO-BIE": "bie-usov", + "AO-CCU": "cuando-cubango-sifc", + "AO-CNN": "cunene-etup", + "AO-CNO": "cuanza-norte-avuq", + "AO-CUS": "cuanza-sul-uays", + "AO-HUA": "huambo-czeb", + "AO-HUI": "huila-ylej", + "CO-HUI": "huila-appk", + "AO-LNO": "lunda-norte-kkid", + "AO-LSU": "lunda-sul-iyot", + "AO-MAL": "malanje-quaz", + "AO-MOX": "moxico-ievb", + "AO-NAM": "namibe-mitv", + "AO-UIG": "uige-alyd", + "AO-ZAI": "zaire-ikgg", + "AL-03": "elbasan-bjpz", + "AL-10": "shkoder-gmnr", + "AE-AZ": "abu-dhabi-mywn", + "AE-DU": "dubay-kskv", + "AR-A": "salta-uunu", + "AR-B": "buenos-aires-mwnv", + "AR-D": "san-luis-amnp", + "AR-E": "entre-rios-wonq", + "AR-F": "la-rioja-opnr", + "ES-LO": "la-rioja-anut", + "AR-G": "santiago-del-estero-grns", + "AR-H": "chaco-yfnb", + "AR-J": "san-juan-iind", + "DO-22": "san-juan-iczh", + "AR-K": "catamarca-ekne", + "AR-L": "la-pampa-aznx", + "AR-M": "mendoza-sany", + "AR-N": "misiones-ocnz", + "AR-P": "formosa-ctnd", + "AR-Q": "neuquen-yvne", + "AR-R": "rio-negro-qxnf", + "AR-S": "santa-fe-iyng", + "AR-T": "tucuman-ennz", + "AR-U": "chubut-apna", + "AR-V": "tierra-del-fuego-sqnb", + "AR-W": "corrientes-ksnc", + "AR-X": "cordoba-cgnl", + "CO-COR": "cordoba-srwy", + "ES-CO": "cordoba-mxza", + "AR-Y": "jujuy-yinm", + "AR-Z": "santa-cruz-mjnn", + "BO-S": "santa-cruz-kptg", + "AM-GR": "gegharkunik-qezd", + "AM-LO": "lori-aqmn", + "AQ-X01~": "antarctica-mvxe", + "AQ-X02~": "antarctica-ccbf", + "TF-X01~": "archipel-des-kerguelen-fnmd", + "TF-X1~": "iles-saint-paul-et-nouvelle-amsterdam-smio", + "TF-X02~": "archipel-des-crozet-oypb", + "TF-X03~": "iles-eparses-de-l-ocean-indien-zmrd", + "AU-NSW": "new-south-wales-guah", + "AU-NSW-2": "lord-howe-island-krnq", + "AU-NT": "northern-territory-ylns", + "AU-QLD": "queensland-opqa", + "AU-SA": "south-australia-cutu", + "AU-TAS": "tasmania-kptu", + "AU-VIC": "victoria-svnw", + "AU-WA": "western-australia-sxjw", + "AU-X03~": "macquarie-island-yijx", + "AT-2": "karnten-cypo", + "AT-3": "niederosterreich-uapp", + "AT-4": "oberosterreich-mbpq", + "AT-6": "steiermark-afps", + "AT-7": "tirol-sgpt", + "AZ-AGC": "agcabadi-yazh", + "AZ-KAL": "kalbacar-zzbg", + "AZ-QBA": "quba-nxpp", + "BI-BR": "bururi-uaba", + "BI-RY": "ruyigi-kdjc", + "BE-VOV": "east-flanders-cicp", + "BE-WLX": "luxembourg-krjs", + "BJ-AK": "atakora-oobn", + "BJ-AL": "alibori-smbm", + "BJ-BO": "borgou-yqft", + "BJ-CO": "collines-qzhd", + "BJ-DO": "donga-geqd", + "BJ-ZO": "zou-qmpu", + "BF-BAZ": "bazega-ufdx", + "BF-BLG": "boulgou-oyva", + "BF-COM": "komoe-siqa", + "BF-GNA": "gnagna-qjxm", + "BF-GOU": "gourma-okzn", + "BF-HOU": "houet-yrsy", + "BF-KEN": "kenedougou-yxcn", + "BF-KMP": "kompienga-wuin", + "BF-MOU": "mou-houn-azqo", + "BF-OUD": "oudalan-ooyt", + "BF-PON": "poni-upoo", + "BF-SIS": "sissili-amog", + "BF-SMT": "sanmatenga-alfl", + "BF-SNG": "sanguie-skxs", + "BF-SOM": "soum-whaq", + "BF-TAP": "tapoa-gpat", + "BF-TUI": "tuy-updk", + "BF-YAT": "yatenga-ajue", + "BD-B": "chittagong-bxry", + "BD-C": "dhaka-gvrx", + "BD-D": "khulna-purw", + "BD-E": "rajshahi-usrv", + "BD-F": "rangpur-drru", + "BD-G": "sylhet-iprt", + "BG-02": "burgas-nowy", + "BG-04": "veliko-tarnovo-zews", + "BG-06": "vratsa-lhwu", + "BG-16": "plovdiv-euus", + "BG-23": "sofia-corh", + "MG-M-2": "sofia-kmae", + "BG-24": "stara-zagora-hmrg", + "BG-27": "shumen-ahrd", + "BS-AK": "acklins-qehg", + "BS-BI": "bimini-sdjg", + "BS-BY": "berry-islands-wejq", + "BS-CI": "cat-island-kqms", + "BS-EX": "exuma-raxf", + "BS-IN": "inagua-ttnr", + "BS-MG": "mayaguana-kkei", + "BS-NE": "north-eleuthera-nwgq", + "BS-NS": "north-andros-dagc", + "BS-RI": "ragged-island-fprn", + "BS-SS": "san-salvador-kzur", + "BA-BIH-3": "west-bosnia-ayyu", + "BA-BIH-6": "zenica-doboj-kqyp", + "BA-X02~": "banja-luka-qguu", + "BY-BR": "brest-uhpa", + "BY-HO": "gomel-evel", + "BY-HR": "grodno-sbey", + "BY-MA": "mogilev-srqt", + "BY-MI": "minsk-sirf", + "BY-VI": "vitebsk-anmn", + "BZ-CY": "cayo-ejvk", + "BO-B": "el-beni-aptp", + "BO-C": "cochabamba-oqtq", + "BO-H": "chuquisaca-mztf", + "BO-L": "la-paz-kftj", + "BO-N": "pando-uitl", + "BO-O": "oruro-qktm", + "BO-P": "potosi-iltd", + "BO-T": "tarija-grth", + "BR-AC": "acre-ekzw", + "BR-AL": "alagoas-ivzd", + "BR-AM": "amazonas-qtzc", + "CO-AMA": "amazonas-isdt", + "PE-AMA": "amazonas-nthu", + "VE-Z": "amazonas-qfqs", + "BR-AP": "amapa-gozp", + "BR-BA": "bahia-gncm", + "BR-CE": "ceara-wceu", + "BR-ES": "espirito-santo-yopi", + "BR-GO": "goias-suuo", + "BR-MA": "maranhao-ojve", + "BR-MG": "minas-gerais-ymvg", + "BR-MS": "mato-grosso-do-sul-wfvs", + "BR-MT": "mato-grosso-aqvz", + "BR-PA": "para-mmiu", + "SR-PR": "para-scsi", + "BR-PB": "paraiba-aniv", + "BR-PE": "pernambuco-kfiq", + "BR-PI": "piaui-icjc", + "BR-PR": "parana-arjl", + "BR-RJ": "rio-de-janeiro-mhoj", + "BR-RN": "rio-grande-do-norte-knon", + "BR-RO": "rondonia-gpoo", + "BR-RR": "roraima-itoh", + "BR-RS": "rio-grande-do-sul-auoi", + "BR-SC": "santa-catarina-ourg", + "BR-SE": "sergipe-glra", + "BR-SP": "sao-paulo-eurp", + "BR-TO": "tocantins-kczu", + "BN-BE": "belait-asmw", + "BT-15": "thimphu-agoq", + "BT-24": "wangdi-phodrang-ipqp", + "BW-CE": "central-ypdw", + "KE-200": "central-sqzo", + "PG-CPM": "central-cczg", + "ZM-02": "central-svtv", + "BW-GH": "ghanzi-oamb", + "BW-KG": "kgalagadi-gaxy", + "BW-KW": "kweneng-kxwi", + "BW-NW": "north-west-qhdz", + "ZA-NW": "north-west-ispe", + "BW-SO": "southern-ctpk", + "SL-S": "southern-ncas", + "ZM-07": "southern-orts", + "CF-AC": "ouham-mnot", + "CF-BB": "bamingui-bangoran-ilrg", + "CF-BK": "basse-kotto-earz", + "CF-HK": "haute-kotto-ymrh", + "CF-HM": "haut-mbomou-qdrb", + "CF-HS": "mambere-kadei-carz", + "CF-KB": "nana-grebizi-mcza", + "CF-KG": "kemo-uuzv", + "CF-LB": "lobaye-uriq", + "CF-MB": "mbomou-ydky", + "CF-MP": "ombella-m-poko-iklq", + "CF-NM": "nana-mambere-glnv", + "CF-OP": "ouham-pende-obpq", + "CF-SE": "sangha-mbaere-mqfz", + "CF-UK": "ouaka-mmrt", + "CF-VK": "vakaga-ahth", + "CA-AB": "alberta-zopq", + "CA-BC": "british-columbia-vmsh", + "CA-MB": "manitoba-thmy", + "CA-NB": "new-brunswick-wcni", + "CA-NL": "newfoundland-and-labrador-kmno", + "CA-NS": "nova-scotia-ndnz", + "CA-NT": "northwest-territories-gynw", + "CA-NU": "nunavut-banx", + "CA-ON": "ontario-bzqu", + "CA-QC": "quebec-yegk", + "CA-SK": "saskatchewan-cmli", + "CA-YT": "yukon-hsje", + "CH-BE": "bern-pmiz", + "CH-ZH": "zurich-kdpk", + "CL-AI": "aisen-del-general-carlos-ibanez-del-campo-mrpn", + "CL-AN": "antofagasta-czps", + "CL-AP": "arica-y-parinacota-mbpk", + "CL-AR": "la-araucania-aepm", + "CL-AT": "atacama-khpo", + "CL-BI": "bio-bio-kfrw", + "CL-CO": "coquimbo-qtuj", + "CL-LI": "libertador-general-bernardo-o-higgins-ghiu", + "CL-LL": "los-lagos-mmix", + "CL-LR": "los-rios-gxix", + "EC-R": "los-rios-mouz", + "CL-MA": "magallanes-y-antartica-chilena-eqmb", + "CL-ML": "maule-kvme", + "CL-NB": "nuble-wmop", + "CL-RM": "region-metropolitana-de-santiago-qwdi", + "CL-TA": "tarapaca-mrpq", + "CL-VS": "valparaiso-mfuk", + "CN-AH": "anhui-sanz", + "CN-BJ": "beijing-qsqi", + "CN-CQ": "chongqing-mcsc", + "CN-FJ": "fujian-gmhk", + "CN-GD": "guangdong-eajt", + "CN-GS": "gansu-exjm", + "CN-GX": "guangxi-cgjb", + "CN-GZ": "guizhou-qjjd", + "CN-HA": "henan-qdfb", + "CN-HB": "hubei-eefc", + "CN-HE": "hebei-owfx", + "CN-HI": "hainan-mpfj", + "CN-HL": "heilongjiang-shfe", + "CN-HN": "hunan-gkfg", + "CN-JL": "jilin-akky", + "CN-JS": "jiangsu-kpkl", + "CN-JX": "jiangxi-geke", + "CN-LN": "liaoning-wswa", + "CN-NM": "inner-mongol-ioap", + "CN-NX": "ningxia-kwbm", + "CN-QH": "qinghai-cnbf", + "CN-SC": "sichuan-eufy", + "CN-SD": "shandong-ajfr", + "CN-SN": "shaanxi-kyfb", + "CN-SX": "shanxi-ubft", + "CN-TJ": "tianjin-krnw", + "CN-X01~": "paracel-islands-yftc", + "CN-XJ": "xinjiang-oasq", + "CN-XZ": "xizang-kzsk", + "CN-YN": "yunnan-mbuv", + "CN-ZJ": "zhejiang-amww", + "CI-01": "lagunes-igqk", + "CI-02": "haut-sassandra-aiql", + "CI-03": "savanes-sjqm", + "CI-04": "vallee-du-bandama-oyqf", + "CI-06": "dix-huit-montagnes-gcqh", + "CI-08": "zanzan-qsqb", + "CI-09": "bas-sassandra-muqc", + "CI-10": "denguele-ycsk", + "CI-11": "n-zi-comoe-uesl", + "CI-14": "worodougou-wiso", + "CI-15": "sud-bandama-sksp", + "CI-16": "agneby-glsq", + "CI-19": "cavally-qqst", + "CM-AD": "adamaoua-kqsc", + "CM-CE": "centre-aexz", + "TG-C": "centre-kurt", + "CM-EN": "extreme-nord-oubi", + "CM-ES": "est-umbd", + "CM-LT": "littoral-oyts", + "CM-NO": "nord-gkzb", + "NC-X03~": "nord-wofd", + "CM-NW": "nord-ouest-yvzz", + "CM-OU": "ouest-kdbx", + "HT-OU": "ouest-wjof", + "CM-SU": "sud-mukj", + "CM-SW": "sud-ouest-yxkl", + "CD-BC": "bas-congo-yhcf", + "CD-BN": "bandundu-gzcq", + "CD-EQ": "equateur-mkpe", + "CD-KA": "katanga-igym", + "CD-KE": "kasai-oriental-gzyi", + "CD-KN": "kinshasa-city-aoyb", + "CD-KW": "kasai-occidental-udyu", + "CD-MA": "maniema-eoks", + "CD-NK": "nord-kivu-gxmp", + "CD-OR": "orientale-scpz", + "CD-SK": "sud-kivu-katu", + "CG-2": "lekoumou-inqi", + "CG-5": "kouilou-qfqd", + "CG-7": "likouala-aiqf", + "CG-8": "cuvette-wtpy", + "CG-9": "niari-svpz", + "CG-11": "bouenza-elwk", + "CG-12": "pool-umwl", + "CG-13": "sangha-oowm", + "CG-14": "plateaux-kqwn", + "TG-P": "plateaux-myrm", + "CG-15": "cuvette-ouest-crwo", + "CO-ANT": "antioquia-kqan", + "CO-ARA": "arauca-yxsw", + "CO-BOL": "bolivar-shkq", + "VE-F": "bolivar-oyqe", + "CO-BOY": "boyaca-uekx", + "CO-CAL": "caldas-wkha", + "CO-CAQ": "caqueta-qfhx", + "CO-CAS": "casanare-aihz", + "CO-CAU": "cauca-szht", + "CO-CES": "cesar-qcua", + "CO-CHO": "choco-qaew", + "CO-CUN-2": "cundinamarca-ieom", + "CO-GUA": "guainia-utmi", + "CO-GUV": "guaviare-spmp", + "CO-LAG": "la-guajira-utww", + "CO-MAG": "magdalena-wrsg", + "CO-MET": "meta-ymbx", + "CO-NAR": "narino-osue", + "CO-NSA": "norte-de-santander-svgs", + "CO-PUT": "putumayo-ksux", + "CO-SAN": "santander-mmat", + "CO-SAP": "san-andres-y-providencia-sbat", + "CO-SUC": "sucre-glea", + "VE-R": "sucre-qsqk", + "CO-TOL": "tolima-gone", + "CO-VAC": "valle-del-cauca-urfx", + "CO-VAU": "vaupes-ihfh", + "CO-VID": "vichada-oozm", + "CO-X01~": "colombia-weor", + "CR-A": "alajuela-vwmk", + "CR-G": "guanacaste-ffmq", + "CR-L": "limon-ynmv", + "CR-P": "puntarenas-evmt", + "CU-01": "pinar-del-rio-ejbc", + "CU-04": "matanzas-kobf", + "CU-05": "villa-clara-cpbg", + "CU-07": "sancti-spiritus-msbi", + "CU-09": "camaguey-ewbu", + "CU-12": "granma-yeei", + "CU-13": "santiago-de-cuba-qfej", + "-99-X04~": "northern-cyprus-mvnb", + "CY-01": "nicosia-gzli", + "CZ-MO": "moravskoslezsky-sbcc", + "CZ-PL": "plzensky-ysxk", + "CZ-ST": "stredocesky-ihft", + "CZ-VY": "vysocina-kamr", + "DE-BB": "brandenburg-yrjj", + "DE-BW": "baden-wurttemberg-oyje", + "DE-BY": "bayern-aiju", + "DE-HE": "hessen-bqlm", + "DE-MV": "mecklenburg-vorpommern-pqcp", + "DE-NI": "niedersachsen-vxfc", + "DE-NW": "nordrhein-westfalen-hafe", + "DE-RP": "rheinland-pfalz-cfwr", + "DE-SH": "schleswig-holstein-gmaj", + "DE-SN": "sachsen-oiah", + "DE-ST": "sachsen-anhalt-arad", + "DE-TH": "thuringen-mxiz", + "DJ-DI": "dikhil-zrvh", + "DJ-TA": "tadjourah-jsgf", + "DK-82": "midtjylland-gjbs", + "DK-83": "syddanmark-ykbt", + "DO-11": "la-altagracia-iexf", + "DZ-01": "adrar-ctwy", + "MR-07": "adrar-dffe", + "DZ-03": "laghouat-mwwa", + "DZ-05": "batna-enwu", + "DZ-07": "biskra-oqww", + "DZ-08": "bechar-kfwp", + "DZ-11": "tamanghasset-mozx", + "DZ-12": "tebessa-iqzy", + "DZ-14": "tiaret-stza", + "DZ-17": "djelfa-uxzd", + "DZ-19": "setif-mbzf", + "DZ-21": "skikda-odba", + "DZ-22": "sidi-bel-abbes-kfbb", + "DZ-26": "medea-elbf", + "DZ-28": "m-sila-sobh", + "DZ-30": "ouargla-wxdg", + "DZ-32": "el-bayadh-gadi", + "DZ-33": "illizi-ccdj", + "DZ-37": "tindouf-ewdf", + "DZ-39": "el-oued-oldp", + "DZ-40": "khenchela-yomx", + "DZ-41": "souk-ahras-uqmy", + "DZ-45": "naama-swmc", + "DZ-47": "ghardaia-czme", + "DZ-48": "relizane-ybmf", + "EC-A": "azuay-kruk", + "EC-D": "orellana-cmuh", + "EC-E": "esmeraldas-ikug", + "EC-G": "guayas-whue", + "EC-L": "loja-czuz", + "EC-M": "manabi-myuy", + "EC-P": "pichincha-wrub", + "EC-S": "morona-santiago-unuy", + "EC-T": "tungurahua-ylux", + "EC-U": "sucumbios-ejuw", + "EC-W": "galapagos-sguu", + "EC-Y": "pastaza-gdus", + "EC-Z": "zamora-chinchipe-qcur", + "EG-ASN": "aswan-sxuz", + "EG-BA": "al-bahr-al-ahmar-oaom", + "EG-BH": "al-buhayrah-ilnf", + "EG-FYM": "al-fayyum-wdgf", + "EG-GZ": "al-jizah-abuz", + "EG-JS": "janub-sina-mrqx", + "EG-MN": "al-minya-mjfl", + "EG-MT": "matruh-cafp", + "EG-SHR": "ash-sharqiyah-wcnm", + "SA-04": "ash-sharqiyah-qlqi", + "EG-SIN": "shamal-sina-uhqn", + "EG-WAD": "al-wadi-at-jadid-spvg", + "ER-DK": "debubawi-keyih-bahri-jrxo", + "ER-DU": "debub-rtxk", + "ER-GB": "gash-barka-coeg", + "ER-MA": "maekel-litf", + "ER-SK": "semenawi-keyih-bahri-comw", + "ES-AB": "albacete-attf", + "ES-B": "barcelona-iybx", + "ES-BA": "badajoz-ciwt", + "ES-BU": "burgos-asxn", + "ES-CA": "cadiz-aazc", + "ES-CC": "caceres-kdze", + "ES-CR": "ciudad-real-adzn", + "ES-CU": "cuenca-chzq", + "ES-GC": "las-palmas-ujic", + "ES-GR": "granada-yhir", + "ES-GU": "guadalajara-izim", + "ES-H": "huelva-qhbd", + "ES-HU": "huesca-ihkb", + "ES-J": "jaen-ekbf", + "ES-L": "lerida-onbh", + "ES-LE": "leon-uyuj", + "NI-LE": "leon-gvhg", + "ES-LU": "lugo-qbvz", + "ES-M": "madrid-kpbi", + "ES-ML": "melilla-uuxv", + "ES-MU": "murcia-qjxo", + "ES-O": "asturias-usbk", + "ES-OR": "orense-aqch", + "ES-P": "palencia-qubl", + "ES-PM": "baleares-ayfx", + "ES-SA": "salamanca-qrmw", + "ES-SE": "sevilla-oxma", + "ES-SO": "soria-comu", + "ES-TE": "teruel-ofof", + "ES-TF": "santa-cruz-de-tenerife-ggog", + "ES-TO": "toledo-yvoz", + "ES-V": "valencia-ydbr", + "ES-Z": "zaragoza-ajbv", + "ES-ZA": "zamora-qhdj", + "EE-37": "harju-qnwd", + "EE-44": "ida-viru-ictd", + "EE-78": "tartu-aymq", + "ET-AF": "afar-cnlj", + "ET-AM": "amhara-kylq", + "ET-BE": "benshangul-gumaz-iznr", + "ET-GA": "gambela-peoples-sggc", + "ET-OR": "oromiya-otzl", + "ET-SN": "southern-nations-nationalities-and-peoples-ohez", + "ET-SO": "somali-eiea", + "ET-TI": "tigray-ucnt", + "FI-03": "southern-ostrobothnia-ihkk", + "FI-04": "southern-savonia-ewkd", + "FI-05": "kainuu-ayke", + "FI-08": "central-finland-cpkp", + "FI-10": "lapland-gcno", + "FI-11": "pirkanmaa-cenp", + "FI-13": "north-karelia-mhnr", + "FI-14": "northern-ostrobothnia-eins", + "FI-15": "northern-savonia-aknt", + "FI-16": "paijat-hame-olnu", + "FI-18": "uusimaa-gpng", + "FJ-R": "rotuma-kdui", + "FJ-W": "western-alun", + "GH-WP": "western-qwvr", + "PG-WPD": "western-adsp", + "RW-04": "western-mygs", + "SB-CH": "western-afoi", + "ZM-01": "western-cutu", + "FK-X01~": "falkland-islands-ubzb", + "FR-01": "ain-lqtt", + "FR-02": "aisne-gstu", + "FR-2B": "haute-corse-gmyy", + "FR-03": "allier-butv", + "FR-04": "alpes-de-haute-provence-svtw", + "FR-07": "ardeche-zatz", + "FR-11": "aude-pmva", + "FR-12": "aveyron-kovb", + "FR-15": "cantal-rgvw", + "FR-17": "charente-maritime-djvy", + "FR-18": "cher-yyvr", + "FR-21": "cote-d-or-zhyz", + "FR-22": "cotes-d-armor-qiya", + "FR-23": "creuse-lkyb", + "FR-25": "doubs-xnyd", + "FR-27": "eure-jqyf", + "FR-30": "gard-guab", + "FR-31": "haute-garonne-bwac", + "FR-32": "gers-wyad", + "FR-33": "gironde-nzae", + "FR-38": "isere-ghaj", + "FR-40": "landes-kudi", + "FR-41": "loir-et-cher-fwdj", + "FR-44": "loire-atlantique-mode", + "FR-47": "lot-et-garonne-psdh", + "FR-51": "marne-hpgs", + "FR-57": "moselle-rygy", + "FR-61": "orne-jeiv", + "FR-62": "pas-de-calais-egiw", + "FR-72": "sarthe-ebkd", + "FR-73": "savoie-zdke", + "FR-77": "seien-et-marne-bxka", + "FR-80": "somme-sgzc", + "FR-85": "vendee-lozh", + "FR-86": "vienne-cpzi", + "FR-88": "vosges-oszk", + "FR-89": "yonne-juzl", + "FR-GF": "guyane-francaise-gmcw", + "FR-GP": "guadeloupe-wqci", + "FR-MQ": "martinique-tuau", + "FR-RE": "la-reunion-voeo", + "FR-YT": "mayotte-gthm", + "GA-1": "estuaire-qawm", + "GA-2": "haut-ogooue-kcwn", + "GA-3": "moyen-ogooue-eewo", + "GA-4": "ngounie-atwh", + "GA-5": "nyanga-suwi", + "GA-6": "ogooue-ivindo-mwwj", + "GA-7": "ogooue-lolo-cxwk", + "GA-8": "ogooue-maritime-ulwt", + "GA-9": "wouleu-ntem-qnwu", + "GB-ABD": "aberdeenshire-kzrn", + "GB-CAM": "cambridgeshire-fwds", + "GB-CMA": "cumbria-oohy", + "GB-DEV": "devon-slaz", + "GB-DGY": "dumfries-and-galloway-sres", + "GB-HLD": "highland-saxg", + "GB-IOS": "isles-of-scilly-oznv", + "GB-LIN": "lincolnshire-odkr", + "GB-NYK": "north-yorkshire-qalk", + "GB-OMH": "omagh-gocy", + "GB-OXF": "oxfordshire-qxcr", + "GB-POW": "powys-zcfq", + "GB-SFK": "suffolk-peqe", + "GB-SHR": "shropshire-mhvl", + "GB-SOM": "somerset-drhz", + "GB-ZET": "shetland-islands-ypae", + "GE-IM": "imereti-vlst", + "GE-KA": "kakheti-lswd", + "GE-MM": "mtskheta-mtianeti-dbcb", + "GE-SZ": "samegrelo-zemo-svaneti-wjlp", + "GH-AH": "ashanti-abux", + "GH-BA": "brong-ahafo-qqwr", + "GH-EP": "eastern-irer", + "KE-400": "eastern-qapp", + "RW-02": "eastern-avgq", + "SL-E": "eastern-dtaw", + "ZM-03": "eastern-mxtw", + "GH-NP": "northern-ibne", + "PG-NPP": "northern-swud", + "SD-NO": "northern-qinm", + "SL-N": "northern-yiap", + "ZM-05": "northern-eotq", + "GH-TV": "volta-ihni", + "GH-UW": "upper-west-avqy", + "GN-BE": "beyla-vyfv", + "GN-BK": "boke-jifl", + "GN-DI": "dinguiraye-vqqn", + "GN-FA": "faranah-lbvx", + "GN-GA": "gaoual-jpxg", + "GN-K": "kankan-kmei", + "GN-KD": "kindia-gbod", + "GN-KO": "kouroussa-jsoo", + "GN-KS": "kissidougou-hloa", + "GN-MD": "mandiana-alzh", + "GN-ML": "mali-ayzp", + "GN-MM": "mamou-rzzq", + "GN-PI": "pita-rhov", + "GN-SI": "siguiri-juvq", + "GN-TE": "telimele-jadt", + "GN-YO": "yomou-dhxs", + "GM-M": "central-river-qqfp", + "GW-BA": "bafata-krfg", + "GW-OI": "oio-eyrz", + "GQ-AN": "annobon-eedl", + "GQ-BS": "bioko-sur-yvgu", + "GQ-CS": "centro-sur-gwiq", + "GR-A": "anatoliki-makedonia-kai-thraki-abyd", + "GR-B": "kentriki-makedonia-wdye", + "GR-C": "dytiki-makedonia-keyf", + "GR-E": "thessalia-yhyh", + "GR-G": "dytiki-ellada-mlyj", + "GR-H": "sterea-ellada-inyu", + "GR-J": "peloponnisos-wqyw", + "GL-KU": "kommune-kujalleq-nbjz", + "GL-QA": "qaasuitsup-kommunia-kawz", + "GL-QE": "qeqqata-kommunia-mhwd", + "GL-SM": "kommuneqarfik-sermersooq-eqcb", + "GL-UO": "nationalparken-menh", + "GT-AV": "alta-verapaz-myed", + "GT-BV": "baja-verapaz-ongg", + "GT-HU": "huehuetenango-mjgd", + "GT-JU": "jutiapa-wdml", + "GT-PE": "peten-kent", + "GT-SM": "san-marcos-cvvw", + "GY-BA": "barima-waini-wifs", + "GY-MA": "mahaica-berbice-igzl", + "GY-PM": "pomeroon-supenaam-iooq", + "GY-PT": "potaro-siparuni-qaor", + "GY-UD": "upper-demerara-berbice-ynhw", + "GY-UT": "upper-takutu-upper-essequibo-cohg", + "HN-CM": "comayagua-gvxb", + "HN-EP": "el-paraiso-gxia", + "HN-GD": "gracias-a-dios-kumu", + "HN-OL": "olancho-qasq", + "HN-SB": "santa-barbara-qgiw", + "HN-YO": "yoro-chgi", + "HR-01": "zagrebacka-cijs", + "HR-09": "licko-senjska-cvjk", + "HR-13": "zadarska-mglb", + "HR-14": "osjecko-baranjska-ivlu", + "HT-AR": "l-artibonite-egma", + "HU-BE": "bekes-itph", + "HU-BK": "bacs-kiskun-udpx", + "HU-HB": "hajdu-bihar-edea", + "HU-PE": "pest-akxn", + "HU-SO": "somogy-ymes", + "HU-VE": "veszprem-czmj", + "ID-AC": "aceh-ocsz", + "ID-BB": "bangka-belitung-ixwo", + "ID-BE": "bengkulu-qwwn", + "ID-BT": "banten-stwc", + "ID-GO": "gorontalo-gihp", + "ID-JA": "jambi-sxbt", + "ID-JB": "jawa-barat-msbq", + "ID-JI": "jawa-timur-skbb", + "ID-JT": "jawa-tengah-eqby", + "ID-KB": "kalimantan-barat-qpei", + "ID-KI": "kalimantan-timur-kxex", + "ID-KS": "kalimantan-selatan-smex", + "ID-KT": "kalimantan-tengah-area", + "ID-LA": "lampung-yjht", + "ID-MA": "maluku-qzjd", + "ID-MU": "maluku-utara-osjp", + "ID-NB": "nusa-tenggara-barat-ywlq", + "ID-NT": "nusa-tenggara-timur-iflm", + "ID-PA": "papua-rydx", + "ID-PB": "papua-barat-mady", + "ID-RI": "riau-zdhp", + "ID-SA": "sulawesi-utara-ojkh", + "ID-SB": "sumatera-barat-vokk", + "ID-SG": "sulawesi-tenggara-ctkn", + "ID-SN": "sulawesi-selatan-thkw", + "ID-SR": "sulawesi-barat-zpku", + "ID-SS": "sumatera-selatan-enkt", + "ID-ST": "sulawesi-tengah-lskw", + "ID-SU": "sumatera-utara-qqkv", + "IN-AN": "andaman-and-nicobar-stzm", + "IN-AP": "andhra-pradesh-amam", + "IN-AR": "arunachal-pradesh-mpao", + "IN-AS": "assam-dqap", + "IN-BR": "bihar-cbcp", + "IN-CT": "chhattisgarh-yiee", + "IN-GJ": "gujarat-sooi", + "IN-HP": "himachal-pradesh-ggdz", + "IN-HR": "haryana-wkdb", + "IN-JH": "jharkhand-qjit", + "IN-JK": "jammu-and-kashmir-vhis", + "IN-KA": "karnataka-rslx", + "IN-KL": "kerala-clls", + "IN-LA": "ladakh-ppmi", + "IN-MH": "maharashtra-qypg", + "IN-ML": "meghalaya-oepk", + "IN-MN": "manipur-ahpm", + "IN-MP": "madhya-pradesh-qlpo", + "IN-MZ": "mizoram-yapy", + "IN-NL": "nagaland-yvrv", + "IN-OR": "odisha-uxvk", + "IN-PB": "punjab-kjkb", + "PK-PB": "punjab-ghlp", + "IN-RJ": "rajasthan-sfpr", + "IN-TG": "telangana-mfvw", + "IN-TN": "tamil-nadu-sqvd", + "IN-TR": "tripura-ylvj", + "IN-UP": "uttar-pradesh-aaxe", + "IN-UT": "uttarakhand-ygxi", + "IN-WB": "west-bengal-isbk", + "IE-CO": "cork-qnps", + "IE-G": "galway-kjar", + "IE-RN": "roscommon-ytzq", + "IE-WX": "wexford-iasb", + "IR-01": "east-azarbaijan-qxil", + "IR-02": "west-azarbaijan-eyim", + "IR-03": "ardebil-aain", + "IR-04": "esfahan-wpig", + "IR-05": "ilam-oqih", + "IR-06": "bushehr-ksii", + "IR-07": "tehran-ytij", + "IR-08": "chahar-mahall-and-bakhtiari-uiis", + "IR-10": "khuzestan-yrkr", + "IR-11": "zanjan-qsks", + "IR-12": "semnan-mukt", + "IR-13": "sistan-and-baluchestan-avku", + "IR-14": "fars-wxkv", + "IR-15": "kerman-oykw", + "IR-16": "kordestan-gakx", + "IR-17": "kermanshah-ccky", + "IR-18": "kohgiluyeh-and-buyer-ahmad-yekj", + "IR-19": "gilan-ugkk", + "IR-20": "lorestan-ydnw", + "IR-21": "mazandaran-ufnx", + "IR-22": "markazi-qhny", + "IR-23": "hormozgan-einz", + "IR-24": "hamadan-akna", + "IR-25": "yazd-slnb", + "IR-26": "qom-knnc", + "IR-27": "golestan-cond", + "IR-28": "qazvin-crno", + "IR-29": "south-khorasan-usnp", + "IR-30": "razavi-khorasan-cdqd", + "IR-31": "north-khorasan-yfqe", + "IQ-AN": "al-anbar-yjqa", + "IQ-AR": "arbil-sbqc", + "IQ-BA": "al-basrah-lrsw", + "IQ-BB": "babil-emst", + "IQ-DI": "diyala-pzxe", + "IQ-DQ": "dhi-qar-pmxm", + "IQ-MA": "maysan-rzfn", + "IQ-MU": "al-muthannia-pffh", + "IQ-NA": "an-najaf-buiy", + "IQ-NI": "ninawa-bhig", + "IQ-SD": "sala-ad-din-simf", + "IQ-SU": "as-sulaymaniyah-fimw", + "IQ-TS": "at-ta-mim-xbob", + "IQ-WA": "wasit-vawa", + "IS-3": "vesturland-ajfn", + "IS-5": "nordurland-vestra-safh", + "IS-6": "nordurland-eystra-kbfi", + "IS-7": "austurland-cdfj", + "IS-8": "sudurland-ysfc", + "IL-D": "hadarom-uves", + "IT-AL": "alessandria-shfc", + "IT-AO": "aoste-ymff", + "IT-BA": "bari-gtie", + "SO-BR": "bari-sedg", + "IT-BL": "belluno-iojp", + "IT-BO": "bologna-otjs", + "IT-BS": "brescia-mzjw", + "IT-BZ": "bozen-ukjd", + "IT-CB": "campobasso-wmlo", + "IT-CS": "cosenza-oolz", + "IT-CT": "catania-kqla", + "IT-FI": "firenze-sksq", + "IT-GR": "grosseto-gtuw", + "IT-PA": "palermo-cprw", + "IT-PG": "perugia-ozrc", + "IT-PR": "parma-uqrn", + "IT-PZ": "potenza-yerf", + "IT-RM": "roma-sawi", + "IT-SS": "sassari-aeyz", + "IT-TO": "turin-yfaa", + "JM-13": "clarendon-muxv", + "JO-AM": "amman-avrc", + "JO-MA": "mafraq-invm", + "JO-MN": "ma-an-lrvp", + "JP-01": "hokkaido-ksfx", + "JP-03": "iwate-uvfz", + "JP-05": "akita-mmft", + "JP-06": "yamagata-gofu", + "JP-07": "fukushima-wpfv", + "JP-08": "ibaraki-odfe", + "JP-09": "tochigi-kfff", + "JP-15": "niigata-idhx", + "JP-19": "yamanashi-gwhj", + "JP-20": "nagano-kfji", + "JP-21": "gifu-agjj", + "JP-22": "shizuoka-ycjg", + "JP-24": "mie-iljm", + "JP-28": "hyogo-ksja", + "JP-33": "okayama-mymn", + "JP-34": "hiroshima-tqmi", + "JP-39": "kochi-aimd", + "JP-40": "fukuoka-ylvc", + "JP-44": "oita-asvg", + "JP-45": "miyazaki-stvh", + "JP-47": "okinawa-cwvj", + "KZ-AKM": "aqmola-etpx", + "KZ-AKT": "aqtobe-sgpw", + "KZ-ALA": "almaty-waxb", + "KZ-ATY": "atyrau-ixli", + "KZ-KAR": "qaraghandy-khxs", + "KZ-KUS": "qostanay-qwtp", + "KZ-KZY": "qyzylorda-emfx", + "KZ-MAN": "mangghystau-ooqu", + "KZ-PAV": "pavlodar-abzq", + "KZ-SEV": "north-kazakhstan-kdzy", + "KZ-VOS": "east-kazakhstan-ipgz", + "KZ-YUZ": "south-kazakhstan-qtgc", + "KZ-ZAP": "west-kazakhstan-aqxa", + "KZ-ZHA": "zhambyl-qhpv", + "KE-300": "coast-kjrv", + "KE-500": "north-eastern-ewzp", + "KE-600": "nyanza-wpnv", + "KE-700": "rift-valley-wlpc", + "KG-B": "batken-cbll", + "KG-C": "chuy-xdlm", + "KG-J": "jalal-abad-colt", + "KG-N": "naryn-eilp", + "KG-O": "osh-vjlq", + "KG-T": "talas-orlv", + "KG-Y": "ysyk-kol-hqmi", + "KH-2": "batdambang-jett", + "KH-5": "kampong-spoe-gatq", + "KH-6": "kampong-thum-lytp", + "KH-9": "kaoh-kong-astc", + "KH-10": "kracheh-suom", + "KH-11": "mondol-kiri-jvon", + "KH-13": "preah-vihear-xsol", + "KH-14": "prey-veng-qaoq", + "KH-15": "pouthisat-lcor", + "KH-16": "rotanokiri-exoo", + "KH-17": "siemreab-vyop", + "KH-19": "stoeng-treng-jiov", + "KR-41": "gyeonggi-asoh", + "KR-42": "gangwon-uuoi", + "KR-43": "north-chungcheong-kvoj", + "KR-46": "south-jeolla-wooe", + "KR-47": "north-gyeongsang-mpof", + "KR-48": "south-gyeongsang-edoo", + "KR-49": "jeju-afop", + "XK-X19~": "podujevo-ozes", + "KW-JA": "al-jahrah-cvgx", + "LA-AT": "attapu-cxyj", + "LA-BL": "bolikhamxai-csag", + "LA-CH": "champasak-agcn", + "LA-HO": "houaphan-lmpf", + "LA-KH": "khammouan-qmwz", + "LA-LM": "louang-namtha-fbyj", + "LA-LP": "louangphrabang-quyo", + "LA-OU": "oudomxai-trgc", + "LA-PH": "phongsali-okhy", + "LA-SV": "savannakhet-ulpr", + "LA-VI-2": "vientiane-qhaq", + "LA-XA": "xaignabouri-hdan", + "LA-XI": "xiangkhoang-hqaf", + "LB-BI": "beqaa-ryfc", + "LR-CM": "grand-cape-mount-acht", + "LR-GB": "grand-bassa-vzwu", + "LR-GG": "grand-gedeh-cewx", + "LR-NI": "nimba-xaov", + "LR-X1~": "gbapolu-iigq", + "LR-X2~": "river-gee-uqio", + "LY-AJ": "ajdabiya-ikqv", + "LY-BU": "al-butnan-gytn", + "LY-GD": "ghadamis-aagv", + "LY-GT": "ghat-ebgf", + "LY-JU": "al-jufrah-mrvm", + "LY-KF": "al-kufrah-ehbh", + "LY-MI": "misratah-cbhm", + "LY-MJ": "al-marj-ydhn", + "LY-MQ": "murzuq-cohu", + "LY-MZ": "mizdah-uchd", + "LY-NQ": "an-nuqat-al-khams-ehkx", + "LY-QB": "al-qubbah-wlez", + "LY-SB": "sabha-sukt", + "LY-SR": "surt-otkn", + "LY-WD": "wadi-al-hayaa-qrtp", + "LY-WS": "ash-shati-qbtm", + "LK-52": "ampara-oqcc", + "LK-71": "anuradhapura-jzhh", + "LK-82": "monaragala-wspd", + "LK-91": "ratnapura-llsf", + "LS-A": "maseru-quuq", + "LS-K": "thaba-tseka-wjua", + "LT-KL": "klaipedos-kooa", + "LT-KU": "kauno-keod", + "LT-PN": "panevezio-cpal", + "LU-D": "diekirch-kyaq", + "LV-033": "gulbene-gcky", + "LV-099": "tukums-qtmk", + "LV-REZ": "rezeknes-mmcq", + "LV-VEN": "ventspils-cuhk", + "MA-01": "tanger-tetouan-eqeu", + "MA-03": "taza-al-hoceima-taounate-otew", + "MA-04": "oriental-kiep", + "MA-05": "fes-boulemane-cjeq", + "MA-06": "meknes-tafilalet-yler", + "MA-09": "chaouia-ouardigha-edem", + "MA-10": "doukkala-abda-sghb", + "MA-11": "marrakech-tensift-al-haouz-weha", + "MA-12": "tadla-azilal-idhz", + "MA-13": "souss-massa-draa-mbhy", + "MA-14": "guelmim-es-semara-qzhx", + "MA-15": "laayoune-boujdour-sakia-el-hamra-cyhw", + "MA-16": "oued-el-dahab-gwhv", + "MD-CM": "cimislia-acda", + "MD-FA": "falesti-qcpf", + "MG-A": "analanjirofo-hgdp", + "MG-A-2": "atsinanana-uoeq", + "MG-A-3": "alaotra-mangoro-lper", + "MG-D": "diana-oydk", + "MG-D-2": "sava-atuj", + "MG-F": "vatovavy-fitovinany-abdm", + "MG-F-2": "atsimo-atsinanana-cjvi", + "MG-F-3": "amoron-i-mania-ulvj", + "MG-F-4": "ihorombe-mmvk", + "MG-F-5": "haute-matsiatra-iovl", + "MG-M": "boeny-fmdt", + "MG-M-3": "melaky-ynaf", + "MG-M-4": "betsiboka-upag", + "MG-T": "analamanga-szdu", + "MG-T-2": "bongolava-irjg", + "MG-T-3": "vakinankaratra-dtjh", + "MG-U": "anosy-jadv", + "MG-U-2": "androy-wzfq", + "MG-U-3": "atsimo-andrefana-qbfr", + "MG-U-4": "menabe-icfs", + "MX-BCN": "baja-california-rkil", + "MX-BCS": "baja-california-sur-uoie", + "MX-CAM": "campeche-qfna", + "MX-CHH": "chihuahua-imen", + "MX-CHP": "chiapas-izef", + "MX-COA": "coahuila-givi", + "MX-DUR": "durango-gnsc", + "MX-GRO": "guerrero-iroj", + "MX-GUA": "guanajuato-uvcd", + "MX-HID": "hidalgo-drfz", + "MX-JAL": "jalisco-kpbu", + "MX-MEX": "mexico-mpba", + "MX-X01~": "mexico-ewrz", + "MX-MIC": "michoacan-uekn", + "MX-NAY": "nayarit-chkm", + "MX-NLE": "nuevo-leon-rfly", + "MX-OAX": "oaxaca-vcjz", + "MX-PUE": "puebla-apfj", + "MX-QUE": "queretaro-mpre", + "MX-ROO": "quintana-roo-ieho", + "MX-SIN": "sinaloa-ahmy", + "MX-SLP": "san-luis-potosi-wfta", + "MX-SON": "sonora-otbs", + "MX-TAB": "tabasco-hhvb", + "MX-TAM": "tamaulipas-apvq", + "MX-VER": "veracruz-kuoh", + "MX-YUC": "yucatan-mpkz", + "MX-ZAC": "zacatecas-pbpt", + "MK-36": "kavadartsi-yiil", + "ML-1": "kayes-twwi", + "ML-2": "koulikoro-oywj", + "ML-3": "sikasso-fzwk", + "ML-4": "segou-aowd", + "ML-5": "mopti-vqwe", + "ML-6": "timbuktu-mrwf", + "ML-7": "gao-htwg", + "ML-8": "kidal-yhwp", + "MM-01": "sagaing-axrl", + "MM-02": "bago-uzrm", + "MM-03": "magway-karn", + "MM-04": "mandalay-gcro", + "MM-05": "tanintharyi-ydrp", + "MM-07": "ayeyarwady-mhrr", + "MM-11": "kachin-etts", + "MM-12": "kayah-uutt", + "MM-13": "kayin-owtu", + "MM-14": "chin-kltn", + "MM-15": "mon-cmto", + "MM-16": "rakhine-wotp", + "MM-17": "shan-qqtq", + "ME-12": "niksic-mcna", + "MN-039": "hentiy-kufs", + "MN-041": "hovsgol-munb", + "MN-043": "hovd-wxnd", + "MN-046": "uvs-ccng", + "MN-047": "tov-udnh", + "MN-049": "selenge-mhnj", + "MN-051": "suhbaatar-quqi", + "MN-053": "omnogovi-axqk", + "MN-055": "ovorhangay-onqe", + "MN-057": "dzavhan-yqqg", + "MN-059": "dundgovi-mgqq", + "MN-061": "dornod-qpsp", + "MN-063": "dornogovi-assr", + "MN-065": "govi-altay-ovst", + "MN-067": "bulgan-czsv", + "MN-069": "bayanhongor-udsh", + "MN-071": "bayan-olgiy-ucvu", + "MN-073": "arhangay-efvw", + "MZ-A": "niassa-eefk", + "MZ-B": "manica-wffl", + "MZ-G": "gaza-mnfq", + "MZ-I": "inhambane-aqfs", + "MZ-L": "maputo-gvfv", + "MZ-N": "nampula-qyfx", + "MZ-P": "cabo-delgado-mdft", + "MZ-Q": "zambezia-eefu", + "MZ-S": "sofala-ohfw", + "MZ-T": "tete-kjfx", + "MR-01": "hodh-ech-chargui-twfu", + "MR-02": "hodh-el-gharbi-oyfv", + "MR-03": "assaba-fzfa", + "MR-04": "gorgol-abfb", + "MR-05": "brakna-rcfc", + "MR-06": "trarza-mefd", + "MR-08": "dakhlet-nouadhibou-cifl", + "MR-09": "tagant-tjfm", + "MR-10": "guidimaka-cqhe", + "MR-11": "tiris-zemmour-xshf", + "MR-12": "inchiri-othg", + "MW-CK": "chikwawa-ulnn", + "MW-CT": "chitipa-qnno", + "MW-KS": "kasungu-scgl", + "MW-LI": "lilongwe-kdpi", + "MW-MG": "mangochi-qesd", + "MW-MH": "machinga-mtss", + "MW-MZ": "mzimba-svso", + "MW-NB": "nkhata-bay-sgvt", + "MY-01": "johor-omus", + "MY-02": "kedah-gout", + "MY-03": "kelantan-ypuu", + "MY-06": "pahang-ihup", + "MY-08": "perak-sxuz", + "MY-10": "selangor-wkxy", + "MY-11": "terengganu-smxz", + "MY-12": "sabah-knxa", + "MY-13": "sarawak-cpxb", + "NA-CA": "caprivi-yapw", + "NA-ER": "erongo-mmar", + "NA-HA": "hardap-qqnp", + "NA-KA": "karas-etva", + "NA-KH": "khomas-ievh", + "NA-KU": "kunene-cmvm", + "NA-OD": "otjozondjupa-yuld", + "NA-OH": "omaheke-ablr", + "NA-OK": "kavango-gglu", + "NA-OS": "omusati-gtlm", + "NA-OT": "oshikoto-cvln", + "NA-OW": "ohangwena-ialq", + "NE-1": "agadez-ijfb", + "NE-2": "diffa-akfc", + "NE-3": "dosso-smfd", + "NE-4": "maradi-knfe", + "NE-5": "tahoua-gpff", + "NE-6": "tillaberi-yrfg", + "NE-7": "zinder-qsfh", + "NG-AD": "adamawa-ehbv", + "NG-BA": "bauchi-spdb", + "NG-BE": "benue-uwdf", + "NG-BO": "borno-emdz", + "NG-CR": "cross-river-erfd", + "NG-DE": "delta-qnoh", + "NG-ED": "edo-utql", + "NG-EN": "enugu-ijqf", + "NG-GO": "gombe-ogwc", + "NG-JI": "jigawa-yzkn", + "NG-KD": "kaduna-aymn", + "NG-KE": "kebbi-wamo", + "NG-KN": "kano-oomx", + "NG-KO": "kogi-gqmy", + "NG-KT": "katsina-ezmx", + "NG-KW": "kwara-kema", + "NG-NA": "nassarawa-mrzh", + "NG-NI": "niger-qfzz", + "NG-OG": "ogun-soba", + "NG-ON": "ondo-aabr", + "NG-OS": "osun-qhbm", + "NG-OY": "oyo-ksbc", + "NG-PL": "plateau-oako", + "NG-RI": "rivers-esqx", + "NG-SO": "sokoto-mjsi", + "NG-TA": "taraba-cqbj", + "NG-YO": "yobe-sitq", + "NG-ZA": "zamfara-iavl", + "NI-AN": "atlantico-norte-ieag", + "NI-AS": "atlantico-sur-ylal", + "NI-CO": "chontales-uefv", + "NI-JI": "jinotega-yvws", + "NI-MT": "matagalpa-iykc", + "NL-BQ1": "bonaire-makp", + "NL-BQ2": "saba-gckq", + "NL-BQ3": "st-eustatius-wdkr", + "NL-GE": "gelderland-ygoe", + "NL-NH": "noord-holland-otrk", + "NO-02": "akershus-ityh", + "NO-04": "hedmark-akyb", + "NO-05": "oppland-slyc", + "NO-06": "buskerud-onyd", + "NO-08": "telemark-ceyx", + "NO-09": "aust-agder-ufyy", + "NO-12": "hordaland-yrai", + "NO-14": "sogn-og-fjordane-iuak", + "NO-15": "more-og-romsdal-aval", + "NO-16": "sor-trondelag-sxam", + "NO-17": "nord-trondelag-kyan", + "NO-18": "nordland-gaao", + "NO-19": "troms-ccap", + "NO-20": "finnmark-mdcj", + "NO-21": "svalbard-eeck", + "NO-X01~": "bouvet-island-vssk", + "NP-BA": "bagmati-ungl", + "NP-BH": "bheri-czgc", + "NP-GA": "gandaki-ohsw", + "NP-KA": "karnali-mbpa", + "NP-KO": "bhojpur-uxpy", + "NP-RA": "rapti-ewpq", + "NP-SA": "sagarmatha-otrd", + "NP-SE": "seti-qarh", + "NZ-BOP": "bay-of-plenty-wlsa", + "NZ-CAN": "canterbury-kxye", + "NZ-CIT": "chatham-islands-territory-svse", + "NZ-HKB": "hawke-s-bay-iunb", + "NZ-MBH": "marlborough-district-oyxs", + "NZ-MWT": "manawatu-wanganui-zrxu", + "NZ-NTL": "northland-aqhd", + "NZ-OTA": "otago-ctsh", + "NZ-STL": "southland-ukrs", + "NZ-WKO": "waikato-gxqe", + "NZ-WTC": "west-coast-ucji", + "NZ-X01~": "kermadec-islands-ocbs", + "NZ-X03~": "three-kings-islands-qafu", + "NZ-X04~": "antipodes-islands-ynit", + "NZ-X05~": "campbell-islands-ywks", + "NZ-X06~": "auckland-islands-ujmt", + "NZ-X07~": "the-snares-mvou", + "TK-X01~": "tokelau-cqiy", + "OM-BA": "al-batnah-north-ilnl", + "OM-DA": "ad-dakhliyah-qtih", + "OM-MU": "musandam-ubnu", + "OM-SH": "ash-sharqiyah-south-gkzv", + "OM-SS": "ash-sharqiyah-north-qdza", + "OM-WU": "al-wusta-mdok", + "OM-ZA": "al-dhahira-eqif", + "OM-ZU": "dhofar-gtht", + "PK-BA": "baluchistan-ihjh", + "PK-GB": "northern-areas-mevu", + "PK-JK": "azad-kashmir-ajpr", + "PK-KP": "k-p-stsm", + "PK-SD": "sind-atud", + "PK-TA": "f-a-t-a-yhan", + "PA-4": "chiriqui-mxiy", + "PA-5": "darien-iziz", + "PA-8": "panama-oriu", + "PA-9": "veraguas-gsiv", + "PE-ANC": "ancash-mtdg", + "PE-APU": "apurimac-aghq", + "PE-ARE": "arequipa-avbe", + "PE-AYA": "ayacucho-vhko", + "PE-CAJ": "cajamarca-mjjy", + "PE-CUS": "cusco-ypen", + "PE-HUC": "huanuco-uwqc", + "PE-HUV": "huancavelica-orqp", + "PE-ICA": "ica-hijd", + "PE-JUN": "junin-rnyf", + "PE-LAL": "la-libertad-sqmm", + "PE-LAM": "lambayeque-yoml", + "PE-LIM": "lima-iioy", + "PE-LOR": "loreto-ipkx", + "PE-MDD": "madre-de-dios-fpxm", + "PE-MOQ": "moquegua-xwwn", + "PE-PAS": "pasco-ydtb", + "PE-PIU": "piura-whve", + "PE-PUN": "puno-vaqi", + "PE-SAM": "san-martin-orum", + "PE-TAC": "tacna-uiaf", + "PE-UCA": "ucayali-hmry", + "PH-ABR": "abra-cmfg", + "PH-AGS": "agusan-del-sur-efza", + "PH-BTN": "batanes-orcp", + "PH-BUK": "bukidnon-faet", + "PH-CAG": "cagayan-sezc", + "PH-CAS": "camarines-sur-ulzq", + "PH-DAO": "davao-oriental-sxtc", + "PH-ILI": "iloilo-xbzy", + "PH-MDC": "mindoro-occidental-sjgh", + "PH-NCO-2": "cotabato-wzzy", + "PH-NEC": "negros-occidental-erlu", + "PH-NUE": "nueva-ecija-ilyq", + "PH-PAN": "pangasinan-cmhx", + "PH-PLW": "palawan-imjh", + "PH-QUE": "quezon-scfg", + "PH-SUK": "sultan-kudarat-pnsz", + "PH-TAW": "tawi-tawi-khxg", + "PH-WSA": "samar-vdxo", + "PH-ZAN": "zamboanga-del-norte-qvgj", + "PH-ZMB-2": "zambales-gjfs", + "PG-EBR": "east-new-britain-bphy", + "PG-EHG": "eastern-highlands-ohoa", + "PG-EPW": "enga-yfvk", + "PG-ESW": "east-sepik-azma", + "PG-GPK": "gulf-yenl", + "PG-MBA": "milne-bay-gubz", + "PG-MPL": "morobe-anuo", + "PG-MPM": "madang-elun", + "PG-MRL": "manus-oxpg", + "PG-NSB": "north-solomons-yvrf", + "PG-SAN": "sandaun-swut", + "PG-SHM": "southern-highlands-wdcq", + "PG-WBK": "west-new-britain-qila", + "PL-DS": "lower-silesian-eayz", + "PL-KP": "kuyavian-pomeranian-gfwe", + "PL-LB": "lubusz-wsem", + "PL-LD": "lodz-gveo", + "PL-LU": "lublin-gyez", + "PL-MA": "lesser-poland-ukhv", + "PL-MZ": "masovian-uuhs", + "PL-PD": "podlachian-amui", + "PL-PK": "subcarpathian-ajux", + "PL-PM": "pomeranian-saur", + "PL-SK": "swietokrzyskie-yobp", + "PL-SL": "silesian-igbk", + "PL-WN": "warmian-masurian-epsm", + "PL-WP": "greater-poland-ausi", + "PL-ZP": "west-pomeranian-mafy", + "US-PR": "puerto-rico-qqlt", + "KP-02": "p-yongan-namdo-uodu", + "KP-03": "p-yongan-bukto-ipdv", + "KP-04": "chagang-do-erdw", + "KP-06": "hwanghae-bukto-oudy", + "KP-07": "kangwon-do-kwdz", + "KP-08": "hamgyong-namdo-cxda", + "KP-09": "hamgyong-bukto-yzdb", + "KP-10": "ryanggang-ggfz", + "PT-02": "beja-ykgw", + "TN-31": "beja-yaie", + "PT-05": "castelo-branco-gcgr", + "PT-07": "evora-qfgt", + "PT-14": "santarem-sojz", + "PT-17": "vila-real-ytjc", + "PT-18": "viseu-uvjd", + "PT-20": "azores-ayly", + "PT-30": "madeira-croh", + "PY-1": "concepcion-vrml", + "PY-2": "san-pedro-qtmm", + "PY-5": "caaguazu-xlmh", + "PY-6": "caazapa-snmi", + "PY-7": "itapua-jomj", + "PY-9": "paraguari-vemt", + "PY-10": "alto-parana-mimn", + "PY-12": "neembucu-cfml", + "PY-13": "amambay-kemk", + "PY-14": "canindeyu-ocmj", + "PY-15": "presidente-hayes-abmi", + "PY-16": "alto-paraguay-ezmh", + "PY-19": "boqueron-uume", + "PS-GZZ": "gaza-strip-sazs", + "PS-WBK": "west-bank-cjlo", + "QA-RA": "ar-rayyan-ynlo", + "RO-AB": "alba-kbti", + "RO-AG": "arges-hxtf", + "RO-BC": "bacau-zdvy", + "RO-BZ": "buzau-ipvp", + "RO-CJ": "cluj-cgyo", + "RO-CT": "constanta-owyy", + "RO-DJ": "dolj-yaab", + "RO-GJ": "gorj-qeiw", + "RO-HR": "harghita-ybxj", + "RO-IS": "iasi-gzad", + "RO-MM": "maramures-iwjv", + "RO-MS": "mures-yhjv", + "RO-TM": "timis-seme", + "RO-TR": "teleorman-gcnr", + "RU-AL": "gorno-altay-cstw", + "RU-ALT": "altay-mfuq", + "RU-AMU": "amur-clbp", + "RU-ARK": "arkhangel-sk-lhbk", + "RU-AST": "astrakhan-anec", + "RU-BA": "bashkortostan-uovk", + "RU-BEL": "belgorod-wxjk", + "RU-BRY": "bryansk-hxom", + "RU-BU": "buryat-wvvy", + "RU-CE": "chechnya-qixv", + "RU-CHE": "chelyabinsk-qnxc", + "RU-CHU": "chukchi-autonomous-okrug-mmxs", + "RU-CU": "chuvash-mhxl", + "RU-DA": "dagestan-qfgq", + "RU-IRK": "irkutsk-wjtq", + "RU-IVA": "ivanovo-uneq", + "RU-KAM": "kamchatka-rncn", + "RU-KB": "kabardin-balkar-kgec", + "RU-KC": "karachay-cherkess-gied", + "RU-KDA": "krasnodar-nzpm", + "RU-KEM": "kemerovo-larh", + "RU-KGD": "kaliningrad-ihxa", + "RU-KGN": "kurgan-yyxu", + "RU-KHA": "khabarovsk-vetk", + "RU-KHM": "khanty-mansiy-tkto", + "RU-KIR": "kirov-gfvm", + "RU-KK": "khakass-cuel", + "RU-KL": "kalmyk-yjee", + "RU-KLU": "kaluga-fmjg", + "RU-KO": "komi-eoeh", + "RU-KOS": "kostroma-hmrp", + "RU-KR": "karelia-ohem", + "RU-KRS": "kursk-obra", + "RU-KYA": "krasnoyarsk-znif", + "RU-LEN": "leningrad-mknu", + "RU-LIP": "lipetsk-qvwo", + "RU-MAG": "maga-buryatdan-wvtk", + "RU-ME": "mariy-el-umod", + "RU-MO": "mordovia-abon", + "RU-MOW": "moskovskaya-chlr", + "RU-MUR": "murmansk-etas", + "RU-NEN": "nenets-qyga", + "RU-NGR": "novgorod-cvlo", + "RU-NIZ": "nizhegorod-clce", + "RU-NVS": "novosibirsk-mivi", + "RU-OMS": "omsk-aufy", + "RU-ORE": "orenburg-nkfp", + "RU-ORL": "orel-svfw", + "RU-PER": "perm-cphx", + "RU-PNZ": "penza-mzew", + "RU-PRI": "primor-ye-edix", + "RU-PSK": "pskov-kakm", + "RU-ROS": "rostov-ylrd", + "RU-RYA": "ryazan-ggrj", + "RU-SA": "sakha-yakutia-yxkf", + "RU-SAK": "sakhalin-wlzc", + "RU-SAM": "samara-koze", + "RU-SAR": "saratov-avzz", + "RU-SE": "north-ossetia-arkb", + "RU-SMO": "smolensk-qrwu", + "RU-STA": "stavropol-mizd", + "RU-SVE": "sverdlovsk-eefj", + "RU-TA": "tatarstan-aotw", + "RU-TAM": "tambov-evce", + "RU-TOM": "tomsk-gews", + "RU-TUL": "tula-cvuo", + "RU-TVE": "tver-qdaj", + "RU-TY": "tuva-ecty", + "RU-TYU": "tyumen-uppf", + "RU-UD": "udmurt-cave", + "RU-ULY": "ul-yanovsk-uovf", + "RU-VGG": "volgograd-omkg", + "RU-VLA": "vladimir-mqvt", + "RU-VLG": "vologda-ynvr", + "RU-VOR": "voronezh-svdp", + "RU-YAN": "yamal-nenets-aqsx", + "RU-YAR": "yaroslavl-cksd", + "RU-YEV": "yevrey-itcn", + "RU-ZAB": "chita-qxms", + "UA-43": "crimea-qsnu", + "EH-X01~": "western-sahara-gozf", + "SA-01": "ar-riyad-gsqn", + "SA-02": "makkah-yuqo", + "SA-03": "al-madinah-uwqp", + "SA-05": "al-quassim-imqj", + "SA-06": "ha-il-eoqk", + "SA-07": "tabuk-spql", + "SA-08": "al-hudud-ash-shamaliyah-kdqu", + "SA-09": "jizan-gfqv", + "SA-10": "najran-wlss", + "SA-11": "al-bahah-ajsr", + "SA-12": "al-jawf-misq", + "YE-JA": "al-jawf-wngz", + "SA-14": "asir-yfso", + "SD-DE": "central-darfur-wrpe", + "SD-DN": "north-darfur-mfpn", + "SD-DS": "southern-darfur-iopm", + "SD-DS-2": "eastern-darfur-kbbu", + "SD-DW": "western-darfur-kvpq", + "SD-GD": "gedarif-oxvo", + "SD-GZ": "gezira-chvu", + "SD-KA": "kassala-odzh", + "SD-KH": "khartoum-wpzy", + "SD-KN": "north-kordufan-kmzw", + "SD-KS": "south-kordufan-ygzz", + "SD-NB": "blue-nile-conz", + "SD-NR": "river-nile-gpnj", + "SD-NW": "white-nile-uwno", + "SD-RS": "red-sea-zspo", + "SD-SI": "sennar-dssz", + "SS-BN": "northern-bahr-el-ghazal-civj", + "SS-BW": "western-bahr-el-ghazal-uwvs", + "SS-EC": "central-equatoria-sogr", + "SS-EE": "eastern-equatoria-ilgp", + "SS-EW": "western-equatoria-yffx", + "SS-JG": "jonglei-setz", + "SS-LK": "lakes-uvxp", + "SS-NU": "upper-nile-kxdz", + "SS-UY": "unity-smuv", + "SS-WR": "warrap-kuzy", + "SN-FK": "fatick-kohi", + "SN-KA": "kaffrine-ufni", + "SN-KD": "kolda-oanf", + "SN-KE": "kedougou-syne", + "SN-LG": "louga-wgwg", + "SN-MT": "matam-qxzf", + "SN-SE": "sedhiou-qgha", + "SN-SL": "saint-louis-iuhj", + "SN-TC": "tambacounda-shqy", + "SN-TH": "thies-mpqd", + "SB-MK": "makira-qcnj", + "SB-RB": "rennell-and-bellona-amuo", + "SB-TE": "temotu-wpdk", + "SV-US": "usulutan-xbjc", + "-99-X11~": "somaliland-gapg", + "SO-BK": "bakool-grdf", + "SO-BY": "bay-uvdr", + "SO-GA": "galguduud-arwl", + "SO-GE": "gedo-yxwp", + "SO-HI": "hiiraan-knsf", + "SO-JD": "jubbada-dhexe-unxw", + "SO-JH": "jubbada-hoose-wuxk", + "SO-MU": "mudug-kpld", + "SO-NU": "nugaal-gznd", + "SO-SD": "shabeellaha-dhexe-ueua", + "SO-SH": "shabeellaha-hoose-sxum", + "RS-06": "juzno-backi-girr", + "RS-07": "sremski-xjrs", + "RS-11": "branicevski-nitf", + "RS-15": "zajecarski-lotj", + "RS-16": "zlatiborski-gqtk", + "SR-SI": "sipaliwini-lvya", + "SK-BC": "banskobystricky-iono", + "SK-NI": "nitriansky-muds", + "SK-PV": "presov-kpwz", + "SI-048": "kocevje-gyjj", + "SE-AC": "vasterbotten-ykth", + "SE-BD": "norrbotten-gqvp", + "SE-C": "uppsala-aeug", + "SE-D": "sodermanland-sfuh", + "SE-E": "ostergotland-ohui", + "SE-F": "jonkoping-eiuj", + "SE-G": "kronoberg-ykuk", + "SE-H": "kalmar-umuv", + "SE-I": "gotland-qouw", + "SE-M": "skane-ouua", + "SE-O": "vastra-gotaland-yxuc", + "SE-S": "varmland-aeuq", + "SE-W": "dalarna-cluu", + "SE-X": "gavleborg-ynuf", + "SE-Y": "vasternorrland-upug", + "SE-Z": "jamtland-kquh", + "SZ-LU": "lubombo-ybpl", + "SY-DY": "dayr-az-zawr-nthe", + "SY-HA": "hasaka-al-haksa-vlle", + "SY-HI": "homs-hims-vcmm", + "SY-HL": "aleppo-cqlh", + "SY-HM": "hamah-xsli", + "SY-ID": "idlib-yoou", + "SY-RA": "ar-raqqah-lhjy", + "SY-RD": "rif-dimashq-smjb", + "SY-SU": "as-suwayda-jzmr", + "TD-BA": "batha-dyem", + "TD-BG": "barh-el-gazel-nhes", + "TD-BO": "borkou-nuea", + "TD-CB": "chari-baguirmi-aeay", + "TD-GR": "guera-qyrk", + "TD-HL": "hadjer-lamis-avbt", + "TD-KA": "kanem-bhvv", + "TD-LC": "lac-rmsk", + "TD-LR": "logone-oriental-wotz", + "TD-MA": "mandoul-jypx", + "TD-MC": "moyen-chari-vbpz", + "TD-ME": "mayo-kebbi-est-hepb", + "TD-MO": "mayo-kebbi-ouest-tupl", + "TD-OD": "ouaddai-ukka", + "TD-SA": "salamat-nrnf", + "TD-SI": "sila-rfnx", + "TD-TA": "tandjile-trlq", + "TD-TI": "tibesti-teli", + "TD-WF": "wadi-fira-wtem", + "TD-X01~": "ennedi-sxtm", + "TG-K": "kara-khrl", + "TH-14": "phra-nakhon-si-ayutthaya-eddh", + "TH-24": "chachoengsao-uwfm", + "TH-27": "sa-kaeo-cufl", + "TH-30": "nakhon-ratchasima-kfip", + "TH-31": "buri-ram-ghiq", + "TH-34": "ubon-ratchathani-mzil", + "TH-36": "chaiyaphum-acin", + "TH-40": "khon-kaen-msqg", + "TH-41": "udon-thani-iuqh", + "TH-42": "loei-avqi", + "TH-45": "roi-et-gerl", + "TH-47": "sakon-nakhon-qhrn", + "TH-49": "mukdahan-ihqz", + "TH-50": "chiang-mai-qstn", + "TH-52": "lampang-avtp", + "TH-53": "uttaradit-swtq", + "TH-55": "nan-kntk", + "TH-57": "chiang-rai-uqtm", + "TH-58": "mae-hong-son-qftf", + "TH-60": "nakhon-sawan-ckvs", + "TH-61": "uthai-thani-ymvt", + "TH-63": "tak-ojvr", + "TH-65": "phitsanulok-agvp", + "TH-67": "phetchabun-mcvn", + "TH-71": "kanchanaburi-udyq", + "TH-76": "phetchaburi-klyv", + "TH-80": "nakhon-si-thammarat-utgo", + "TH-84": "surat-thani-wngk", + "TH-90": "songkhla-eojn", + "TH-95": "yala-ywjs", + "TJ-GB": "gorno-badakhshan-sgex", + "TJ-KT": "khatlon-qlhv", + "TJ-SU": "leninabad-dnbu", + "TJ-X01~": "tadzhikistan-territories-uxcw", + "TM-A": "ahal-weco", + "TM-B": "balkan-edcn", + "TM-D": "tashauz-mmct", + "TM-L": "chardzhou-mzcb", + "TM-M": "mary-qxca", + "TL-OE": "ambeno-kpna", + "TL-VI": "viqueque-wkyr", + "TT-RCM": "rio-claro-mayaro-ojxf", + "TT-WTO": "western-tobago-lmvd", + "TN-33": "le-kef-oxic", + "TN-43": "sidi-bou-zid-ifqk", + "TN-61": "sfax-ktva", + "TN-71": "gafsa-ofsu", + "TN-73": "kebili-ecss", + "TN-83": "tataouine-qrma", + "TR-01": "adana-wdhs", + "TR-03": "afyonkarahisar-gghu", + "TR-04": "agri-cvhn", + "TR-06": "ankara-oyhp", + "TR-07": "antalya-iahq", + "TR-08": "artvin-aohz", + "TR-10": "balikesir-exjy", + "TR-11": "bilecik-wyjz", + "TR-13": "bitlis-gbjb", + "TR-14": "bolu-cdjc", + "TR-16": "bursa-ogje", + "TR-19": "corum-amjr", + "TR-20": "denizli-spld", + "TR-21": "diyarbakir-mrle", + "TR-24": "erzincan-qvlh", + "TR-25": "erzurum-kxli", + "TR-26": "eskisehir-eslf", + "TR-28": "giresun-wdlv", + "TR-29": "gumushane-melw", + "TR-33": "mersin-mqol", + "TR-35": "izmir-ehof", + "TR-36": "kars-uiog", + "TR-37": "kastamonu-okoh", + "TR-38": "kayseri-kzoa", + "TR-40": "kirsehir-iywz", + "TR-42": "konya-ubwb", + "TR-43": "kutahya-odwc", + "TR-44": "malatya-kfwd", + "TR-45": "manisa-cgwe", + "TR-46": "k-maras-wiwf", + "TR-48": "mugla-mmwr", + "TR-55": "samsun-inzb", + "TR-56": "siirt-yozc", + "TR-58": "sivas-ofzw", + "TR-63": "sanliurfa-imci", + "TR-65": "van-ujcg", + "TR-66": "yozgat-oecd", + "TR-68": "aksaray-cbcb", + "TW-HUA": "hualien-babs", + "TW-KHH": "kaohsiung-city-gnnm", + "TW-KIN": "kinmen-mdpx", + "TW-PEN": "penghu-oghr", + "TW-TPQ": "new-taipei-city-wbtm", + "TZ-01": "arusha-ssrk", + "TZ-03": "dodoma-cvrm", + "TZ-04": "iringa-ykrf", + "TZ-05": "kagera-umrg", + "TZ-08": "kigoma-aerb", + "TZ-09": "kilimanjaro-wgrc", + "TZ-10": "kusini-pemba-iltp", + "TZ-12": "lindi-yitn", + "TZ-13": "mara-cgtm", + "TZ-14": "mbeya-getl", + "TZ-16": "morogoro-wbtj", + "TZ-17": "mtwara-eati", + "TZ-18": "mwanza-iyth", + "TZ-19": "pwani-qxtg", + "TZ-20": "rukwa-ygvp", + "TZ-21": "ruvuma-qivq", + "TZ-22": "shinyanga-kdvn", + "TZ-23": "singida-gfvo", + "TZ-24": "tabora-wnvt", + "TZ-25": "tanga-oovu", + "TZ-26": "manyara-mkvr", + "TZ-27": "geita-elvs", + "TZ-28": "katavi-ytvx", + "TZ-29": "njombe-qvvy", + "TZ-30": "simiyu-iyyt", + "UG-107": "mubende-stqq", + "UG-108": "mukono-khqz", + "UG-109": "nakasongola-gjqa", + "UG-120": "buvuma-gikj", + "UG-207": "katakwi-xlyx", + "UG-216": "amuria-izaz", + "UG-305": "kitgum-hetq", + "UG-319": "amuru-fprn", + "UG-328": "napak-yzyn", + "UG-329": "nwoya-payo", + "UG-403": "hoima-dcsv", + "UG-406": "kasese-khsy", + "UG-410": "mbarara-yqvb", + "UG-410-2": "mbarara-mcue", + "UA-05": "vinnytsya-yoxi", + "UA-07": "volyn-irxk", + "UA-09": "luhans-k-whxu", + "UA-12": "dnipropetrovs-k-uszu", + "UA-14": "donets-k-gvzw", + "UA-18": "zhytomyr-iczk", + "UA-21": "transcarpathia-qncy", + "UA-23": "zaporizhzhya-cjcw", + "UA-26": "ivano-frankivs-k-iocz", + "UA-32": "kiev-yefc", + "UA-35": "kirovohrad-gwfx", + "UA-46": "l-viv-wbox", + "UA-48": "mykolayiv-obnj", + "UA-51": "odessa-kpqz", + "UA-53": "poltava-usqb", + "UA-56": "rivne-ekqw", + "UA-59": "sumy-kcqr", + "UA-61": "ternopil-whse", + "UA-63": "kharkiv-mesc", + "UA-65": "kherson-ybsa", + "UA-68": "khmel-nyts-kyy-etsv", + "UA-71": "cherkasy-wzvf", + "UA-74": "chernihiv-cevi", + "UY-AR": "artigas-stkw", + "UY-CL": "cerro-largo-sjom", + "UY-DU": "durazno-qcxo", + "UY-FD": "florida-acct", + "US-FL": "florida-gmqg", + "UY-LA": "lavalleja-mdrw", + "UY-PA": "paysandu-ikte", + "UY-RO": "rocha-ymzo", + "UY-SA": "salto-aobp", + "UY-SJ": "san-jose-qcby", + "UY-SO": "soriano-ixbv", + "UY-TA": "tacuarembo-yekg", + "US-AK": "alaska-qfen", + "US-AL": "alabama-uqeu", + "US-AR": "arkansas-itew", + "US-AZ": "arizona-igee", + "US-CA": "california-kikh", + "US-CO": "colorado-wfkf", + "US-CT": "connecticut-apkc", + "US-GA": "georgia-uotf", + "US-HI": "hawaii-mxvl", + "US-IA": "iowa-cdyh", + "US-ID": "idaho-slym", + "US-IL": "illinois-syye", + "US-IN": "indiana-ivyc", + "US-KS": "kansas-ondv", + "US-KY": "kentucky-abeb", + "US-LA": "louisiana-wlgr", + "US-MA": "massachusetts-ggid", + "US-MD": "maryland-ecia", + "US-ME": "maine-maiz", + "US-MI": "michigan-gtil", + "US-MN": "minnesota-qlig", + "US-MO": "missouri-ykif", + "US-MS": "mississippi-scir", + "US-MT": "montana-abiq", + "US-NC": "north-carolina-ozkp", + "US-ND": "north-dakota-ehku", + "US-NE": "nebraska-wikv", + "US-NH": "new-hampshire-koki", + "US-NJ": "new-jersey-wlkg", + "US-NM": "new-mexico-awkn", + "US-NV": "nevada-uekc", + "US-NY": "new-york-cqkt", + "US-OH": "ohio-kgmu", + "US-OK": "oklahoma-cimv", + "US-OR": "oregon-qznu", + "US-PA": "pennsylvania-ylkc", + "US-SC": "south-carolina-izro", + "US-SD": "south-dakota-oerr", + "US-TN": "tennessee-geup", + "US-TX": "texas-mguh", + "US-UT": "utah-whas", + "US-VA": "virginia-oedb", + "US-VT": "vermont-ujdo", + "US-WA": "washington-exgl", + "US-WI": "wisconsin-ekgt", + "US-WV": "west-virginia-ivga", + "US-WY": "wyoming-ajgj", + "UZ-BU": "bukhoro-udcy", + "UZ-FA": "ferghana-ammo", + "UZ-JI": "jizzakh-uoed", + "UZ-NW": "navoi-ahpf", + "UZ-QA": "kashkadarya-uvou", + "UZ-QR": "karakalpakstan-cuod", + "UZ-SA": "samarkand-ansu", + "UZ-SU": "surkhandarya-usso", + "UZ-TO": "tashkent-awvo", + "VE-B": "anzoategui-mrqa", + "VE-C": "apure-gtqb", + "VE-E": "barinas-uwqd", + "VE-H": "cojedes-abqg", + "VE-I": "falcon-scqh", + "VE-J": "guarico-meqi", + "VE-K": "lara-ggqj", + "VE-L": "merida-yhqk", + "VE-M": "miranda-ujql", + "VE-N": "monagas-kkqm", + "VE-P": "portuguesa-epqi", + "VE-S": "tachira-kuql", + "VE-U": "yaracuy-yxqn", + "VE-V": "zulia-szqo", + "VE-X01~": "venezuela-oxzs", + "VE-Y": "delta-amacuro-wdqr", + "VN-02": "lao-cai-suzu", + "VN-05": "son-la-amzp", + "VN-07": "tuyen-quang-kpzr", + "VN-09": "lang-son-yfzb", + "VN-21": "thanh-hoa-okef", + "VN-22": "nghe-an-ifec", + "VN-24": "quang-binh-wpei", + "VN-27": "quang-nam-cneh", + "VN-28": "kon-tum-ywew", + "VN-30": "gia-lai-kyhl", + "VN-33": "djak-lak-qdho", + "VN-35": "lam-djong-iuhi", + "VN-41": "long-an-irqd", + "VN-47": "kien-giang-qaqj", + "VN-58": "binh-phuoc-qysb", + "VN-71": "djien-bien-uwxm", + "VN-HN": "ha-noi-shnb", + "VU-SAM": "sanma-yzht", + "VU-TAE": "tafea-wskq", + "VU-TOB": "torba-ckkb", + "YE-AB": "abyan-oexn", + "YE-DH": "dhamar-utko", + "YE-HD": "hadramawt-itbu", + "YE-HJ": "hajjah-uqbs", + "YE-HU": "al-hudaydah-aubl", + "YE-LA": "lahij-saqb", + "YE-MA": "ma-rib-oyto", + "YE-MR": "al-mahrah-gatz", + "YE-SD": "sa-dah-kvqv", + "YE-SH": "shabwah-mpqr", + "YE-SN": "sana-a-ylqp", + "YE-TA": "ta-izz-ctzr", + "ZA-EC": "eastern-cape-oqpg", + "ZA-FS": "free-state-idrj", + "ZA-GT": "gauteng-eruj", + "ZA-LP": "limpopo-kvkx", + "ZA-MP": "mpumalanga-yrnu", + "ZA-NC": "northern-cape-glpq", + "ZA-NL": "kwazulu-natal-capj", + "ZA-WC": "western-cape-qngk", + "ZM-04": "luapula-imtp", + "ZM-06": "north-western-uptr", + "ZM-08": "copperbelt-gftb", + "ZM-09": "lusaka-ygtc", + "ZM-10": "muchinga-kova", + "ZW-MA": "manicaland-czzx", + "ZW-MC": "mashonaland-central-mczz", + "ZW-ME": "mashonaland-east-afzb", + "ZW-MI": "midlands-cmzf", + "ZW-MN": "matabeleland-north-otzk", + "ZW-MS": "matabeleland-south-qdzj", + "ZW-MV": "masvingo-wizm", + "ZW-MW": "mashonaland-west-ojzn" +} diff --git a/scripts/build-region-keys.mjs b/scripts/build-region-keys.mjs new file mode 100644 index 0000000..6bd1157 --- /dev/null +++ b/scripts/build-region-keys.mjs @@ -0,0 +1,158 @@ +/** + * scripts/build-region-keys.mjs — build the deterministic region-key manifest. + * + * Region ownership flips from whole-country (ISO_A3) to individual sub-region + * granularity, but the LLM and the persisted `Nation.territory` list need a + * *stable, human-readable, globally unique* identifier per sub-region. Raw + * feature ids (`FR-57`) are opaque to the model, so we mint a readable key of + * the form: + * + * -<4char> e.g. brittany-xk2a, western-alun + * + * where: + * - = properties.name → NFKD → strip combining marks → lowercase + * → a tiny fold table for the handful of letters NFKD does NOT decompose + * (ə ø ð đ œ ł, the only non-folding letters present in this dataset) + * → every non-alphanumeric run collapsed to a single '-' → leading/trailing + * '-' trimmed. + * - <4char> = a deterministic 4-letter lowercase code derived from the + * feature's stable id (FNV-1a 32-bit → 4 base-26 chars). It is stable + * (same id → same code on every run) because the key is persisted in + * SQLite and shown to the LLM. Within any name-slug group (e.g. the six + * regions all named "Western") the 4-char codes are made distinct by + * re-deriving with a deterministic salt on collision, which guarantees the + * full key is unique across all 1,796 regions. + * + * Output: `public/region-keys.json` — a `{ [stableFeatureId]: regionKey }` + * object, e.g. `{ "FR-57": "brittany-xk2a" }`, in file (stable) order. The map + * is looked up by the client (`WorldMap`) and the server (`map`/`presets`/ + * `engine`) to join a sub-region's stable id to its readable key. + * + * Builtins only — deliberately NO `@turf`/geojson import (importing one pulls + * `@types/geojson` into the tsc program and breaks `WorldMap.tsx`; see the + * v0.17 changelog note). Reads the geo file with plain `JSON.parse`. + * + * Idempotent: a re-run rewrites a byte-identical file (no timestamps, no + * randomness, stable feature order, deterministic hash). + * + * Usage: `node scripts/build-region-keys.mjs` (or `npm run build:region-keys`). + */ +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(here, '..'); + +/** + * Letters present in the dataset that NFKD does NOT decompose, and their + * single/multi-letter ASCII equivalents, so their slugs aren't hyphen-soup. + * Kept deliberately tiny + deterministic (only the six that actually occur). + */ +const FOLD = { + 'ə': 'a', // schwa + 'ø': 'o', // o-stroke + 'ð': 'd', // eth + 'đ': 'dj', // d-stroke + 'œ': 'oe', // oe ligature + 'ł': 'l', // l-stroke +}; + +/** + * Readable slug from a region name. NFKD decomposes + we strip the combining + * marks, lowercase, fold the non-decomposing letters, collapse every other + * non-alphanumeric run to one hyphen, and trim leading/trailing hyphens. + */ +function slug(name) { + let s = name.normalize('NFKD').replace(/[\u0300-\u036f]/g, ''); + s = s.toLowerCase(); + s = [...s].map((ch) => FOLD[ch] ?? ch).join(''); + s = s.replace(/[^a-z0-9]+/g, '-'); + s = s.replace(/^-+|-+$/g, ''); + return s; +} + +/** FNV-1a 32-bit — a tiny, stable, pure string hash. */ +function fnv1a32(str) { + let h = 0x811c9dc5; + for (let i = 0; i < str.length; i++) { + h ^= str.charCodeAt(i); + h = (h * 0x01000193) >>> 0; + } + return h >>> 0; +} + +/** Spread a 32-bit hash across four lowercase letters (base 26 per byte). */ +function code4(h) { + let out = ''; + for (let i = 0; i < 4; i++) { + out += String.fromCharCode(97 + ((((h >>> (i * 8)) & 0xff) % 26))); + } + return out; +} + +/** The 4-char code for an id, deterministically salted on within-group collision. */ +function codeFor(id, used) { + let code = code4(fnv1a32(id)); + let attempt = 0; + while (used.has(code)) { + attempt += 1; + code = code4(fnv1a32(`${id}#${attempt}`)); + } + return code; +} + +// --- load the region geo (plain parse; no geojson types) --- +const geoFile = path.join(root, 'public', 'regions.geo.json'); +const geo = JSON.parse(readFileSync(geoFile, 'utf8')); +const features = Array.isArray(geo?.features) ? geo.features : []; + +if (features.length !== 1796) { + throw new Error(`expected 1,796 regions, got ${features.length} — regions.geo.json changed; re-verify the region-key contract`); +} + +// Group features by their (computed) name-slug, preserving file order, so the +// within-slug 4-char uniqueness resolution below is deterministic. +const groups = new Map(); // slug -> array of { id } +for (const f of features) { + const id = f.id == null ? '' : String(f.id); + const name = f.properties?.name; + if (!id || typeof name !== 'string') { + throw new Error(`region with id ${JSON.stringify(id)} has no usable name`); + } + const s = slug(name); + if (!groups.has(s)) groups.set(s, []); + groups.get(s).push({ id }); +} + +// Assign keys, resolving 4-char collisions within each slug group. +const manifest = {}; +for (const [s, ids] of groups) { + const used = new Set(); + for (const { id } of ids) { + manifest[id] = `${s}-${codeFor(id, used)}`; + used.add(manifest[id].slice(-4)); + } +} + +// --- hard assertions (the test re-checks these against the committed file) --- +const keys = Object.values(manifest); +if (new Set(keys).size !== keys.length) { + throw new Error(`region-key collision: ${keys.length} keys but only ${new Set(keys).size} unique`); +} +const KEY_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*-[a-z]{4}$/; +for (const k of keys) { + if (!KEY_RE.test(k) || !k.includes('-')) { + throw new Error(`malformed region key: ${JSON.stringify(k)}`); + } +} + +// --- write idempotently (stable order = insertion order = file order) --- +const out = JSON.stringify(manifest, null, 2) + '\n'; +writeFileSync(path.join(root, 'public', 'region-keys.json'), out); + +const western = Object.entries(manifest) + .filter(([, k]) => k.startsWith('western-')) + .sort((a, b) => a[0] < b[0] ? -1 : 1); +console.log(`[build-region-keys] wrote public/region-keys.json — ${keys.length} unique region keys (1,796 expected)`); +console.log(` western group: ${western.map(([id, k]) => `${id}=${k}`).join(', ')}`);