From 416ff8c3923695a65b5c395581d889cccaf685f3 Mon Sep 17 00:00:00 2001 From: Jared Wein <jwein@mozilla.com> Date: Sun, 23 Sep 2018 23:50:03 -0700 Subject: [PATCH] Bug 1481972 - Add remaining countries to address autofill countries list. r=MattN Saving and filling the countries via Form Autofill will still be limited to certain countries but this allows the storage to be useful for Web Payments in other countries. Differential Revision: https://phabricator.services.mozilla.com/D5194 --HG-- extra : amend_source : c6810478b747cf51aaaafa73f83682cb23711231 --- browser/app/profile/firefox.js | 3 +- .../content/paymentDialogFrameScript.js | 2 +- .../payments/content/paymentDialogWrapper.js | 1 + .../payments/res/containers/address-form.js | 2 +- .../payments/res/unprivileged-fallbacks.js | 14 +- .../components/payments/test/browser/head.js | 2 +- .../extensions/formautofill/FormAutofill.jsm | 5 + .../formautofill/FormAutofillHandler.jsm | 7 + .../formautofill/FormAutofillParent.jsm | 13 +- .../formautofill/FormAutofillStorage.jsm | 4 +- .../formautofill/FormAutofillUtils.jsm | 48 +++- .../ProfileAutoCompleteResult.jsm | 1 + .../addressmetadata/addressReferences.js | 259 +++++++++++++++++- .../addressmetadata/addressReferencesExt.js | 2 +- .../formautofill/content/autofillEditForms.js | 26 +- .../formautofill/content/editAddress.xhtml | 12 +- .../locales/en-US/formautofill.properties | 43 +++ .../formautofill/skin/shared/editAddress.css | 2 + .../test/browser/browser_editAddressDialog.js | 126 ++++++++- .../formautofill/test/browser/head.js | 16 ++ .../test/unit/test_createRecords.js | 19 +- .../test/unit/test_onFormSubmitted.js | 51 ++-- .../test/unit/test_parseAddressFormat.js | 12 + .../test/unit/test_transformFields.js | 2 +- toolkit/components/mozintl/mozIMozIntl.idl | 13 +- toolkit/components/mozintl/mozIntl.js | 31 ++- .../test_mozintl_getLocaleDisplayNames.js | 8 + 27 files changed, 633 insertions(+), 91 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index a104abd5ca3ca..c50b0250cc2cc 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1684,8 +1684,7 @@ pref("extensions.formautofill.section.enabled", true); pref("extensions.formautofill.loglevel", "Warn"); #ifdef NIGHTLY_BUILD -// Comma separated list of countries Form Autofill supports. -// This affects feature availability and the address edit form country picker. +// Comma separated list of countries Form Autofill is available in. pref("extensions.formautofill.supportedCountries", "US,CA,DE"); pref("extensions.formautofill.supportRTL", true); #else diff --git a/browser/components/payments/content/paymentDialogFrameScript.js b/browser/components/payments/content/paymentDialogFrameScript.js index 024618ddd6d53..ee0dfb8b80105 100644 --- a/browser/components/payments/content/paymentDialogFrameScript.js +++ b/browser/components/payments/content/paymentDialogFrameScript.js @@ -74,7 +74,7 @@ let PaymentFrameScript = { let waivedContent = Cu.waiveXrays(content); let PaymentDialogUtils = { DEFAULT_REGION: FormAutofill.DEFAULT_REGION, - supportedCountries: FormAutofill.supportedCountries, + countries: FormAutofill.countries, getAddressLabel(address, addressFields = null) { return FormAutofillUtils.getAddressLabel(address, addressFields); diff --git a/browser/components/payments/content/paymentDialogWrapper.js b/browser/components/payments/content/paymentDialogWrapper.js index 7f1c6f6232044..1f71ace0afd57 100644 --- a/browser/components/payments/content/paymentDialogWrapper.js +++ b/browser/components/payments/content/paymentDialogWrapper.js @@ -136,6 +136,7 @@ var paymentDialogWrapper = { addressLines: addressData["street-address"].split("\n"), region: addressData["address-level1"], city: addressData["address-level2"], + dependentLocality: addressData["address-level3"], postalCode: addressData["postal-code"], organization: addressData.organization, recipient: addressData.name, diff --git a/browser/components/payments/res/containers/address-form.js b/browser/components/payments/res/containers/address-form.js index a9a31f46f9e87..7b7bb51e8ed94 100644 --- a/browser/components/payments/res/containers/address-form.js +++ b/browser/components/payments/res/containers/address-form.js @@ -88,7 +88,7 @@ export default class AddressForm extends PaymentStateSubscriberMixin(PaymentRequ }, record, { DEFAULT_REGION: PaymentDialogUtils.DEFAULT_REGION, getFormFormat: PaymentDialogUtils.getFormFormat, - supportedCountries: PaymentDialogUtils.supportedCountries, + countries: PaymentDialogUtils.countries, }); // The EditAddress constructor adds `input` event listeners on the same element, diff --git a/browser/components/payments/res/unprivileged-fallbacks.js b/browser/components/payments/res/unprivileged-fallbacks.js index 6a08e3bb07d3b..c7ac612bc6c60 100644 --- a/browser/components/payments/res/unprivileged-fallbacks.js +++ b/browser/components/payments/res/unprivileged-fallbacks.js @@ -50,10 +50,12 @@ var PaymentDialogUtils = { return !!str.replace(/[-\s]/g, "").match(/^\d{9,}$/); }, DEFAULT_REGION: "US", - supportedCountries: ["US", "CA", "DE"], + countries: new Map([["US", "United States"], ["CA", "Canada"], ["DE", "Germany"]]), getFormFormat(country) { if (country == "DE") { return { + addressLevel3Label: "", + addressLevel2Label: "city", addressLevel1Label: "province", postalCodeLabel: "postalCode", fieldsOrder: [ @@ -77,9 +79,11 @@ var PaymentDialogUtils = { } return { - "addressLevel1Label": country == "US" ? "state" : "province", - "postalCodeLabel": country == "US" ? "zip" : "postalCode", - "fieldsOrder": [ + addressLevel3Label: "", + addressLevel2Label: "city", + addressLevel1Label: country == "US" ? "state" : "province", + postalCodeLabel: country == "US" ? "zip" : "postalCode", + fieldsOrder: [ {fieldId: "name", newLine: true}, {fieldId: "street-address", newLine: true}, {fieldId: "address-level2"}, @@ -89,7 +93,7 @@ var PaymentDialogUtils = { ], // The following values come from addressReferences.js and should not be changed. /* eslint-disable-next-line max-len */ - "postalCodePattern": country == "US" ? "(\\d{5})(?:[ \\-](\\d{4}))?" : "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", + postalCodePattern: country == "US" ? "(\\d{5})(?:[ \\-](\\d{4}))?" : "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", }; }, getDefaultPreferences() { diff --git a/browser/components/payments/test/browser/head.js b/browser/components/payments/test/browser/head.js index 078a4a8538626..1f0243829fd96 100644 --- a/browser/components/payments/test/browser/head.js +++ b/browser/components/payments/test/browser/head.js @@ -387,7 +387,7 @@ async function navigateToAddAddressPage(frame, aOptions = { PaymentTestUtils, } = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {}); - info("navigateToAddAddressPage: check were on the expected page first"); + info("navigateToAddAddressPage: check we're on the expected page first"); await PaymentTestUtils.DialogContentUtils.waitForState(content, (state) => { info("current page state: " + state.page.id + " waiting for: " + options.initialPageId); return state.page.id == options.initialPageId; diff --git a/browser/extensions/formautofill/FormAutofill.jsm b/browser/extensions/formautofill/FormAutofill.jsm index 96855168c2772..7725c3f171945 100644 --- a/browser/extensions/formautofill/FormAutofill.jsm +++ b/browser/extensions/formautofill/FormAutofill.jsm @@ -7,6 +7,7 @@ var EXPORTED_SYMBOLS = ["FormAutofill"]; ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +ChromeUtils.import("resource://gre/modules/Services.jsm"); const ADDRESSES_FIRST_TIME_USE_PREF = "extensions.formautofill.firstTimeUse"; const AUTOFILL_CREDITCARDS_AVAILABLE_PREF = "extensions.formautofill.creditCards.available"; @@ -73,3 +74,7 @@ XPCOMUtils.defineLazyPreferenceGetter(FormAutofill, XPCOMUtils.defineLazyPreferenceGetter(FormAutofill, "supportedCountries", SUPPORTED_COUNTRIES_PREF, null, null, val => val.split(",")); + +XPCOMUtils.defineLazyGetter(FormAutofill, "countries", () => { + return Services.intl.getRegions(undefined); +}); diff --git a/browser/extensions/formautofill/FormAutofillHandler.jsm b/browser/extensions/formautofill/FormAutofillHandler.jsm index 8e622bac79854..edf4bd81945a3 100644 --- a/browser/extensions/formautofill/FormAutofillHandler.jsm +++ b/browser/extensions/formautofill/FormAutofillHandler.jsm @@ -555,6 +555,13 @@ class FormAutofillAddressSection extends FormAutofillSection { } isRecordCreatable(record) { + if (record.country && !FormAutofill.supportedCountries.includes(record.country)) { + // We don't want to save data in the wrong fields due to not having proper + // heuristic regexes in countries we don't yet support. + log.warn("isRecordCreatable: Country not supported:", record.country); + return false; + } + let hasName = 0; let length = 0; for (let key of Object.keys(record)) { diff --git a/browser/extensions/formautofill/FormAutofillParent.jsm b/browser/extensions/formautofill/FormAutofillParent.jsm index 57c558a6b566d..bbafb63b5bb5b 100644 --- a/browser/extensions/formautofill/FormAutofillParent.jsm +++ b/browser/extensions/formautofill/FormAutofillParent.jsm @@ -54,6 +54,7 @@ const { } = FormAutofill; const { + ADDRESSES_COLLECTION_NAME, CREDITCARDS_COLLECTION_NAME, } = FormAutofillUtils; @@ -345,9 +346,17 @@ FormAutofillParent.prototype = { fieldValue = record["cc-number-decrypted"]; } - if (!lcSearchString || String(fieldValue).toLowerCase().startsWith(lcSearchString)) { - records.push(record); + if (collectionName == ADDRESSES_COLLECTION_NAME && record.country + && !FormAutofill.supportedCountries.includes(record.country)) { + // Address autofill isn't supported for the record's country so we don't + // want to attempt to potentially incorrectly fill the address fields. + continue; + } + + if (lcSearchString && !String(fieldValue).toLowerCase().startsWith(lcSearchString)) { + continue; } + records.push(record); } target.sendAsyncMessage("FormAutofill:Records", records); diff --git a/browser/extensions/formautofill/FormAutofillStorage.jsm b/browser/extensions/formautofill/FormAutofillStorage.jsm index 21f72761b2558..84b08595f9062 100644 --- a/browser/extensions/formautofill/FormAutofillStorage.jsm +++ b/browser/extensions/formautofill/FormAutofillStorage.jsm @@ -22,6 +22,7 @@ * family-name, * organization, // Company * street-address, // (Multiline) + * address-level3, // Suburb/Sublocality * address-level2, // City/Town * address-level1, // Province (Standardized code if possible) * postal-code, @@ -165,6 +166,7 @@ const VALID_ADDRESS_FIELDS = [ "family-name", "organization", "street-address", + "address-level3", "address-level2", "address-level1", "postal-code", @@ -1297,7 +1299,7 @@ class Addresses extends AutofillRecords { } _recordReadProcessor(address) { - if (address.country && !FormAutofill.supportedCountries.includes(address.country)) { + if (address.country && !FormAutofill.countries.has(address.country)) { delete address.country; delete address["country-name"]; } diff --git a/browser/extensions/formautofill/FormAutofillUtils.jsm b/browser/extensions/formautofill/FormAutofillUtils.jsm index dc44a9fca2668..9896ccefea4f5 100644 --- a/browser/extensions/formautofill/FormAutofillUtils.jsm +++ b/browser/extensions/formautofill/FormAutofillUtils.jsm @@ -72,7 +72,12 @@ let AddressDataLoader = { if (extSandbox.addressDataExt) { for (let key in extSandbox.addressDataExt) { - Object.assign(sandbox.addressData[key], extSandbox.addressDataExt[key]); + let addressDataForKey = sandbox.addressData[key]; + if (!addressDataForKey) { + addressDataForKey = sandbox.addressData[key] = {}; + } + + Object.assign(addressDataForKey, extSandbox.addressDataExt[key]); } } return sandbox; @@ -270,6 +275,7 @@ this.FormAutofillUtils = { let fieldOrder = [ "name", "-moz-street-address-one-line", // Street address + "address-level3", // Townland / Neighborhood / Village "address-level2", // City/Town "organization", // Company or organization name "address-level1", // Province/State (Standardized code if possible) @@ -371,10 +377,10 @@ this.FormAutofillUtils = { * The country code for requesting specific country's metadata. It'll be * default region if parameter is not set. * @param {string} [level1=null] - * Retrun address level 1/level 2 metadata if parameter is set. + * Return address level 1/level 2 metadata if parameter is set. * @returns {object|null} * Return metadata of specific region with default locale and other supported - * locales. We need to return a deafult country metadata for layout format + * locales. We need to return a default country metadata for layout format * and collator, but for sub-region metadata we'll just return null if not found. */ getCountryAddressRawData(country = FormAutofill.DEFAULT_REGION, level1 = null) { @@ -402,6 +408,9 @@ this.FormAutofillUtils = { * @param {string} country * @param {string} level1 * @returns {object|null} Return metadata of specific region with default locale. + * NOTE: The returned data may be for a default region if the + * specified one cannot be found. Callers who only want the specific + * region should check the returned country code. */ getCountryAddressData(country, level1) { let metadata = this.getCountryAddressRawData(country, level1); @@ -414,6 +423,9 @@ this.FormAutofillUtils = { * @param {string} level1 * @returns {array<object>|null} * Return metadata of specific region with all the locales. + * NOTE: The returned data may be for a default region if the + * specified one cannot be found. Callers who only want the specific + * region should check the returned country code. */ getCountryAddressDataWithLocales(country, level1) { let metadata = this.getCountryAddressRawData(country, level1); @@ -464,6 +476,7 @@ this.FormAutofillUtils = { A: "street-address", S: "address-level1", C: "address-level2", + D: "address-level3", Z: "postal-code", n: "newLine", }; @@ -496,12 +509,20 @@ this.FormAutofillUtils = { * @returns {string} The matching country code. */ identifyCountryCode(countryName, countrySpecified) { - let countries = countrySpecified ? [countrySpecified] : FormAutofill.supportedCountries; + let countries = countrySpecified ? [countrySpecified] : [...FormAutofill.countries.keys()]; for (let country of countries) { let collators = this.getCollators(country); - let metadata = this.getCountryAddressData(country); + if (country != metadata.key) { + // We hit the fallback logic in getCountryAddressRawData so ignore it as + // it's not related to `country` and use the name from l10n instead. + metadata = { + id: `data/${country}`, + key: country, + name: FormAutofill.countries.get(country), + }; + } let alternativeCountryNames = metadata.alternative_names || [metadata.name]; let reAlternativeCountryNames = this._reAlternativeCountryNames[country]; if (!reAlternativeCountryNames) { @@ -776,18 +797,27 @@ this.FormAutofillUtils = { * @param {string} country * @returns {object} * { + * {string} addressLevel3Label + * {string} addressLevel2Label * {string} addressLevel1Label * {string} postalCodeLabel * {object} fieldsOrder + * {string} postalCodePattern * } */ getFormFormat(country) { const dataset = this.getCountryAddressData(country); return { - "addressLevel1Label": dataset.state_name_type || "province", - "postalCodeLabel": dataset.zip_name_type || "postalCode", - "fieldsOrder": this.parseAddressFormat(dataset.fmt || "%N%n%O%n%A%n%C, %S %Z"), - "postalCodePattern": dataset.zip, + // Phillipines doesn't specify a sublocality_name_type but + // has one referenced in their fmt value. + addressLevel3Label: dataset.sublocality_name_type || "suburb", + // Many locales don't specify a locality_name_type but + // have one referenced in their fmt value. + addressLevel2Label: dataset.locality_name_type || "city", + addressLevel1Label: dataset.state_name_type || "province", + postalCodeLabel: dataset.zip_name_type || "postalCode", + fieldsOrder: this.parseAddressFormat(dataset.fmt || "%N%n%O%n%A%n%C, %S %Z"), + postalCodePattern: dataset.zip, }; }, diff --git a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm index cc76daed22625..522be57e37840 100644 --- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm +++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm @@ -220,6 +220,7 @@ class AddressResult extends ProfileAutoCompleteResult { const secondaryLabelOrder = [ "street-address", // Street address "name", // Full name + "address-level3", // Townland / Neighborhood / Village "address-level2", // City/Town "organization", // Company or organization name "address-level1", // Province/State (Standardized code if possible) diff --git a/browser/extensions/formautofill/addressmetadata/addressReferences.js b/browser/extensions/formautofill/addressmetadata/addressReferences.js index 794c9b8c07246..b378b7754de62 100644 --- a/browser/extensions/formautofill/addressmetadata/addressReferences.js +++ b/browser/extensions/formautofill/addressmetadata/addressReferences.js @@ -10,14 +10,265 @@ // The data below is initially copied from // https://chromium-i18n.appspot.com/ssl-aggregate-address +// See https://github.com/googlei18n/libaddressinput/wiki/AddressValidationMetadata for +// documentation on how to use the data. + // WARNING: DO NOT change any value or add additional properties in addressData. // We only accept the metadata of the supported countries that is copied from libaddressinput directly. // Please edit addressReferencesExt.js instead if you want to add new property as complement // or overwrite the existing properties. var addressData = { - "data/CA": {"lang": "en", "upper": "ACNOSZ", "zipex": "H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1", "name": "CANADA", "zip": "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", "fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/CA", "languages": "en~fr", "sub_keys": "AB~BC~MB~NB~NL~NT~NS~NU~ON~PE~QC~SK~YT", "key": "CA", "posturl": "https://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf", "require": "ACSZ", "sub_names": "Alberta~British Columbia~Manitoba~New Brunswick~Newfoundland and Labrador~Northwest Territories~Nova Scotia~Nunavut~Ontario~Prince Edward Island~Quebec~Saskatchewan~Yukon", "sub_zips": "T~V~R~E~A~X0E|X0G|X1A~B~X0A|X0B|X0C~K|L|M|N|P~C~G|H|J|K1A~S|R8A~Y"}, - "data/CA--fr": {"lang": "fr", "upper": "ACNOSZ", "zipex": "H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1", "name": "CANADA", "zip": "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", "fmt": "%N%n%O%n%A%n%C %S %Z", "require": "ACSZ", "sub_keys": "AB~BC~PE~MB~NB~NS~NU~ON~QC~SK~NL~NT~YT", "key": "CA", "posturl": "https://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf", "id": "data/CA--fr", "sub_names": "Alberta~Colombie-Britannique~ÃŽle-du-Prince-Édouard~Manitoba~Nouveau-Brunswick~Nouvelle-Écosse~Nunavut~Ontario~Québec~Saskatchewan~Terre-Neuve-et-Labrador~Territoires du Nord-Ouest~Yukon", "sub_zips": "T~V~C~R~E~B~X0A|X0B|X0C~K|L|M|N|P~G|H|J|K1A~S|R8A~A~X0E|X0G|X1A~Y"}, - "data/DE": {"zipex": "26133,53225", "name": "GERMANY", "zip": "\\d{5}", "fmt": "%N%n%O%n%A%n%Z %C", "id": "data/DE", "key": "DE", "posturl": "http://www.postdirekt.de/plzserver/", "require": "ACZ"}, - "data/US": {"lang": "en", "upper": "CS", "sub_zipexs": "35000,36999~99500,99999~96799~85000,86999~71600,72999~34000,34099~09000,09999~96200,96699~90000,96199~80000,81999~06000,06999~19700,19999~20000,56999~32000,34999~30000,39901~96910,96932~96700,96899~83200,83999~60000,62999~46000,47999~50000,52999~66000,67999~40000,42799~70000,71599~03900,04999~96960,96979~20600,21999~01000,05544~48000,49999~96941,96944~55000,56799~38600,39799~63000,65999~59000,59999~68000,69999~88900,89999~03000,03899~07000,08999~87000,88499~10000,00544~27000,28999~58000,58999~96950,96952~43000,45999~73000,74999~97000,97999~96940~15000,19699~00600,00999~02800,02999~29000,29999~57000,57999~37000,38599~75000,73344~84000,84999~05000,05999~00800,00899~20100,24699~98000,99499~24700,26999~53000,54999~82000,83414", "zipex": "95014,22162-1010", "name": "UNITED STATES", "zip": "(\\d{5})(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "fmt": "%N%n%O%n%A%n%C, %S %Z", "state_name_type": "state", "id": "data/US", "languages": "en", "sub_keys": "AL~AK~AS~AZ~AR~AA~AE~AP~CA~CO~CT~DE~DC~FL~GA~GU~HI~ID~IL~IN~IA~KS~KY~LA~ME~MH~MD~MA~MI~FM~MN~MS~MO~MT~NE~NV~NH~NJ~NM~NY~NC~ND~MP~OH~OK~OR~PW~PA~PR~RI~SC~SD~TN~TX~UT~VT~VI~VA~WA~WV~WI~WY", "key": "US", "posturl": "https://tools.usps.com/go/ZipLookupAction!input.action", "require": "ACSZ", "sub_names": "Alabama~Alaska~American Samoa~Arizona~Arkansas~Armed Forces (AA)~Armed Forces (AE)~Armed Forces (AP)~California~Colorado~Connecticut~Delaware~District of Columbia~Florida~Georgia~Guam~Hawaii~Idaho~Illinois~Indiana~Iowa~Kansas~Kentucky~Louisiana~Maine~Marshall Islands~Maryland~Massachusetts~Michigan~Micronesia~Minnesota~Mississippi~Missouri~Montana~Nebraska~Nevada~New Hampshire~New Jersey~New Mexico~New York~North Carolina~North Dakota~Northern Mariana Islands~Ohio~Oklahoma~Oregon~Palau~Pennsylvania~Puerto Rico~Rhode Island~South Carolina~South Dakota~Tennessee~Texas~Utah~Vermont~Virgin Islands~Virginia~Washington~West Virginia~Wisconsin~Wyoming", "sub_zips": "3[56]~99[5-9]~96799~8[56]~71[6-9]|72~340~09~96[2-6]~9[0-5]|96[01]~8[01]~06~19[7-9]~20[02-5]|569~3[23]|34[1-9]~3[01]|398|39901~969([1-2]\\d|3[12])~967[0-8]|9679[0-8]|968~83[2-9]~6[0-2]~4[67]~5[0-2]~6[67]~4[01]|42[0-7]~70|71[0-5]~039|04~969[67]~20[6-9]|21~01|02[0-7]|05501|05544~4[89]~9694[1-4]~55|56[0-7]~38[6-9]|39[0-7]~6[3-5]~59~6[89]~889|89~03[0-8]~0[78]~87|88[0-4]~1[0-4]|06390|00501|00544~2[78]~58~9695[0-2]~4[3-5]~7[34]~97~969(39|40)~1[5-8]|19[0-6]~00[679]~02[89]~29~57~37|38[0-5]~7[5-9]|885|73301|73344~84~05~008~201|2[23]|24[0-6]~98|99[0-4]~24[7-9]|2[56]~5[34]~82|83[01]|83414"}, + "data/AD": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/AD", "key": "AD", "lang": "ca", "languages": "ca", "name": "ANDORRA", "posturl": "http://www.correos.es/comun/CodigosPostales/1010_s-CodPostal.asp?Provincia=", "sub_isoids": "07~02~03~08~04~05~06", "sub_keys": "Parròquia d'Andorra la Vella~Canillo~Encamp~Escaldes-Engordany~La Massana~Ordino~Sant Julià de Lòria", "sub_names": "Andorra la Vella~Canillo~Encamp~Escaldes-Engordany~La Massana~Ordino~Sant Julià de Lòria", "sub_zipexs": "AD500~AD100~AD200~AD700~AD400~AD300~AD600", "sub_zips": "AD50[01]~AD10[01]~AD20[01]~AD70[01]~AD40[01]~AD30[01]~AD60[01]", "zip": "AD[1-7]0\\d", "zipex": "AD100,AD501,AD700"}, + "data/AE": {"fmt": "%N%n%O%n%A%n%S", "id": "data/AE", "key": "AE", "lang": "ar", "languages": "ar", "lfmt": "%N%n%O%n%A%n%S", "name": "UNITED ARAB EMIRATES", "require": "AS", "state_name_type": "emirate", "sub_isoids": "AZ~SH~FU~UQ~DU~RK~AJ", "sub_keys": "أبو ظبي~إمارة الشارقةّ~الÙجيرة~ام القيوين~إمارة دبيّ~إمارة رأس الخيمة~عجمان", "sub_lnames": "Abu Dhabi~Sharjah~Fujairah~Umm Al Quwain~Dubai~Ras al Khaimah~Ajman", "sub_names": "أبو ظبي~الشارقة~الÙجيرة~ام القيوين~دبي~رأس الخيمة~عجمان"}, + "data/AF": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/AF", "key": "AF", "name": "AFGHANISTAN", "zip": "\\d{4}", "zipex": "1001,2601,3801"}, + "data/AG": {"id": "data/AG", "key": "AG", "name": "ANTIGUA AND BARBUDA", "require": "A"}, + "data/AI": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/AI", "key": "AI", "name": "ANGUILLA", "zip": "(?:AI-)?2640", "zipex": "2640"}, + "data/AL": {"fmt": "%N%n%O%n%A%n%Z%n%C", "id": "data/AL", "key": "AL", "name": "ALBANIA", "zip": "\\d{4}", "zipex": "1001,1017,3501"}, + "data/AM": {"fmt": "%N%n%O%n%A%n%Z%n%C%n%S", "id": "data/AM", "key": "AM", "lang": "hy", "languages": "hy", "lfmt": "%N%n%O%n%A%n%Z%n%C%n%S", "name": "ARMENIA", "sub_isoids": "AG~AR~AV~GR~ER~LO~KT~SH~SU~VD~TV", "sub_keys": "Ô±Ö€Õ¡Õ£Õ¡Õ®Õ¸Õ¿Õ¶~Ô±Ö€Õ¡Ö€Õ¡Õ¿~Ô±Ö€Õ´Õ¡Õ¾Õ«Ö€~Ô³Õ¥Õ²Õ¡Ö€Ö„Õ¸Ö‚Õ¶Õ«Ö„~ÔµÖ€Ö‡Õ¡Õ¶~Ô¼Õ¸Õ¼Õ«~Ô¿Õ¸Õ¿Õ¡ÕµÖ„~Õ‡Õ«Ö€Õ¡Õ¯~ÕÕµÕ¸Ö‚Õ¶Õ«Ö„~ÕŽÕ¡ÕµÕ¸Ö Õ±Õ¸Ö€~ÕÕ¡Õ¾Õ¸Ö‚Õ·", "sub_lnames": "Aragatsotn~Ararat~Armavir~Gegharkunik~Yerevan~Lori~Kotayk~Shirak~Syunik~Vayots Dzor~Tavush", "sub_zipexs": "0201,0514~0601,0823~0901,1149~1201,1626~0000,0099~1701,2117~2201,2506~2601,3126~3201,3519~3601,3810~3901,4216", "sub_zips": "0[2-5]~0[6-8]~09|1[01]~1[2-6]~00~1[7-9]|2[01]~2[2-5]~2[6-9]|3[01]~3[2-5]~3[6-8]~39|4[0-2]", "zip": "(?:37)?\\d{4}", "zipex": "375010,0002,0010"}, + "data/AO": {"id": "data/AO", "key": "AO", "name": "ANGOLA"}, + "data/AQ": {"id": "data/AQ", "key": "AQ", "name": "ANTARCTICA"}, + "data/AR": {"fmt": "%N%n%O%n%A%n%Z %C%n%S", "id": "data/AR", "key": "AR", "lang": "es", "languages": "es", "name": "ARGENTINA", "posturl": "http://www.correoargentino.com.ar/formularios/cpa", "sub_isoids": "B~K~H~U~C~X~W~E~P~Y~L~F~M~N~Q~R~A~J~D~Z~S~G~V~T", "sub_keys": "Buenos Aires~Catamarca~Chaco~Chubut~Ciudad Autónoma de Buenos Aires~Córdoba~Corrientes~Entre RÃos~Formosa~Jujuy~La Pampa~La Rioja~Mendoza~Misiones~Neuquén~RÃo Negro~Salta~San Juan~San Luis~Santa Cruz~Santa Fe~Santiago del Estero~Tierra del Fuego~Tucumán", "sub_names": "Buenos Aires~Catamarca~Chaco~Chubut~Ciudad Autónoma de Buenos Aires~Córdoba~Corrientes~Entre RÃos~Formosa~Jujuy~La Pampa~La Rioja~Mendoza~Misiones~Neuquén~RÃo Negro~Salta~San Juan~San Luis~Santa Cruz~Santa Fe~Santiago del Estero~Tierra del Fuego~Tucumán", "sub_zips": "B?[1-36-8]~K?[45]~H?3~U?[89]~C?1~X?[235-8]~W?3~E?[1-3]~P?[37]~Y?4~L?[3568]~F?5~M?[56]~N?3~Q?[38]~R?[89]~A?[34]~J?5~D?[4-6]~Z?[89]~S?[2368]~G?[2-5]~V?9~T?[45]", "upper": "ACZ", "zip": "((?:[A-HJ-NP-Z])?\\d{4})([A-Z]{3})?", "zipex": "C1070AAM,C1000WAM,B1000TBU,X5187XAB"}, + "data/AS": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/AS", "key": "AS", "name": "AMERICAN SAMOA", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACSZ", "state_name_type": "state", "upper": "ACNOS", "zip": "(96799)(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "96799"}, + "data/AT": {"fmt": "%O%n%N%n%A%n%Z %C", "id": "data/AT", "key": "AT", "name": "AUSTRIA", "posturl": "http://www.post.at/post_subsite_postleitzahlfinder.php", "require": "ACZ", "zip": "\\d{4}", "zipex": "1010,3741"}, + "data/AU": {"fmt": "%O%n%N%n%A%n%C %S %Z", "id": "data/AU", "key": "AU", "lang": "en", "languages": "en", "locality_name_type": "suburb", "name": "AUSTRALIA", "posturl": "http://www1.auspost.com.au/postcodes/", "require": "ACSZ", "state_name_type": "state", "sub_isoids": "ACT~NSW~NT~QLD~SA~TAS~VIC~WA", "sub_keys": "ACT~NSW~NT~QLD~SA~TAS~VIC~WA", "sub_names": "Australian Capital Territory~New South Wales~Northern Territory~Queensland~South Australia~Tasmania~Victoria~Western Australia", "sub_zipexs": "0200,2540,2618,2999~1000,2888,3585,3707~0800,0999~4000,9999~5000~7000,7999~3000,8000~6000,0872", "sub_zips": "29|2540|260|261[0-8]|02|2620~1|2[0-57-8]|26[2-9]|261[189]|3500|358[56]|3644|3707~0[89]~[49]~5|0872~7~[38]~6|0872", "upper": "CS", "zip": "\\d{4}", "zipex": "2060,3171,6430,4000,4006,3001"}, + "data/AW": {"id": "data/AW", "key": "AW", "name": "ARUBA"}, + "data/AZ": {"fmt": "%N%n%O%n%A%nAZ %Z %C", "id": "data/AZ", "key": "AZ", "name": "AZERBAIJAN", "postprefix": "AZ ", "zip": "\\d{4}", "zipex": "1000"}, + "data/BA": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/BA", "key": "BA", "name": "BOSNIA AND HERZEGOVINA", "zip": "\\d{5}", "zipex": "71000"}, + "data/BB": {"fmt": "%N%n%O%n%A%n%C, %S %Z", "id": "data/BB", "key": "BB", "name": "BARBADOS", "state_name_type": "parish", "zip": "BB\\d{5}", "zipex": "BB23026,BB22025"}, + "data/BD": {"fmt": "%N%n%O%n%A%n%C - %Z", "id": "data/BD", "key": "BD", "name": "BANGLADESH", "posturl": "http://www.bangladeshpost.gov.bd/PostCode.asp", "zip": "\\d{4}", "zipex": "1340,1000"}, + "data/BE": {"fmt": "%O%n%N%n%A%n%Z %C", "id": "data/BE", "key": "BE", "name": "BELGIUM", "posturl": "http://www.post.be/site/nl/residential/customerservice/search/postal_codes.html", "require": "ACZ", "zip": "\\d{4}", "zipex": "4000,1000"}, + "data/BF": {"fmt": "%N%n%O%n%A%n%C %X", "id": "data/BF", "key": "BF", "name": "BURKINA FASO"}, + "data/BG": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/BG", "key": "BG", "name": "BULGARIA (REP.)", "posturl": "http://www.bgpost.bg/?cid=5", "zip": "\\d{4}", "zipex": "1000,1700"}, + "data/BH": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/BH", "key": "BH", "name": "BAHRAIN", "zip": "(?:\\d|1[0-2])\\d{2}", "zipex": "317"}, + "data/BI": {"id": "data/BI", "key": "BI", "name": "BURUNDI"}, + "data/BJ": {"id": "data/BJ", "key": "BJ", "name": "BENIN", "upper": "AC"}, + "data/BL": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/BL", "key": "BL", "name": "SAINT BARTHELEMY", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "ACX", "zip": "9[78][01]\\d{2}", "zipex": "97100"}, + "data/BM": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/BM", "key": "BM", "name": "BERMUDA", "posturl": "http://www.landvaluation.bm/", "zip": "[A-Z]{2} ?[A-Z0-9]{2}", "zipex": "FL 07,HM GX,HM 12"}, + "data/BN": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/BN", "key": "BN", "name": "BRUNEI DARUSSALAM", "posturl": "http://www.post.gov.bn/SitePages/postcodes.aspx", "zip": "[A-Z]{2} ?\\d{4}", "zipex": "BT2328,KA1131,BA1511"}, + "data/BO": {"id": "data/BO", "key": "BO", "name": "BOLIVIA", "upper": "AC"}, + "data/BQ": {"id": "data/BQ", "key": "BQ", "name": "BONAIRE, SINT EUSTATIUS, AND SABA"}, + "data/BR": {"fmt": "%O%n%N%n%A%n%D%n%C-%S%n%Z", "id": "data/BR", "key": "BR", "lang": "pt", "languages": "pt", "name": "BRAZIL", "posturl": "http://www.buscacep.correios.com.br/", "require": "ASCZ", "state_name_type": "state", "sub_isoids": "AC~AL~AP~AM~BA~CE~DF~ES~GO~MA~MT~MS~MG~PA~PB~PR~PE~PI~RJ~RN~RS~RO~RR~SC~SP~SE~TO", "sub_keys": "AC~AL~AP~AM~BA~CE~DF~ES~GO~MA~MT~MS~MG~PA~PB~PR~PE~PI~RJ~RN~RS~RO~RR~SC~SP~SE~TO", "sub_mores": "true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true", "sub_names": "Acre~Alagoas~Amapá~Amazonas~Bahia~Ceará~Distrito Federal~EspÃrito Santo~Goiás~Maranhão~Mato Grosso~Mato Grosso do Sul~Minas Gerais~Pará~ParaÃba~Paraná~Pernambuco~PiauÃ~Rio de Janeiro~Rio Grande do Norte~Rio Grande do Sul~Rondônia~Roraima~Santa Catarina~São Paulo~Sergipe~Tocantins", "sub_zipexs": "69900-000,69999-999~57000-000,57999-999~68900-000,68999-999~69000-000,69400-123~40000-000,48999-999~60000-000,63999-999~70000-000,73500-123~29000-000,29999-999~72800-000,73700-123~65000-000,65999-999~78000-000,78899-999~79000-000,79999-999~30000-000,39999-999~66000-000,68899-999~58000-000,58999-999~80000-000,87999-999~50000-000,56999-999~64000-000,64999-999~20000-000,28999-999~59000-000,59999-999~90000-000,99999-999~76800-000,78900-000,78999-999~69300-000,69399-999~88000-000,89999-999~01000-000,13000-123~49000-000,49999-999~77000-000,77999-999", "sub_zips": "699~57~689~69[0-24-8]~4[0-8]~6[0-3]~7[0-1]|72[0-7]|73[0-6]~29~72[89]|73[7-9]|7[4-6]~65~78[0-8]~79~3~6[6-7]|68[0-8]~58~8[0-7]~5[0-6]~64~2[0-8]~59~9~76[89]|789~693~8[89]~[01][1-9]~49~77", "sublocality_name_type": "neighborhood", "upper": "CS", "zip": "\\d{5}-?\\d{3}", "zipex": "40301-110,70002-900"}, + "data/BS": {"fmt": "%N%n%O%n%A%n%C, %S", "id": "data/BS", "key": "BS", "lang": "en", "languages": "en", "name": "BAHAMAS", "state_name_type": "island", "sub_isoids": "~AK~~BY~BI~CI~~~EX~~HI~IN~LI~MG~~RI~RC~SS~SW", "sub_keys": "Abaco~Acklins~Andros~Berry Islands~Bimini~Cat Island~Crooked Island~Eleuthera~Exuma~Grand Bahama~Harbour Island~Inagua~Long Island~Mayaguana~N.P.~Ragged Island~Rum Cay~San Salvador~Spanish Wells", "sub_names": "Abaco Islands~Acklins~Andros Island~Berry Islands~Bimini~Cat Island~Crooked Island~Eleuthera~Exuma and Cays~Grand Bahama~Harbour Island~Inagua~Long Island~Mayaguana~New Providence~Ragged Island~Rum Cay~San Salvador~Spanish Wells"}, + "data/BT": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/BT", "key": "BT", "name": "BHUTAN", "posturl": "http://www.bhutanpost.bt/postcodes/", "zip": "\\d{5}", "zipex": "11001,31101,35003"}, + "data/BV": {"id": "data/BV", "key": "BV", "name": "BOUVET ISLAND"}, + "data/BW": {"id": "data/BW", "key": "BW", "name": "BOTSWANA"}, + "data/BY": {"fmt": "%S%n%Z %C%n%A%n%O%n%N", "id": "data/BY", "key": "BY", "name": "BELARUS", "posturl": "http://ex.belpost.by/addressbook/", "zip": "\\d{6}", "zipex": "223016,225860,220050"}, + "data/BZ": {"id": "data/BZ", "key": "BZ", "name": "BELIZE"}, + "data/CA": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/CA", "key": "CA", "lang": "en", "languages": "en~fr", "name": "CANADA", "posturl": "https://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf", "require": "ACSZ", "sub_isoids": "AB~BC~MB~NB~NL~NT~NS~NU~ON~PE~QC~SK~YT", "sub_keys": "AB~BC~MB~NB~NL~NT~NS~NU~ON~PE~QC~SK~YT", "sub_names": "Alberta~British Columbia~Manitoba~New Brunswick~Newfoundland and Labrador~Northwest Territories~Nova Scotia~Nunavut~Ontario~Prince Edward Island~Quebec~Saskatchewan~Yukon", "sub_zips": "T~V~R~E~A~X0E|X0G|X1A~B~X0A|X0B|X0C~K|L|M|N|P~C~G|H|J|K1A~S|R8A~Y", "upper": "ACNOSZ", "zip": "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", "zipex": "H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1"}, + "data/CA--fr": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/CA--fr", "key": "CA", "lang": "fr", "name": "CANADA", "posturl": "https://www.canadapost.ca/cpo/mc/personal/postalcode/fpc.jsf", "require": "ACSZ", "sub_isoids": "AB~BC~PE~MB~NB~NS~NU~ON~QC~SK~NL~NT~YT", "sub_keys": "AB~BC~PE~MB~NB~NS~NU~ON~QC~SK~NL~NT~YT", "sub_names": "Alberta~Colombie-Britannique~ÃŽle-du-Prince-Édouard~Manitoba~Nouveau-Brunswick~Nouvelle-Écosse~Nunavut~Ontario~Québec~Saskatchewan~Terre-Neuve-et-Labrador~Territoires du Nord-Ouest~Yukon", "sub_zips": "T~V~C~R~E~B~X0A|X0B|X0C~K|L|M|N|P~G|H|J|K1A~S|R8A~A~X0E|X0G|X1A~Y", "upper": "ACNOSZ", "zip": "[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z] ?\\d[ABCEGHJ-NPRSTV-Z]\\d", "zipex": "H3Z 2Y7,V8X 3X4,T0L 1K0,T0H 1A0,K1A 0B1"}, + "data/CC": {"fmt": "%O%n%N%n%A%n%C %S %Z", "id": "data/CC", "key": "CC", "name": "COCOS (KEELING) ISLANDS", "upper": "CS", "zip": "6799", "zipex": "6799"}, + "data/CD": {"id": "data/CD", "key": "CD", "name": "CONGO (DEM. REP.)"}, + "data/CF": {"id": "data/CF", "key": "CF", "name": "CENTRAL AFRICAN REPUBLIC"}, + "data/CG": {"id": "data/CG", "key": "CG", "name": "CONGO (REP.)"}, + "data/CH": {"fmt": "%O%n%N%n%A%nCH-%Z %C", "id": "data/CH", "key": "CH", "name": "SWITZERLAND", "postprefix": "CH-", "posturl": "http://www.post.ch/db/owa/pv_plz_pack/pr_main", "require": "ACZ", "upper": "", "zip": "\\d{4}", "zipex": "2544,1211,1556,3030"}, + "data/CI": {"fmt": "%N%n%O%n%X %A %C %X", "id": "data/CI", "key": "CI", "name": "COTE D'IVOIRE"}, + "data/CK": {"id": "data/CK", "key": "CK", "name": "COOK ISLANDS"}, + "data/CL": {"fmt": "%N%n%O%n%A%n%Z %C%n%S", "id": "data/CL", "key": "CL", "lang": "es", "languages": "es", "name": "CHILE", "posturl": "http://www.correos.cl/SitePages/home.aspx", "sub_isoids": "AN~AR~AP~AT~AI~BI~CO~LI~LL~LR~MA~ML~RM~TA~VS", "sub_keys": "Antofagasta~AraucanÃa~Arica y Parinacota~Atacama~Aysén~BiobÃo~Coquimbo~O'Higgins~Los Lagos~Los RÃos~Magallanes~Maule~Región Metropolitana~Tarapacá~ValparaÃso", "sub_mores": "true~true~true~true~true~true~true~true~true~true~true~true~true~true~true", "sub_names": "Antofagasta~AraucanÃa~Arica y Parinacota~Atacama~Aysén del General Carlos Ibáñez del Campo~BiobÃo~Coquimbo~Libertador General Bernardo O'Higgins~Los Lagos~Los RÃos~Magallanes y de la Antártica Chilena~Maule~Metropolitana de Santiago~Tarapacá~ValparaÃso", "zip": "\\d{7}", "zipex": "8340457,8720019,1230000,8329100"}, + "data/CM": {"id": "data/CM", "key": "CM", "name": "CAMEROON"}, + "data/CN": {"fmt": "%Z%n%S%C%D%n%A%n%O%n%N", "id": "data/CN", "key": "CN", "lang": "zh", "languages": "zh", "lfmt": "%N%n%O%n%A%n%D%n%C%n%S, %Z", "name": "CHINA", "posturl": "http://www.ems.com.cn/serviceguide/you_bian_cha_xun.html", "require": "ACSZ", "sub_isoids": "34~92~11~50~35~62~44~45~52~46~13~41~23~42~43~22~32~36~21~15~64~63~37~14~61~31~51~71~12~54~91~65~53~33", "sub_keys": "安徽çœ~澳门~北京市~é‡åº†å¸‚~ç¦å»ºçœ~甘肃çœ~广东çœ~广西壮æ—自治区~贵州çœ~æµ·å—çœ~河北çœ~æ²³å—çœ~黑龙江çœ~湖北çœ~æ¹–å—çœ~å‰æž—çœ~江è‹çœ~江西çœ~è¾½å®çœ~内蒙å¤è‡ªæ²»åŒº~å®å¤å›žæ—自治区~é’æµ·çœ~山东çœ~山西çœ~陕西çœ~上海市~å››å·çœ~å°æ¹¾~天津市~西è—自治区~香港~新疆维å¾å°”自治区~云å—çœ~浙江çœ", "sub_lnames": "Anhui Sheng~Macau~Beijing Shi~Chongqing Shi~Fujian Sheng~Gansu Sheng~Guangdong Sheng~Guangxi Zhuangzuzizhiqu~Guizhou Sheng~Hainan Sheng~Hebei Sheng~Henan Sheng~Heilongjiang Sheng~Hubei Sheng~Hunan Sheng~Jilin Sheng~Jiangsu Sheng~Jiangxi Sheng~Liaoning Sheng~Neimenggu Zizhiqu~Ningxia Huizuzizhiqu~Qinghai Sheng~Shandong Sheng~Shanxi Sheng~Shaanxi Sheng~Shanghai Shi~Sichuan Sheng~Taiwan~Tianjin Shi~Xizang Zizhiqu~Hong Kong~Xinjiang Weiwuerzizhiqu~Yunnan Sheng~Zhejiang Sheng", "sub_mores": "true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true", "sub_names": "安徽çœ~澳门~北京市~é‡åº†å¸‚~ç¦å»ºçœ~甘肃çœ~广东çœ~广西~贵州çœ~æµ·å—çœ~河北çœ~æ²³å—çœ~黑龙江çœ~湖北çœ~æ¹–å—çœ~å‰æž—çœ~江è‹çœ~江西çœ~è¾½å®çœ~内蒙å¤~å®å¤~é’æµ·çœ~山东çœ~山西çœ~陕西çœ~上海市~å››å·çœ~å°æ¹¾~天津市~西è—~香港~æ–°ç–†~云å—çœ~浙江çœ", "sub_xrequires": "~A~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ACS~~~", "sub_xzips": "~999078~~~~~~~~~~~~~~~~~~~~~~~~~~\\d{3}(\\d{2})?~~~999077~~~", "sublocality_name_type": "district", "upper": "S", "zip": "\\d{6}", "zipex": "266033,317204,100096,100808"}, + "data/CO": {"fmt": "%N%n%O%n%A%n%C, %S, %Z", "id": "data/CO", "key": "CO", "name": "COLOMBIA", "posturl": "http://www.codigopostal.gov.co/", "require": "AS", "state_name_type": "department", "zip": "\\d{6}", "zipex": "111221,130001,760011"}, + "data/CR": {"fmt": "%N%n%O%n%A%n%S, %C%n%Z", "id": "data/CR", "key": "CR", "name": "COSTA RICA", "posturl": "https://www.correos.go.cr/nosotros/codigopostal/busqueda.html", "require": "ACS", "zip": "\\d{4,5}|\\d{3}-\\d{4}", "zipex": "1000,2010,1001"}, + "data/CU": {"fmt": "%N%n%O%n%A%n%C %S%n%Z", "id": "data/CU", "key": "CU", "lang": "es", "languages": "es", "name": "CUBA", "sub_isoids": "15~09~08~06~12~14~11~99~03~10~04~16~01~07~13~05", "sub_keys": "Artemisa~Camagüey~Ciego de Ãvila~Cienfuegos~Granma~Guantánamo~HolguÃn~Isla de la Juventud~La Habana~Las Tunas~Matanzas~Mayabeque~Pinar del RÃo~Sancti SpÃritus~Santiago de Cuba~Villa Clara", "zip": "\\d{5}", "zipex": "10700"}, + "data/CV": {"fmt": "%N%n%O%n%A%n%Z %C%n%S", "id": "data/CV", "key": "CV", "lang": "pt", "languages": "pt", "name": "CAPE VERDE", "state_name_type": "island", "sub_isoids": "BV~BR~~MA~SL~~~~SV", "sub_keys": "Boa Vista~Brava~Fogo~Maio~Sal~Santiago~Santo Antão~São Nicolau~São Vicente", "zip": "\\d{4}", "zipex": "7600"}, + "data/CW": {"id": "data/CW", "key": "CW", "name": "CURACAO"}, + "data/CX": {"fmt": "%O%n%N%n%A%n%C %S %Z", "id": "data/CX", "key": "CX", "name": "CHRISTMAS ISLAND", "upper": "CS", "zip": "6798", "zipex": "6798"}, + "data/CY": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/CY", "key": "CY", "name": "CYPRUS", "zip": "\\d{4}", "zipex": "2008,3304,1900"}, + "data/CZ": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/CZ", "key": "CZ", "name": "CZECH REP.", "posturl": "http://psc.ceskaposta.cz/CleanForm.action", "require": "ACZ", "zip": "\\d{3} ?\\d{2}", "zipex": "100 00,251 66,530 87,110 00,225 99"}, + "data/DE": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/DE", "key": "DE", "name": "GERMANY", "posturl": "http://www.postdirekt.de/plzserver/", "require": "ACZ", "zip": "\\d{5}", "zipex": "26133,53225"}, + "data/DJ": {"id": "data/DJ", "key": "DJ", "name": "DJIBOUTI"}, + "data/DK": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/DK", "key": "DK", "name": "DENMARK", "posturl": "http://www.postdanmark.dk/da/Privat/Kundeservice/postnummerkort/Sider/Find-postnummer.aspx", "require": "ACZ", "zip": "\\d{4}", "zipex": "8660,1566"}, + "data/DM": {"id": "data/DM", "key": "DM", "name": "DOMINICA"}, + "data/DO": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/DO", "key": "DO", "name": "DOMINICAN REP.", "posturl": "http://inposdom.gob.do/codigo-postal/", "zip": "\\d{5}", "zipex": "11903,10101"}, + "data/DZ": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/DZ", "key": "DZ", "name": "ALGERIA", "zip": "\\d{5}", "zipex": "40304,16027"}, + "data/EC": {"fmt": "%N%n%O%n%A%n%Z%n%C", "id": "data/EC", "key": "EC", "name": "ECUADOR", "posturl": "http://www.codigopostal.gob.ec/", "upper": "CZ", "zip": "\\d{6}", "zipex": "090105,092301"}, + "data/EE": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/EE", "key": "EE", "name": "ESTONIA", "posturl": "https://www.omniva.ee/era/sihtnumbrite_otsing", "zip": "\\d{5}", "zipex": "69501,11212"}, + "data/EG": {"fmt": "%N%n%O%n%A%n%C%n%S%n%Z", "id": "data/EG", "key": "EG", "lang": "ar", "languages": "ar", "lfmt": "%N%n%O%n%A%n%C%n%S%n%Z", "name": "EGYPT", "sub_isoids": "ASN~AST~ALX~IS~LX~BA~BH~GZ~DK~SUZ~SHR~GH~FYM~C~KB~MNF~MN~WAD~BNS~PTS~JS~DT~SHG~SIN~KN~KFS~MT", "sub_keys": "أسوان~أسيوط~الإسكندرية~الإسماعيلية~الأقصر~البØر الأØمر~البØيرة~الجيزة~الدقهلية~السويس~الشرقية~الغربية~الÙيوم~القاهرة~القليوبية~المنوÙية~المنيا~الوادي الجديد~بني سويÙ~بورسعيد~جنوب سيناء~دمياط~سوهاج~شمال سيناء~قنا~ÙƒÙر الشيخ~مطروØ", "sub_lnames": "Aswan Governorate~Asyut Governorate~Alexandria Governorate~Ismailia Governorate~Luxor Governorate~Red Sea Governorate~El Beheira Governorate~Giza Governorate~Dakahlia Governorate~Suez Governorate~Ash Sharqia Governorate~Gharbia Governorate~Faiyum Governorate~Cairo Governorate~Qalyubia Governorate~Menofia Governorate~Menia Governorate~New Valley Governorate~Beni Suef Governorate~Port Said Governorate~South Sinai Governorate~Damietta Governorate~Sohag Governorate~North Sinai Governorate~Qena Governorate~Kafr El Sheikh Governorate~Matrouh Governorate", "sub_zipexs": "81000~71000~21000,23000~41000~85000~84000~22000~12000~35000~43000~44000~31000~63000~11000~13000~32000~61000~72000~62000~42000~46000~34000~82000~45000~83000~33000~51000", "sub_zips": "81~71~2[13]~41~85~84~22~12~35~43~44~31~63~11~13~32~61~72~62~42~46~34~82~45~83~33~51", "zip": "\\d{5}", "zipex": "12411,11599"}, + "data/EH": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/EH", "key": "EH", "name": "WESTERN SAHARA", "zip": "\\d{5}", "zipex": "70000,72000"}, + "data/ER": {"id": "data/ER", "key": "ER", "name": "ERITREA"}, + "data/ES": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/ES", "key": "ES", "lang": "es", "languages": "es~ca~gl~eu", "name": "SPAIN", "posturl": "http://www.correos.es/contenido/13-MenuRec2/04-MenuRec24/1010_s-CodPostal.asp", "require": "ACSZ", "sub_keys": "VI~AB~A~AL~O~AV~BA~B~BU~CC~CA~S~CS~CE~CR~CO~CU~GI~GR~GU~SS~H~HU~PM~J~C~LO~GC~LE~L~LU~M~MA~ML~MU~NA~OR~P~PO~SA~TF~SG~SE~SO~T~TE~TO~V~VA~BI~ZA~Z", "sub_names": "Ãlava~Albacete~Alicante~AlmerÃa~Asturias~Ãvila~Badajoz~Barcelona~Burgos~Cáceres~Cádiz~Cantabria~Castellón~Ceuta~Ciudad Real~Córdoba~Cuenca~Girona~Granada~Guadalajara~Guipúzcoa~Huelva~Huesca~Islas Baleares~Jaén~La Coruña~La Rioja~Las Palmas~León~Lérida~Lugo~Madrid~Málaga~Melilla~Murcia~Navarra~Ourense~Palencia~Pontevedra~Salamanca~Santa Cruz de Tenerife~Segovia~Sevilla~Soria~Tarragona~Teruel~Toledo~Valencia~Valladolid~Vizcaya~Zamora~Zaragoza", "sub_zips": "01~02~03~04~33~05~06~08~09~10~11~39~12~51~13~14~16~17~18~19~20~21~22~07~23~15~26~35~24~25~27~28~29~52~30~31~32~34~36~37~38~40~41~42~43~44~45~46~47~48~49~50", "upper": "CS", "zip": "\\d{5}", "zipex": "28039,28300,28070"}, + "data/ES--ca": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/ES--ca", "key": "ES", "lang": "ca", "name": "SPAIN", "posturl": "http://www.correos.es/contenido/13-MenuRec2/04-MenuRec24/1010_s-CodPostal.asp", "require": "ACSZ", "sub_keys": "A~AB~AL~VI~O~AV~BA~B~BI~BU~CC~CA~S~CS~CE~CR~CO~CU~GI~GR~GU~SS~H~HU~PM~J~C~LO~GC~LE~L~LU~M~MA~ML~MU~NA~OR~P~PO~SA~TF~SG~SE~SO~T~TE~TO~V~VA~ZA~Z", "sub_names": "Alacant~Albacete~Almeria~Araba~Asturias~Àvila~Badajoz~Barcelona~Bizkaia~Burgos~Cáceres~Cadis~Cantabria~Castelló~Ceuta~Ciudad Real~Córdoba~Cuenca~Girona~Granada~Guadalajara~Guipúscoa~Huelva~Huesca~Illes Balears~Jaén~La Corunya~La Rioja~Las Palmas~León~Lleida~Lugo~Madrid~Málaga~Melilla~Murcia~Navarra~Ourense~Palencia~Pontevedra~Salamanca~Santa Cruz de Tenerife~Segovia~Sevilla~Soria~Tarragona~Teruel~Toledo~València~Valladolid~Zamora~Zaragoza", "sub_zips": "03~02~04~01~33~05~06~08~48~09~10~11~39~12~51~13~14~16~17~18~19~20~21~22~07~23~15~26~35~24~25~27~28~29~52~30~31~32~34~36~37~38~40~41~42~43~44~45~46~47~49~50", "upper": "CS", "zip": "\\d{5}", "zipex": "28039,28300,28070"}, + "data/ES--eu": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/ES--eu", "key": "ES", "lang": "eu", "name": "SPAIN", "posturl": "http://www.correos.es/contenido/13-MenuRec2/04-MenuRec24/1010_s-CodPostal.asp", "require": "ACSZ", "sub_keys": "A~AB~AL~VI~O~AV~BA~B~BI~BU~CC~CA~S~CS~CE~CR~C~CU~SS~GI~GR~GU~H~HU~PM~J~CO~LO~GC~LE~L~LU~M~MA~ML~MU~NA~OR~P~PO~SA~TF~SG~SE~SO~T~TE~TO~V~VA~ZA~Z", "sub_names": "Alacant~Albacete~AlmerÃa~Araba~Asturias~Ãvila~Badajoz~Barcelona~Bizkaia~Burgos~Cáceres~Cádiz~Cantabria~Castelló~Ceuta~Ciudad Real~Coruña~Cuenca~Gipuzkoa~Girona~Granada~Guadalajara~Huelva~Huesca~Illes Balears~Jaén~Kordoba~La Rioja~Las Palmas~León~Lleida~Lugo~Madrid~Málaga~Melilla~Murtzia~Nafarroa~Ourense~Palentzia~Pontevedra~Salamanca~Santa Cruz Tenerifekoa~Segovia~Sevilla~Soria~Tarragona~Teruel~Toledo~Valentzia~Valladolid~Zamora~Zaragoza", "sub_zips": "03~02~04~01~33~05~06~08~48~09~10~11~39~12~51~13~15~16~20~17~18~19~21~22~07~23~14~26~35~24~25~27~28~29~52~30~31~32~34~36~37~38~40~41~42~43~44~45~46~47~49~50", "upper": "CS", "zip": "\\d{5}", "zipex": "28039,28300,28070"}, + "data/ES--gl": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/ES--gl", "key": "ES", "lang": "gl", "name": "SPAIN", "posturl": "http://www.correos.es/contenido/13-MenuRec2/04-MenuRec24/1010_s-CodPostal.asp", "require": "ACSZ", "sub_keys": "C~A~VI~AB~AL~GC~O~AV~BA~B~BI~BU~CC~CA~S~CS~CE~CR~CO~CU~GR~GU~SS~H~HU~PM~LO~LE~L~LU~M~MA~ML~MU~NA~OR~P~PO~SA~TF~SG~SE~SO~T~TE~TO~V~VA~J~GI~ZA~Z", "sub_names": "A Coruña~Alacant~Ãlava~Albacete~AlmerÃa~As Palmas~Asturias~Ãvila~Badaxoz~Barcelona~Biscaia~Burgos~Cáceres~Cádiz~Cantabria~Castelló~Ceuta~Cidade Real~Córdoba~Cuenca~Granada~Guadalajara~Guipúscoa~Huelva~Huesca~Illas Baleares~La Rioja~León~Lleida~Lugo~Madrid~Málaga~Melilla~Murcia~Navarra~Ourense~Palencia~Pontevedra~Salamanca~Santa Cruz de Tenerife~Segovia~Sevilla~Soria~Tarragona~Teruel~Toledo~Valencia~Valladolid~Xaén~Xirona~Zamora~Zaragoza", "sub_zips": "15~03~01~02~04~35~33~05~06~08~48~09~10~11~39~12~51~13~14~16~18~19~20~21~22~07~26~24~25~27~28~29~52~30~31~32~34~36~37~38~40~41~42~43~44~45~46~47~23~17~49~50", "upper": "CS", "zip": "\\d{5}", "zipex": "28039,28300,28070"}, + "data/ET": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/ET", "key": "ET", "name": "ETHIOPIA", "zip": "\\d{4}", "zipex": "1000"}, + "data/FI": {"fmt": "%O%n%N%n%A%nFI-%Z %C", "id": "data/FI", "key": "FI", "name": "FINLAND", "postprefix": "FI-", "posturl": "http://www.verkkoposti.com/e3/postinumeroluettelo", "require": "ACZ", "zip": "\\d{5}", "zipex": "00550,00011"}, + "data/FJ": {"id": "data/FJ", "key": "FJ", "name": "FIJI"}, + "data/FK": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/FK", "key": "FK", "name": "FALKLAND ISLANDS (MALVINAS)", "require": "ACZ", "upper": "CZ", "zip": "FIQQ 1ZZ", "zipex": "FIQQ 1ZZ"}, + "data/FM": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/FM", "key": "FM", "name": "MICRONESIA (Federated State of)", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACSZ", "state_name_type": "state", "upper": "ACNOS", "zip": "(9694[1-4])(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "96941,96944"}, + "data/FO": {"fmt": "%N%n%O%n%A%nFO%Z %C", "id": "data/FO", "key": "FO", "name": "FAROE ISLANDS", "postprefix": "FO", "posturl": "http://www.postur.fo/", "zip": "\\d{3}", "zipex": "100"}, + "data/FR": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/FR", "key": "FR", "name": "FRANCE", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "CX", "zip": "\\d{2} ?\\d{3}", "zipex": "33380,34092,33506"}, + "data/GA": {"id": "data/GA", "key": "GA", "name": "GABON"}, + "data/GB": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/GB", "key": "GB", "locality_name_type": "post_town", "name": "UNITED KINGDOM", "posturl": "http://www.royalmail.com/postcode-finder", "require": "ACZ", "upper": "CZ", "zip": "GIR ?0AA|(?:(?:AB|AL|B|BA|BB|BD|BF|BH|BL|BN|BR|BS|BT|BX|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(?:\\d[\\dA-Z]? ?\\d[ABD-HJLN-UW-Z]{2}))|BFPO ?\\d{1,4}", "zipex": "EC1Y 8SY,GIR 0AA,M2 5BQ,M34 4AB,CR0 2YR,DN16 9AA,W1A 4ZZ,EC1A 1HQ,OX14 4PG,BS18 8HF,NR25 7HG,RH6 0NP,BH23 6AA,B6 5BA,SO23 9AP,PO1 3AX,BFPO 61"}, + "data/GD": {"id": "data/GD", "key": "GD", "name": "GRENADA (WEST INDIES)"}, + "data/GE": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/GE", "key": "GE", "name": "GEORGIA", "posturl": "http://www.georgianpost.ge/index.php?page=10", "zip": "\\d{4}", "zipex": "0101"}, + "data/GF": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/GF", "key": "GF", "name": "FRENCH GUIANA", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "ACX", "zip": "9[78]3\\d{2}", "zipex": "97300"}, + "data/GG": {"fmt": "%N%n%O%n%A%n%C%nGUERNSEY%n%Z", "id": "data/GG", "key": "GG", "name": "CHANNEL ISLANDS", "posturl": "http://www.guernseypost.com/postcode_finder/", "require": "ACZ", "upper": "CZ", "zip": "GY\\d[\\dA-Z]? ?\\d[ABD-HJLN-UW-Z]{2}", "zipex": "GY1 1AA,GY2 2BT"}, + "data/GH": {"id": "data/GH", "key": "GH", "name": "GHANA"}, + "data/GI": {"fmt": "%N%n%O%n%A%nGIBRALTAR%n%Z", "id": "data/GI", "key": "GI", "name": "GIBRALTAR", "require": "A", "zip": "GX11 1AA", "zipex": "GX11 1AA"}, + "data/GL": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/GL", "key": "GL", "name": "GREENLAND", "require": "ACZ", "zip": "39\\d{2}", "zipex": "3900,3950,3911"}, + "data/GM": {"id": "data/GM", "key": "GM", "name": "GAMBIA"}, + "data/GN": {"fmt": "%N%n%O%n%Z %A %C", "id": "data/GN", "key": "GN", "name": "GUINEA", "zip": "\\d{3}", "zipex": "001,200,100"}, + "data/GP": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/GP", "key": "GP", "name": "GUADELOUPE", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "ACX", "zip": "9[78][01]\\d{2}", "zipex": "97100"}, + "data/GQ": {"id": "data/GQ", "key": "GQ", "name": "EQUATORIAL GUINEA"}, + "data/GR": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/GR", "key": "GR", "name": "GREECE", "posturl": "http://www.elta.gr/findapostcode.aspx", "require": "ACZ", "zip": "\\d{3} ?\\d{2}", "zipex": "151 24,151 10,101 88"}, + "data/GS": {"fmt": "%N%n%O%n%A%n%n%C%n%Z", "id": "data/GS", "key": "GS", "name": "SOUTH GEORGIA", "require": "ACZ", "upper": "CZ", "zip": "SIQQ 1ZZ", "zipex": "SIQQ 1ZZ"}, + "data/GT": {"fmt": "%N%n%O%n%A%n%Z- %C", "id": "data/GT", "key": "GT", "name": "GUATEMALA", "zip": "\\d{5}", "zipex": "09001,01501"}, + "data/GU": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/GU", "key": "GU", "name": "GUAM", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACZ", "upper": "ACNO", "zip": "(969(?:[12]\\d|3[12]))(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "96910,96931"}, + "data/GW": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/GW", "key": "GW", "name": "GUINEA-BISSAU", "zip": "\\d{4}", "zipex": "1000,1011"}, + "data/GY": {"id": "data/GY", "key": "GY", "name": "GUYANA"}, + "data/HK": {"fmt": "%S%n%C%n%A%n%O%n%N", "id": "data/HK", "key": "HK", "lang": "zh-Hant", "languages": "zh-Hant~en", "lfmt": "%N%n%O%n%A%n%C%n%S", "locality_name_type": "district", "name": "HONG KONG", "require": "AS", "state_name_type": "area", "sub_keys": "Kowloon~Hong Kong Island~New Territories", "sub_mores": "true~true~true", "sub_names": "ä¹é¾~香港島~æ–°ç•Œ", "upper": "S"}, + "data/HK--en": {"fmt": "%S%n%C%n%A%n%O%n%N", "id": "data/HK--en", "key": "HK", "lang": "en", "lfmt": "%N%n%O%n%A%n%C%n%S", "locality_name_type": "district", "name": "HONG KONG", "require": "AS", "state_name_type": "area", "sub_keys": "Hong Kong Island~Kowloon~New Territories", "sub_lnames": "Hong Kong Island~Kowloon~New Territories", "sub_mores": "true~true~true", "upper": "S"}, + "data/HM": {"fmt": "%O%n%N%n%A%n%C %S %Z", "id": "data/HM", "key": "HM", "name": "HEARD AND MCDONALD ISLANDS", "upper": "CS", "zip": "\\d{4}", "zipex": "7050"}, + "data/HN": {"fmt": "%N%n%O%n%A%n%C, %S%n%Z", "id": "data/HN", "key": "HN", "name": "HONDURAS", "require": "ACS", "zip": "\\d{5}", "zipex": "31301"}, + "data/HR": {"fmt": "%N%n%O%n%A%nHR-%Z %C", "id": "data/HR", "key": "HR", "name": "CROATIA", "postprefix": "HR-", "posturl": "http://www.posta.hr/default.aspx?pretpum", "zip": "\\d{5}", "zipex": "10000,21001,10002"}, + "data/HT": {"fmt": "%N%n%O%n%A%nHT%Z %C", "id": "data/HT", "key": "HT", "name": "HAITI", "postprefix": "HT", "zip": "\\d{4}", "zipex": "6120,5310,6110,8510"}, + "data/HU": {"fmt": "%N%n%O%n%C%n%A%n%Z", "id": "data/HU", "key": "HU", "name": "HUNGARY (Rep.)", "posturl": "http://posta.hu/ugyfelszolgalat/iranyitoszam_kereso", "require": "ACZ", "upper": "ACNO", "zip": "\\d{4}", "zipex": "1037,2380,1540"}, + "data/ID": {"fmt": "%N%n%O%n%A%n%C%n%S %Z", "id": "data/ID", "key": "ID", "lang": "id", "languages": "id", "name": "INDONESIA", "require": "AS", "sub_isoids": "AC~BA~BT~BE~YO~JK~GO~JA~JB~JT~JI~KB~KS~KT~KI~KU~BB~KR~LA~MA~MU~NB~NT~PA~PB~RI~SR~SN~ST~SG~SA~SB~SS~SU", "sub_keys": "Aceh~Bali~Banten~Bengkulu~Daerah Istimewa Yogyakarta~DKI Jakarta~Gorontalo~Jambi~Jawa Barat~Jawa Tengah~Jawa Timur~Kalimantan Barat~Kalimantan Selatan~Kalimantan Tengah~Kalimantan Timur~Kalimantan Utara~Kepulauan Bangka Belitung~Kepulauan Riau~Lampung~Maluku~Maluku Utara~Nusa Tenggara Barat~Nusa Tenggara Timur~Papua~Papua Barat~Riau~Sulawesi Barat~Sulawesi Selatan~Sulawesi Tengah~Sulawesi Tenggara~Sulawesi Utara~Sumatera Barat~Sumatera Selatan~Sumatera Utara", "zip": "\\d{5}", "zipex": "40115"}, + "data/IE": {"fmt": "%N%n%O%n%A%n%D%n%C%n%S %Z", "id": "data/IE", "key": "IE", "lang": "en", "languages": "en", "name": "IRELAND", "posturl": "https://finder.eircode.ie", "state_name_type": "county", "sub_isoids": "CW~CN~CE~C~DL~D~G~KY~KE~KK~LS~LM~LK~LD~LH~MO~MH~MN~OY~RN~SO~TA~WD~WH~WX~WW", "sub_keys": "Co. Carlow~Co. Cavan~Co. Clare~Co. Cork~Co. Donegal~Co. Dublin~Co. Galway~Co. Kerry~Co. Kildare~Co. Kilkenny~Co. Laois~Co. Leitrim~Co. Limerick~Co. Longford~Co. Louth~Co. Mayo~Co. Meath~Co. Monaghan~Co. Offaly~Co. Roscommon~Co. Sligo~Co. Tipperary~Co. Waterford~Co. Westmeath~Co. Wexford~Co. Wicklow", "sublocality_name_type": "townland", "zip": "[\\dA-Z]{3} ?[\\dA-Z]{4}", "zip_name_type": "eircode", "zipex": "A65 F4E2"}, + "data/IL": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/IL", "key": "IL", "name": "ISRAEL", "posturl": "http://www.israelpost.co.il/zipcode.nsf/demozip?openform", "zip": "\\d{5}(?:\\d{2})?", "zipex": "9614303"}, + "data/IM": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/IM", "key": "IM", "name": "ISLE OF MAN", "posturl": "https://www.iompost.com/tools-forms/postcode-finder/", "require": "ACZ", "upper": "CZ", "zip": "IM\\d[\\dA-Z]? ?\\d[ABD-HJLN-UW-Z]{2}", "zipex": "IM2 1AA,IM99 1PS"}, + "data/IN": {"fmt": "%N%n%O%n%A%n%C %Z%n%S", "id": "data/IN", "key": "IN", "lang": "en", "languages": "en~hi", "name": "INDIA", "posturl": "https://www.indiapost.gov.in/vas/pages/FindPinCode.aspx", "require": "ACSZ", "state_name_type": "state", "sub_isoids": "AN~AP~AR~AS~BR~CH~CT~DN~DD~DL~GA~GJ~HR~HP~JK~JH~KA~KL~LD~MP~MH~MN~ML~MZ~NL~OR~PY~PB~RJ~SK~TN~TG~TR~UP~UT~WB", "sub_keys": "Andaman and Nicobar Islands~Andhra Pradesh~Arunachal Pradesh~Assam~Bihar~Chandigarh~Chhattisgarh~Dadra and Nagar Haveli~Daman and Diu~Delhi~Goa~Gujarat~Haryana~Himachal Pradesh~Jammu and Kashmir~Jharkhand~Karnataka~Kerala~Lakshadweep~Madhya Pradesh~Maharashtra~Manipur~Meghalaya~Mizoram~Nagaland~Odisha~Puducherry~Punjab~Rajasthan~Sikkim~Tamil Nadu~Telangana~Tripura~Uttar Pradesh~Uttarakhand~West Bengal", "sub_names": "Andaman & Nicobar~Andhra Pradesh~Arunachal Pradesh~Assam~Bihar~Chandigarh~Chhattisgarh~Dadra & Nagar Haveli~Daman & Diu~Delhi~Goa~Gujarat~Haryana~Himachal Pradesh~Jammu & Kashmir~Jharkhand~Karnataka~Kerala~Lakshadweep~Madhya Pradesh~Maharashtra~Manipur~Meghalaya~Mizoram~Nagaland~Odisha~Puducherry~Punjab~Rajasthan~Sikkim~Tamil Nadu~Telangana~Tripura~Uttar Pradesh~Uttarakhand~West Bengal", "sub_zips": "744~5[0-3]~79[0-2]~78~8[0-5]~16|1440[3-9]~49~396~396~11~403~3[6-9]~1[23]~17~1[89]~81[4-9]|82|83[0-5]~5[4-9]|53[7-9]~6[7-9]|6010|607008|777~682~4[5-8]|490~4[0-4]~79[56]~79[34]~796~79[78]~7[5-7]~60[579]~1[456]~3[0-4]~737|750~6[0-6]|536~5[0-3]~799~2[0-35-8]|24[0-7]|26[12]~24[46-9]|254|26[23]~7[0-4]", "zip": "\\d{6}", "zip_name_type": "pin", "zipex": "110034,110001"}, + "data/IN--hi": {"fmt": "%N%n%O%n%A%n%C %Z%n%S", "id": "data/IN--hi", "key": "IN", "lang": "hi", "name": "INDIA", "posturl": "https://www.indiapost.gov.in/vas/pages/FindPinCode.aspx", "require": "ACSZ", "state_name_type": "state", "sub_isoids": "AN~AR~AS~AP~UP~UT~OR~KA~KL~GJ~GA~CH~CT~JK~JH~TN~TG~TR~DD~DN~DL~NL~PB~WB~PY~BR~MN~MP~MH~MZ~ML~RJ~LD~SK~HR~HP", "sub_keys": "Andaman & Nicobar~Arunachal Pradesh~Assam~Andhra Pradesh~Uttar Pradesh~Uttarakhand~Odisha~Karnataka~Kerala~Gujarat~Goa~Chandigarh~Chhattisgarh~Jammu & Kashmir~Jharkhand~Tamil Nadu~Telangana~Tripura~Daman & Diu~Dadra & Nagar Haveli~Delhi~Nagaland~Punjab~West Bengal~Puducherry~Bihar~Manipur~Madhya Pradesh~Maharashtra~Mizoram~Meghalaya~Rajasthan~Lakshadweep~Sikkim~Haryana~Himachal Pradesh", "sub_names": "अंडमान और निकोबार दà¥à¤µà¥€à¤ªà¤¸à¤®à¥‚ह~अरà¥à¤£à¤¾à¤šà¤² पà¥à¤°à¤¦à¥‡à¤¶~असम~आंधà¥à¤° पà¥à¤°à¤¦à¥‡à¤¶~उतà¥à¤¤à¤° पà¥à¤°à¤¦à¥‡à¤¶~उतà¥à¤¤à¤°à¤¾à¤–णà¥à¤¡~ओड़िशा~करà¥à¤¨à¤¾à¤Ÿà¤•~केरल~गà¥à¤œà¤°à¤¾à¤¤~गोआ~चंडीगढ़~छतà¥à¤¤à¥€à¤¸à¤—ढ़~जमà¥à¤®à¥‚ और कशà¥à¤®à¥€à¤°~à¤à¤¾à¤°à¤–णà¥à¤¡~तमिल नाडà¥~तेलंगाना~तà¥à¤°à¤¿à¤ªà¥à¤°à¤¾~दमन और दीव~दादरा और नगर हवेली~दिलà¥à¤²à¥€~नागालैंड~पंजाब~पशà¥à¤šà¤¿à¤® बंगाल~पांडिचेरी~बिहार~मणिपà¥à¤°~मधà¥à¤¯ पà¥à¤°à¤¦à¥‡à¤¶~महाराषà¥à¤Ÿà¥à¤°~मिजोरम~मेघालय~राजसà¥à¤¥à¤¾à¤¨~लकà¥à¤·à¤¦à¥à¤µà¥€à¤ª~सिकà¥à¤•à¤¿à¤®~हरियाणा~हिमाचल पà¥à¤°à¤¦à¥‡à¤¶", "sub_zips": "744~79[0-2]~78~5[0-3]~2[0-35-8]|24[0-7]|26[12]~24[46-9]|254|26[23]~7[5-7]~5[4-9]|53[7-9]~6[7-9]|6010|607008|777~3[6-9]~403~16|1440[3-9]~49~1[89]~81[4-9]|82|83[0-5]~6[0-6]|536~5[0-3]~799~396~396~11~79[78]~1[456]~7[0-4]~60[579]~8[0-5]~79[56]~4[5-8]|490~4[0-4]~796~79[34]~3[0-4]~682~737|750~1[23]~17", "zip": "\\d{6}", "zip_name_type": "pin", "zipex": "110034,110001"}, + "data/IO": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/IO", "key": "IO", "name": "BRITISH INDIAN OCEAN TERRITORY", "require": "ACZ", "upper": "CZ", "zip": "BBND 1ZZ", "zipex": "BBND 1ZZ"}, + "data/IQ": {"fmt": "%O%n%N%n%A%n%C, %S%n%Z", "id": "data/IQ", "key": "IQ", "name": "IRAQ", "require": "ACS", "upper": "CS", "zip": "\\d{5}", "zipex": "31001"}, + "data/IR": {"fmt": "%O%n%N%n%S%n%C, %D%n%A%n%Z", "id": "data/IR", "key": "IR", "lang": "fa", "languages": "fa", "name": "IRAN", "sub_isoids": "01~02~03~04~32~05~06~07~08~29~30~31~10~11~12~13~14~28~26~16~15~17~18~27~19~20~21~22~23~24~25", "sub_keys": "استان آذربایجان شرقی~استان آذربایجان غربی~استان اردبیل~استان اصÙهان~استان البرز~استان ایلام~استان بوشهر~استان تهران~استان چهارمØال Ùˆ بختیاری~استان خراسان جنوبی~استان خراسان رضوی~استان خراسان شمالی~استان خوزستان~استان زنجان~استان سمنان~استان سیستان Ùˆ بلوچستان~استان Ùارس~استان قزوین~استان قم~استان کردستان~استان کرمان~استان کرمانشاه~استان کهگیلویه Ùˆ بویراØمد~استان گلستان~استان گیلان~استان لرستان~استان مازندران~استان مرکزی~استان هرمزگان~استان همدان~استان یزد", "sub_lnames": "East Azerbaijan Province~West Azerbaijan Province~Ardabil Province~Isfahan Province~Alborz Province~Ilam Province~Bushehr Province~Tehran Province~Chaharmahal and Bakhtiari Province~South Khorasan Province~Razavi Khorasan Province~North Khorasan Province~Khuzestan Province~Zanjan Province~Semnan Province~Sistan and Baluchestan Province~Fars Province~Qazvin Province~Qom Province~Kurdistan Province~Kerman Province~Kermanshah Province~Kohgiluyeh and Boyer-Ahmad Province~Golestan Province~Gilan Province~Lorestan Province~Mazandaran Province~Markazi Province~Hormozgan Province~Hamadan Province~Yazd Province", "sublocality_name_type": "neighborhood", "zip": "\\d{5}-?\\d{5}", "zipex": "11936-12345"}, + "data/IS": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/IS", "key": "IS", "name": "ICELAND", "posturl": "http://www.postur.is/einstaklingar/posthus/postnumer/", "zip": "\\d{3}", "zipex": "320,121,220,110"}, + "data/IT": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/IT", "key": "IT", "lang": "it", "languages": "it", "name": "ITALY", "posturl": "http://www.poste.it/online/cercacap/", "require": "ACSZ", "sub_isoids": "AG~AL~AN~AO~AR~AP~AT~AV~BA~BT~BL~BN~BG~BI~BO~BZ~BS~BR~CA~CL~CB~CI~CE~CT~CZ~CH~CO~CS~CR~KR~CN~EN~FM~FE~FI~FG~FC~FR~GE~GO~GR~IM~IS~AQ~SP~LT~LE~LC~LI~LO~LU~MC~MN~MS~MT~VS~ME~MI~MO~MB~NA~NO~NU~OG~OT~OR~PD~PA~PR~PV~PG~PU~PE~PC~PI~PT~PN~PZ~PO~RG~RA~RC~RE~RI~RN~RM~RO~SA~SS~SV~SI~SR~SO~TA~TE~TR~TO~TP~TN~TV~TS~UD~VA~VE~VB~VC~VR~VV~VI~VT", "sub_keys": "AG~AL~AN~AO~AR~AP~AT~AV~BA~BT~BL~BN~BG~BI~BO~BZ~BS~BR~CA~CL~CB~CI~CE~CT~CZ~CH~CO~CS~CR~KR~CN~EN~FM~FE~FI~FG~FC~FR~GE~GO~GR~IM~IS~AQ~SP~LT~LE~LC~LI~LO~LU~MC~MN~MS~MT~VS~ME~MI~MO~MB~NA~NO~NU~OG~OT~OR~PD~PA~PR~PV~PG~PU~PE~PC~PI~PT~PN~PZ~PO~RG~RA~RC~RE~RI~RN~RM~RO~SA~SS~SV~SI~SR~SO~TA~TE~TR~TO~TP~TN~TV~TS~UD~VA~VE~VB~VC~VR~VV~VI~VT", "sub_names": "Agrigento~Alessandria~Ancona~Aosta~Arezzo~Ascoli Piceno~Asti~Avellino~Bari~Barletta-Andria-Trani~Belluno~Benevento~Bergamo~Biella~Bologna~Bolzano~Brescia~Brindisi~Cagliari~Caltanissetta~Campobasso~Carbonia-Iglesias~Caserta~Catania~Catanzaro~Chieti~Como~Cosenza~Cremona~Crotone~Cuneo~Enna~Fermo~Ferrara~Firenze~Foggia~Forlì-Cesena~Frosinone~Genova~Gorizia~Grosseto~Imperia~Isernia~L'Aquila~La Spezia~Latina~Lecce~Lecco~Livorno~Lodi~Lucca~Macerata~Mantova~Massa-Carrara~Matera~Medio Campidano~Messina~Milano~Modena~Monza e Brianza~Napoli~Novara~Nuoro~Ogliastra~Olbia-Tempio~Oristano~Padova~Palermo~Parma~Pavia~Perugia~Pesaro e Urbino~Pescara~Piacenza~Pisa~Pistoia~Pordenone~Potenza~Prato~Ragusa~Ravenna~Reggio Calabria~Reggio Emilia~Rieti~Rimini~Roma~Rovigo~Salerno~Sassari~Savona~Siena~Siracusa~Sondrio~Taranto~Teramo~Terni~Torino~Trapani~Trento~Treviso~Trieste~Udine~Varese~Venezia~Verbano-Cusio-Ossola~Vercelli~Verona~Vibo Valentia~Vicenza~Viterbo", "sub_zips": "92~15~60~11~52~63~14~83~70~76[01]~32~82~24~13[89]~40~39~25~72~0912[1-9]|0913[0-4]|0901[0289]|0902[03468]|0903[0234]|0904|0803[035]|08043~93~860[1-4]|86100~0901[013-7]~81~95~88[01]~66~22~87~26[01]~88[89]~12|18025~94~638|63900~44~50~71~47[015]~03~16~34[01]7~58~18~860[7-9]|86170~67~19~04~73~23[89]~57~26[89]~55~62~46~54~75~0902[012579]|0903[015-9]|09040~98~20~41~208|20900~80~28[01]~080[1-3]|08100~08037|0804[024-9]~08020|0702|0703[08]~090[7-9]|09170|0801[039]|0803[04]~35~90~43~27~06~61~65~29~56~51~330[7-9]|33170~85~59~97~48~89[01]~42~02~47[89]~00~45~84~070[14]|0703[0-79]|07100~17|12071~53~96~23[01]~74~64~05~10~91~38~31~3401|341[0-689]|34062~330[1-5]|33100~21~30~28[89]~13[01]~37~89[89]~36~01", "upper": "CS", "zip": "\\d{5}", "zipex": "00144,47037,39049"}, + "data/JE": {"fmt": "%N%n%O%n%A%n%C%nJERSEY%n%Z", "id": "data/JE", "key": "JE", "name": "CHANNEL ISLANDS", "posturl": "http://www.jerseypost.com/tools/postcode-address-finder/", "require": "ACZ", "upper": "CZ", "zip": "JE\\d[\\dA-Z]? ?\\d[ABD-HJLN-UW-Z]{2}", "zipex": "JE1 1AA,JE2 2BT"}, + "data/JM": {"fmt": "%N%n%O%n%A%n%C%n%S %X", "id": "data/JM", "key": "JM", "lang": "en", "languages": "en", "name": "JAMAICA", "require": "ACS", "state_name_type": "parish", "sub_isoids": "13~09~01~12~04~02~06~14~11~08~05~03~07~10", "sub_keys": "Clarendon~Hanover~Kingston~Manchester~Portland~St. Andrew~St. Ann~St. Catherine~St. Elizabeth~St. James~St. Mary~St. Thomas~Trelawny~Westmoreland"}, + "data/JO": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/JO", "key": "JO", "name": "JORDAN", "zip": "\\d{5}", "zipex": "11937,11190"}, + "data/JP": {"fmt": "〒%Z%n%S%n%A%n%O%n%N", "id": "data/JP", "key": "JP", "lang": "ja", "languages": "ja", "lfmt": "%N%n%O%n%A, %S%n%Z", "name": "JAPAN", "posturl": "http://www.post.japanpost.jp/zipcode/", "require": "ASZ", "state_name_type": "prefecture", "sub_isoids": "01~02~03~04~05~06~07~08~09~10~11~12~13~14~15~16~17~18~19~20~21~22~23~24~25~26~27~28~29~30~31~32~33~34~35~36~37~38~39~40~41~42~43~44~45~46~47", "sub_keys": "北海é“~é’森県~岩手県~宮城県~秋田県~山形県~ç¦å³¶çœŒ~茨城県~æ ƒæœ¨çœŒ~群馬県~埼玉県~åƒè‘‰çœŒ~æ±äº¬éƒ½~神奈å·çœŒ~新潟県~富山県~石å·çœŒ~ç¦äº•çœŒ~山梨県~長野県~å²é˜œçœŒ~é™å²¡çœŒ~愛知県~三é‡çœŒ~滋賀県~京都府~大阪府~兵庫県~奈良県~å’ŒæŒå±±çœŒ~é³¥å–県~å³¶æ ¹çœŒ~岡山県~広島県~å±±å£çœŒ~徳島県~香å·çœŒ~愛媛県~高知県~ç¦å²¡çœŒ~ä½è³€çœŒ~長崎県~熊本県~大分県~宮崎県~鹿å…島県~沖縄県", "sub_lnames": "Hokkaido~Aomori~Iwate~Miyagi~Akita~Yamagata~Fukushima~Ibaraki~Tochigi~Gunma~Saitama~Chiba~Tokyo~Kanagawa~Niigata~Toyama~Ishikawa~Fukui~Yamanashi~Nagano~Gifu~Shizuoka~Aichi~Mie~Shiga~Kyoto~Osaka~Hyogo~Nara~Wakayama~Tottori~Shimane~Okayama~Hiroshima~Yamaguchi~Tokushima~Kagawa~Ehime~Kochi~Fukuoka~Saga~Nagasaki~Kumamoto~Oita~Miyazaki~Kagoshima~Okinawa", "sub_zips": "0[4-9]|00[1-7]~03|018~02~98~01~99~9[67]~3[01]~32|311|349~37|38[49]~3[3-6]~2[6-9]~1[0-8]|19[0-8]|20~2[1-5]|199~9[45]|389~93~92|939~91|922~40~3[89]|949~50~4[1-9]~4[4-9]|431~51|498|647~52~6[0-2]|520~5[3-9]|618|630~6[5-7]|563~63|64[78]~64|519~68~69|68[45]~7[01]~7[23]~7[45]~77~76~79~78~8[0-3]|871~84~85|81[17]|848~86~87|839~88~89~90", "upper": "S", "zip": "\\d{3}-?\\d{4}", "zipex": "154-0023,350-1106,951-8073,112-0001,208-0032,231-0012"}, + "data/KE": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/KE", "key": "KE", "name": "KENYA", "zip": "\\d{5}", "zipex": "20100,00100"}, + "data/KG": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/KG", "key": "KG", "name": "KYRGYZSTAN", "zip": "\\d{6}", "zipex": "720001"}, + "data/KH": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/KH", "key": "KH", "name": "CAMBODIA", "zip": "\\d{5}", "zipex": "12203,14206,12000"}, + "data/KI": {"fmt": "%N%n%O%n%A%n%S%n%C", "id": "data/KI", "key": "KI", "name": "KIRIBATI", "state_name_type": "island", "upper": "ACNOS"}, + "data/KM": {"id": "data/KM", "key": "KM", "name": "COMOROS", "upper": "AC"}, + "data/KN": {"fmt": "%N%n%O%n%A%n%C, %S", "id": "data/KN", "key": "KN", "lang": "en", "languages": "en", "name": "SAINT KITTS AND NEVIS", "require": "ACS", "state_name_type": "island", "sub_isoids": "N~K", "sub_keys": "Nevis~St. Kitts"}, + "data/KP": {"fmt": "%Z%n%S%n%C%n%A%n%O%n%N", "id": "data/KP", "key": "KP", "lang": "ko", "languages": "ko", "lfmt": "%N%n%O%n%A%n%C%n%S, %Z", "name": "NORTH KOREA", "sub_isoids": "07~13~10~04~02~03~01~08~09~05~06", "sub_keys": "ê°•ì›ë„~ë¼ì„ 특별시~량강ë„~ìžê°•ë„~í‰ì•ˆ 남ë„~í‰ì•ˆ ë¶ë„~í‰ì–‘ ì§í• ì‹œ~함경 남ë„~함경 ë¶ë„~황해남ë„~황해ë¶ë„", "sub_lnames": "Kangwon~Rason~Ryanggang~Chagang~South Pyongan~North Pyongan~Pyongyang~South Hamgyong~North Hamgyong~South Hwanghae~North Hwanghae"}, + "data/KR": {"fmt": "%S %C%D%n%A%n%O%n%N%n%Z", "id": "data/KR", "key": "KR", "lang": "ko", "languages": "ko", "lfmt": "%N%n%O%n%A%n%D%n%C%n%S%n%Z", "name": "SOUTH KOREA", "posturl": "http://www.epost.go.kr/search/zipcode/search5.jsp", "require": "ACSZ", "state_name_type": "do_si", "sub_isoids": "42~41~48~47~29~27~30~26~11~50~31~28~46~45~49~44~43", "sub_keys": "ê°•ì›ë„~경기ë„~ê²½ìƒë‚¨ë„~ê²½ìƒë¶ë„~광주광ì—ì‹œ~대구광ì—ì‹œ~ëŒ€ì „ê´‘ì—ì‹œ~부산광ì—ì‹œ~서울특별시~세종특별ìžì¹˜ì‹œ~울산광ì—ì‹œ~ì¸ì²œê´‘ì—ì‹œ~ì „ë¼ë‚¨ë„~ì „ë¼ë¶ë„~ì œì£¼íŠ¹ë³„ìžì¹˜ë„~충ì²ë‚¨ë„~충ì²ë¶ë„", "sub_lnames": "Gangwon-do~Gyeonggi-do~Gyeongsangnam-do~Gyeongsangbuk-do~Gwangju~Daegu~Daejeon~Busan~Seoul~Sejong~Ulsan~Incheon~Jeollanam-do~Jeollabuk-do~Jeju-do~Chungcheongnam-do~Chungcheongbuk-do", "sub_mores": "true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true", "sub_names": "ê°•ì›~경기~경남~ê²½ë¶~광주~대구~ëŒ€ì „~부산~서울~세종~울산~ì¸ì²œ~ì „ë‚¨~ì „ë¶~ì œì£¼~충남~충ë¶", "sub_zipexs": "25627~12410~53286~38540~62394~42456~34316~46706~06321~30065~44782~23024~59222~56445~63563~32832~28006", "sub_zips": "2[456]\\d{2}~1[0-8]\\d{2}~5[0-3]\\d{2}~(?:3[6-9]|40)\\d{2}~6[12]\\d{2}~4[12]\\d{2}~3[45]\\d{2}~4[6-9]\\d{2}~0[1-8]\\d{2}~30[01]\\d~4[45]\\d{2}~2[1-3]\\d{2}~5[7-9]\\d{2}~5[4-6]\\d{2}~63[0-356]\\d~3[1-3]\\d{2}~2[789]\\d{2}", "sublocality_name_type": "district", "upper": "Z", "zip": "\\d{5}", "zipex": "03051"}, + "data/KW": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/KW", "key": "KW", "name": "KUWAIT", "zip": "\\d{5}", "zipex": "54541,54551,54404,13009"}, + "data/KY": {"fmt": "%N%n%O%n%A%n%S %Z", "id": "data/KY", "key": "KY", "lang": "en", "languages": "en", "name": "CAYMAN ISLANDS", "posturl": "http://www.caymanpost.gov.ky/", "require": "AS", "state_name_type": "island", "sub_keys": "Cayman Brac~Grand Cayman~Little Cayman", "zip": "KY\\d-\\d{4}", "zipex": "KY1-1100,KY1-1702,KY2-2101"}, + "data/KZ": {"fmt": "%Z%n%S%n%C%n%A%n%O%n%N", "id": "data/KZ", "key": "KZ", "name": "KAZAKHSTAN", "zip": "\\d{6}", "zipex": "040900,050012"}, + "data/LA": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/LA", "key": "LA", "name": "LAO (PEOPLE'S DEM. REP.)", "zip": "\\d{5}", "zipex": "01160,01000"}, + "data/LB": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/LB", "key": "LB", "name": "LEBANON", "zip": "(?:\\d{4})(?: ?(?:\\d{4}))?", "zipex": "2038 3054,1107 2810,1000"}, + "data/LC": {"id": "data/LC", "key": "LC", "name": "SAINT LUCIA"}, + "data/LI": {"fmt": "%O%n%N%n%A%nFL-%Z %C", "id": "data/LI", "key": "LI", "name": "LIECHTENSTEIN", "postprefix": "FL-", "posturl": "http://www.post.ch/db/owa/pv_plz_pack/pr_main", "require": "ACZ", "zip": "948[5-9]|949[0-8]", "zipex": "9496,9491,9490,9485"}, + "data/LK": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/LK", "key": "LK", "name": "SRI LANKA", "posturl": "http://www.slpost.gov.lk/", "zip": "\\d{5}", "zipex": "20000,00100"}, + "data/LR": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/LR", "key": "LR", "name": "LIBERIA", "zip": "\\d{4}", "zipex": "1000"}, + "data/LS": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/LS", "key": "LS", "name": "LESOTHO", "zip": "\\d{3}", "zipex": "100"}, + "data/LT": {"fmt": "%O%n%N%n%A%nLT-%Z %C", "id": "data/LT", "key": "LT", "name": "LITHUANIA", "postprefix": "LT-", "posturl": "http://www.post.lt/lt/?id=316", "zip": "\\d{5}", "zipex": "04340,03500"}, + "data/LU": {"fmt": "%O%n%N%n%A%nL-%Z %C", "id": "data/LU", "key": "LU", "name": "LUXEMBOURG", "postprefix": "L-", "posturl": "https://www.post.lu/fr/grandes-entreprises/solutions-postales/rechercher-un-code-postal", "require": "ACZ", "zip": "\\d{4}", "zipex": "4750,2998"}, + "data/LV": {"fmt": "%N%n%O%n%A%n%C, %Z", "id": "data/LV", "key": "LV", "name": "LATVIA", "posturl": "http://www.pasts.lv/lv/uzzinas/nodalas/", "zip": "LV-\\d{4}", "zipex": "LV-1073,LV-1000"}, + "data/LY": {"id": "data/LY", "key": "LY", "name": "LIBYA"}, + "data/MA": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/MA", "key": "MA", "name": "MOROCCO", "zip": "\\d{5}", "zipex": "53000,10000,20050,16052"}, + "data/MC": {"fmt": "%N%n%O%n%A%nMC-%Z %C %X", "id": "data/MC", "key": "MC", "name": "MONACO", "postprefix": "MC-", "zip": "980\\d{2}", "zipex": "98000,98020,98011,98001"}, + "data/MD": {"fmt": "%N%n%O%n%A%nMD-%Z %C", "id": "data/MD", "key": "MD", "name": "Rep. MOLDOVA", "postprefix": "MD-", "zip": "\\d{4}", "zipex": "2012,2019"}, + "data/ME": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/ME", "key": "ME", "name": "MONTENEGRO", "zip": "8\\d{4}", "zipex": "81257,81258,81217,84314,85366"}, + "data/MF": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/MF", "key": "MF", "name": "SAINT MARTIN", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "ACX", "zip": "9[78][01]\\d{2}", "zipex": "97100"}, + "data/MG": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/MG", "key": "MG", "name": "MADAGASCAR", "zip": "\\d{3}", "zipex": "501,101"}, + "data/MH": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/MH", "key": "MH", "name": "MARSHALL ISLANDS", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACSZ", "state_name_type": "state", "upper": "ACNOS", "zip": "(969[67]\\d)(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "96960,96970"}, + "data/MK": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/MK", "key": "MK", "name": "MACEDONIA", "zip": "\\d{4}", "zipex": "1314,1321,1443,1062"}, + "data/ML": {"id": "data/ML", "key": "ML", "name": "MALI"}, + "data/MM": {"fmt": "%N%n%O%n%A%n%C, %Z", "id": "data/MM", "key": "MM", "name": "MYANMAR", "zip": "\\d{5}", "zipex": "11181"}, + "data/MN": {"fmt": "%N%n%O%n%A%n%C%n%S %Z", "id": "data/MN", "key": "MN", "name": "MONGOLIA", "posturl": "http://www.zipcode.mn/", "zip": "\\d{5}", "zipex": "65030,65270"}, + "data/MO": {"fmt": "%A%n%O%n%N", "id": "data/MO", "key": "MO", "lfmt": "%N%n%O%n%A", "name": "MACAO", "require": "A"}, + "data/MP": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/MP", "key": "MP", "name": "NORTHERN MARIANA ISLANDS", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACSZ", "state_name_type": "state", "upper": "ACNOS", "zip": "(9695[012])(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "96950,96951,96952"}, + "data/MQ": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/MQ", "key": "MQ", "name": "MARTINIQUE", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "ACX", "zip": "9[78]2\\d{2}", "zipex": "97220"}, + "data/MR": {"id": "data/MR", "key": "MR", "name": "MAURITANIA", "upper": "AC"}, + "data/MS": {"id": "data/MS", "key": "MS", "name": "MONTSERRAT"}, + "data/MT": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/MT", "key": "MT", "name": "MALTA", "posturl": "http://postcodes.maltapost.com/", "upper": "CZ", "zip": "[A-Z]{3} ?\\d{2,4}", "zipex": "NXR 01,ZTN 05,GPO 01,BZN 1130,SPB 6031,VCT 1753"}, + "data/MU": {"fmt": "%N%n%O%n%A%n%Z%n%C", "id": "data/MU", "key": "MU", "name": "MAURITIUS", "upper": "CZ", "zip": "\\d{3}(?:\\d{2}|[A-Z]{2}\\d{3})", "zipex": "42602"}, + "data/MV": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/MV", "key": "MV", "name": "MALDIVES", "posturl": "http://www.maldivespost.com/?lid=10", "zip": "\\d{5}", "zipex": "20026"}, + "data/MW": {"fmt": "%N%n%O%n%A%n%C %X", "id": "data/MW", "key": "MW", "name": "MALAWI"}, + "data/MX": {"fmt": "%N%n%O%n%A%n%D%n%Z %C, %S", "id": "data/MX", "key": "MX", "lang": "es", "languages": "es", "name": "MEXICO", "posturl": "http://www.correosdemexico.gob.mx/ServiciosLinea/Paginas/ccpostales.aspx", "require": "ACZ", "state_name_type": "state", "sub_isoids": "AGU~BCN~BCS~CAM~CHP~CHH~CMX~COA~COL~DUR~MEX~GUA~GRO~HID~JAL~MIC~MOR~NAY~NLE~OAX~PUE~QUE~ROO~SLP~SIN~SON~TAB~TAM~TLA~VER~YUC~ZAC", "sub_keys": "Ags.~B.C.~B.C.S.~Camp.~Chis.~Chih.~CDMX~Coah.~Col.~Dgo.~Méx.~Gto.~Gro.~Hgo.~Jal.~Mich.~Mor.~Nay.~N.L.~Oax.~Pue.~Qro.~Q.R.~S.L.P.~Sin.~Son.~Tab.~Tamps.~Tlax.~Ver.~Yuc.~Zac.", "sub_names": "Aguascalientes~Baja California~Baja California Sur~Campeche~Chiapas~Chihuahua~Ciudad de México~Coahuila de Zaragoza~Colima~Durango~Estado de México~Guanajuato~Guerrero~Hidalgo~Jalisco~Michoacán~Morelos~Nayarit~Nuevo León~Oaxaca~Puebla~Querétaro~Quintana Roo~San Luis PotosÃ~Sinaloa~Sonora~Tabasco~Tamaulipas~Tlaxcala~Veracruz~Yucatán~Zacatecas", "sub_zipexs": "20000,20999~21000,22999~23000,23999~24000,24999~29000,30999~31000,33999~00000,16999~25000,27999~28000,28999~34000,35999~50000,57999~36000,38999~39000,41999~42000,43999~44000,49999~58000,61999~62000,62999~63000,63999~64000,67999~68000,71999~72000,75999~76000,76999~77000,77999~78000,79999~80000,82999~83000,85999~86000,86999~87000,89999~90000,90999~91000,96999~97000,97999~98000,99999", "sub_zips": "20~2[12]~23~24~29|30~3[1-3]~0|1[0-6]~2[5-7]~28~3[45]~5[0-7]~3[6-8]~39|4[01]~4[23]~4[4-9]~5[89]|6[01]~62~63~6[4-7]~6[89]|7[01]~7[2-5]~76~77~7[89]~8[0-2]~8[3-5]~86~8[7-9]~90~9[1-6]~97~9[89]", "sublocality_name_type": "neighborhood", "upper": "CSZ", "zip": "\\d{5}", "zipex": "02860,77520,06082"}, + "data/MY": {"fmt": "%N%n%O%n%A%n%D%n%Z %C%n%S", "id": "data/MY", "key": "MY", "lang": "ms", "languages": "ms", "name": "MALAYSIA", "posturl": "http://www.pos.com.my", "require": "ACZ", "state_name_type": "state", "sub_isoids": "01~02~03~14~15~04~05~06~08~09~07~16~12~13~10~11", "sub_keys": "Johor~Kedah~Kelantan~Kuala Lumpur~Labuan~Melaka~Negeri Sembilan~Pahang~Perak~Perlis~Pulau Pinang~Putrajaya~Sabah~Sarawak~Selangor~Terengganu", "sub_zipexs": "79000,86999~05000,09999,34950~15000,18599~50000,60000~87000,87999~75000,78399~70000,73599~25000,28999,39000,49000,69000~30000,36899,39000~01000,02799~10000,14999~62000,62999~88000,91999~93000,98999~40000,48999,63000,68199~20000,24999", "sub_zips": "79|8[0-6]~0[5-9]|34950~1[5-9]~5|60~87~7[5-8]~7[0-4]~2[5-8]|[346]9~3[0-6]|39000~0[12]~1[0-4]~62~8[89]|9[01]~9[3-8]~4[0-8]|6[3-8]~2[0-4]", "sublocality_name_type": "village_township", "upper": "CS", "zip": "\\d{5}", "zipex": "43000,50754,88990,50670"}, + "data/MZ": {"fmt": "%N%n%O%n%A%n%Z %C%S", "id": "data/MZ", "key": "MZ", "lang": "pt", "languages": "pt", "name": "MOZAMBIQUE", "sub_isoids": "P~MPM~G~I~B~L~N~A~S~T~Q", "sub_keys": "Cabo Delgado~Cidade de Maputo~Gaza~Inhambane~Manica~Maputo~Nampula~Niassa~Sofala~Tete~Zambezia", "zip": "\\d{4}", "zipex": "1102,1119,3212"}, + "data/NA": {"id": "data/NA", "key": "NA", "name": "NAMIBIA"}, + "data/NC": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/NC", "key": "NC", "name": "NEW CALEDONIA", "posturl": "http://poste.opt.nc/index.php?option=com_content&view=article&id=80&Itemid=131", "require": "ACZ", "upper": "ACX", "zip": "988\\d{2}", "zipex": "98814,98800,98810"}, + "data/NE": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/NE", "key": "NE", "name": "NIGER", "zip": "\\d{4}", "zipex": "8001"}, + "data/NF": {"fmt": "%O%n%N%n%A%n%C %S %Z", "id": "data/NF", "key": "NF", "name": "NORFOLK ISLAND", "upper": "CS", "zip": "2899", "zipex": "2899"}, + "data/NG": {"fmt": "%N%n%O%n%A%n%D%n%C %Z%n%S", "id": "data/NG", "key": "NG", "lang": "en", "languages": "en", "name": "NIGERIA", "posturl": "http://www.nigeriapostcodes.com/", "state_name_type": "state", "sub_isoids": "AB~AD~AK~AN~BA~BY~BE~BO~CR~DE~EB~ED~EK~EN~FC~GO~IM~JI~KD~KN~KT~KE~KO~KW~LA~NA~NI~OG~ON~OS~OY~PL~RI~SO~TA~YO~ZA", "sub_keys": "Abia~Adamawa~Akwa Ibom~Anambra~Bauchi~Bayelsa~Benue~Borno~Cross River~Delta~Ebonyi~Edo~Ekiti~Enugu~Federal Capital Territory~Gombe~Imo~Jigawa~Kaduna~Kano~Katsina~Kebbi~Kogi~Kwara~Lagos~Nasarawa~Niger~Ogun State~Ondo~Osun~Oyo~Plateau~Rivers~Sokoto~Taraba~Yobe~Zamfara", "upper": "CS", "zip": "\\d{6}", "zipex": "930283,300001,931104"}, + "data/NI": {"fmt": "%N%n%O%n%A%n%Z%n%C, %S", "id": "data/NI", "key": "NI", "lang": "es", "languages": "es", "name": "NICARAGUA", "posturl": "http://www.correos.gob.ni/index.php/codigo-postal-2", "state_name_type": "department", "sub_isoids": "BO~CA~CI~CO~ES~GR~JI~LE~MD~MN~MS~MT~NS~AN~AS~SJ~RI", "sub_keys": "Boaco~Carazo~Chinandega~Chontales~Esteli~Granada~Jinotega~Leon~Madriz~Managua~Masaya~Matagalpa~Nueva Segovia~Raan~Raas~Rio San Juan~Rivas", "sub_zips": "5[12]~4[56]~2[5-7]~5[56]~3[12]~4[34]~6[56]~2[12]~3[45]~1[0-6]~4[12]~6[1-3]~3[7-9]~7[12]~8[1-3]~9[12]~4[78]", "upper": "CS", "zip": "\\d{5}", "zipex": "52000"}, + "data/NL": {"fmt": "%O%n%N%n%A%n%Z %C", "id": "data/NL", "key": "NL", "name": "NETHERLANDS", "posturl": "http://www.postnl.nl/voorthuis/", "require": "ACZ", "zip": "\\d{4} ?[A-Z]{2}", "zipex": "1234 AB,2490 AA"}, + "data/NO": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/NO", "key": "NO", "locality_name_type": "post_town", "name": "NORWAY", "posturl": "http://adressesok.posten.no/nb/postal_codes/search", "require": "ACZ", "zip": "\\d{4}", "zipex": "0025,0107,6631"}, + "data/NP": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/NP", "key": "NP", "name": "NEPAL", "posturl": "http://www.gpo.gov.np/Home/Postalcode", "zip": "\\d{5}", "zipex": "44601"}, + "data/NR": {"fmt": "%N%n%O%n%A%n%S", "id": "data/NR", "key": "NR", "lang": "en", "languages": "en", "name": "NAURU CENTRAL PACIFIC", "require": "AS", "state_name_type": "district", "sub_isoids": "01~02~03~04~05~06~07~08~09~10~11~12~13~14", "sub_keys": "Aiwo District~Anabar District~Anetan District~Anibare District~Baiti District~Boe District~Buada District~Denigomodu District~Ewa District~Ijuw District~Meneng District~Nibok District~Uaboe District~Yaren District"}, + "data/NU": {"id": "data/NU", "key": "NU", "name": "NIUE"}, + "data/NZ": {"fmt": "%N%n%O%n%A%n%D%n%C %Z", "id": "data/NZ", "key": "NZ", "name": "NEW ZEALAND", "posturl": "http://www.nzpost.co.nz/Cultures/en-NZ/OnlineTools/PostCodeFinder/", "require": "ACZ", "zip": "\\d{4}", "zipex": "6001,6015,6332,8252,1030"}, + "data/OM": {"fmt": "%N%n%O%n%A%n%Z%n%C", "id": "data/OM", "key": "OM", "name": "OMAN", "zip": "(?:PC )?\\d{3}", "zipex": "133,112,111"}, + "data/PA": {"fmt": "%N%n%O%n%A%n%C%n%S", "id": "data/PA", "key": "PA", "name": "PANAMA (REP.)", "upper": "CS"}, + "data/PE": {"fmt": "%N%n%O%n%A%n%C %Z%n%S", "id": "data/PE", "key": "PE", "lang": "es", "languages": "es", "locality_name_type": "district", "name": "PERU", "posturl": "http://www.serpost.com.pe/cpostal/codigo", "sub_isoids": "AMA~ANC~APU~ARE~AYA~CAJ~CAL~CUS~LIM~HUV~HUC~ICA~JUN~LAL~LAM~LOR~MDD~MOQ~LMA~PAS~PIU~PUN~SAM~TAC~TUM~UCA", "sub_keys": "Amazonas~Ãncash~ApurÃmac~Arequipa~Ayacucho~Cajamarca~Callao~Cuzco~Gobierno Regional de Lima~Huancavelica~Huánuco~Ica~JunÃn~La Libertad~Lambayeque~Loreto~Madre de Dios~Moquegua~Municipalidad Metropolitana de Lima~Pasco~Piura~Puno~San MartÃn~Tacna~Tumbes~Ucayali", "zip": "(?:LIMA \\d{1,2}|CALLAO 0?\\d)|[0-2]\\d{4}", "zipex": "LIMA 23,LIMA 42,CALLAO 2,02001"}, + "data/PF": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/PF", "key": "PF", "name": "FRENCH POLYNESIA", "require": "ACSZ", "state_name_type": "island", "upper": "CS", "zip": "987\\d{2}", "zipex": "98709"}, + "data/PG": {"fmt": "%N%n%O%n%A%n%C %Z %S", "id": "data/PG", "key": "PG", "name": "PAPUA NEW GUINEA", "require": "ACS", "zip": "\\d{3}", "zipex": "111"}, + "data/PH": {"fmt": "%N%n%O%n%A%n%D, %C%n%Z %S", "id": "data/PH", "key": "PH", "lang": "en", "languages": "en", "name": "PHILIPPINES", "posturl": "http://www.philpost.gov.ph/", "sub_isoids": "ABR~AGN~AGS~AKL~ALB~ANT~APA~AUR~BAS~BAN~BTN~BTG~BEN~BIL~BOH~BUK~BUL~CAG~CAN~CAS~CAM~CAP~CAT~CAV~CEB~COM~NCO~DAV~DAS~DVO~DAO~DIN~EAS~GUI~IFU~ILN~ILS~ILI~ISA~KAL~LUN~LAG~LAN~LAS~LEY~MAG~MAD~MAS~00~MDC~MDR~MSC~MSR~MOU~NEC~NER~NSA~NUE~NUV~PLW~PAM~PAN~QUE~QUI~RIZ~ROM~WSA~SAR~SIG~SOR~SCO~SLE~SUK~SLU~SUN~SUR~TAR~TAW~ZMB~ZAN~ZAS~ZSI", "sub_keys": "Abra~Agusan del Norte~Agusan del Sur~Aklan~Albay~Antique~Apayao~Aurora~Basilan~Bataan~Batanes~Batangas~Benguet~Biliran~Bohol~Bukidnon~Bulacan~Cagayan~Camarines Norte~Camarines Sur~Camiguin~Capiz~Catanduanes~Cavite~Cebu~Compostela Valley~Cotabato~Davao del Norte~Davao del Sur~Davao Occidental~Davao Oriental~Dinagat Islands~Eastern Samar~Guimaras~Ifugao~Ilocos Norte~Ilocos Sur~Iloilo~Isabela~Kalinga~La Union~Laguna~Lanao del Norte~Lanao del Sur~Leyte~Maguindanao~Marinduque~Masbate~Metro Manila~Mindoro Occidental~Mindoro Oriental~Misamis Occidental~Misamis Oriental~Mountain Province~Negros Occidental~Negros Oriental~Northern Samar~Nueva Ecija~Nueva Vizcaya~Palawan~Pampanga~Pangasinan~Quezon Province~Quirino~Rizal~Romblon~Samar~Sarangani~Siquijor~Sorsogon~South Cotabato~Southern Leyte~Sultan Kudarat~Sulu~Surigao del Norte~Surigao del Sur~Tarlac~Tawi-Tawi~Zambales~Zamboanga del Norte~Zamboanga del Sur~Zamboanga Sibuguey", "sub_zipexs": "2800,2826~8600,8611~8500,8513~5600,5616~4500,4517~5700,5717~3800,3806,3808~3200,3207~7300,7306~2100,2114~3900,3905~4200,4234~2600,2615~6543,6550~6300,6337~8700,8723~3000,3024~3500,3528~4600,4612~4400,4436~9100,9104~5800,5816~4800,4810~4100,4126~6000,6053~8800,8810~9400,9417~8100,8120~8000,8010~8015,8013~8200,8210~8426,8412~6800,6822~5044,5046~3600,3610~2900,2922~2700,2733~5000,5043~3300,3336~3807,3809,3814~2500,2520~4000,4033~9200,9223~9300,9321,9700,9716~6500,6542~9600,9619~4900,4905~5400,5421~~5100,5111~5200,5214~7200,7215~9000,9025~2616,2625~6100,6132~6200,6224~6400,6423~3100,3133~3700,3714~5300,5322~2000,2022~2400,2447~4300,4342~3400,3405~1850,1990~5500,5516~6700,6725~8015~6225,6230~4700,4715~9500,9513~6600,6613~9800,9811~7400,7416~8400,8425~8300,8319~2300,2318~7500,7509~2200,2213~7100,7124~7000,7043~7000,7043", "sub_zips": "28[0-2]~86[01]~85[01]~56[01]~45[01]~57[01]~380[0-68]~320~730~21[01]~390~42[0-3]~26(0|1[0-5])~65(4[3-9]|5)~63[0-3]~87[0-2]~30[0-2]~35[0-2]~46[01]~44[0-3]~910~58[01]~48[01]~41[0-2]~60[0-5]~88[01]~94[01]~81[0-2]~80[01]~801[1-5]~82[01]~84[12]~68[0-2]~504[4-6]~36[01]~29[0-2]~27[0-3]~50([0-3]|4[0-3])~33[0-3]~38(0[79]|1[0-4])~25[0-2]~40[0-3]~92[0-2]~9(3[0-2]|7[01])~65([0-3]|4[0-2])~96[01]~490~54[0-2]~~51[01]~52[01]~72[01]~90[0-2]~26(1[6-9]|2[0-5])~61[0-3]~62[0-2]~64[0-2]~31[0-3]~37[01]~53[0-2]~20[0-2]~24[0-4]~43[0-4]~340~1[89]~55[01]~67[0-2]~8015~62(2[5-9]|30)~47[01]~95[01]~66[10]~98[01]~74[01]~84[0-2]~83[01]~23[01]~750~22[01]~71[0-2]~70[0-4]~70[0-4]", "zip": "\\d{4}", "zipex": "1008,1050,1135,1207,2000,1000"}, + "data/PK": {"fmt": "%N%n%O%n%A%n%C-%Z", "id": "data/PK", "key": "PK", "name": "PAKISTAN", "posturl": "http://www.pakpost.gov.pk/postcode.php", "zip": "\\d{5}", "zipex": "44000"}, + "data/PL": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/PL", "key": "PL", "name": "POLAND", "posturl": "http://kody.poczta-polska.pl/", "require": "ACZ", "zip": "\\d{2}-\\d{3}", "zipex": "00-950,05-470,48-300,32-015,00-940"}, + "data/PM": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/PM", "key": "PM", "name": "ST. PIERRE AND MIQUELON", "require": "ACZ", "upper": "ACX", "zip": "9[78]5\\d{2}", "zipex": "97500"}, + "data/PN": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/PN", "key": "PN", "name": "PITCAIRN", "require": "ACZ", "upper": "CZ", "zip": "PCRN 1ZZ", "zipex": "PCRN 1ZZ"}, + "data/PR": {"fmt": "%N%n%O%n%A%n%C PR %Z", "id": "data/PR", "key": "PR", "name": "PUERTO RICO", "postprefix": "PR ", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACZ", "upper": "ACNO", "zip": "(00[679]\\d{2})(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "00930"}, + "data/PT": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/PT", "key": "PT", "name": "PORTUGAL", "posturl": "http://www.ctt.pt/feapl_2/app/open/tools.jspx?tool=1", "require": "ACZ", "zip": "\\d{4}-\\d{3}", "zipex": "2725-079,1250-096,1201-950,2860-571,1208-148"}, + "data/PW": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/PW", "key": "PW", "name": "PALAU", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACSZ", "state_name_type": "state", "upper": "ACNOS", "zip": "(969(?:39|40))(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "96940"}, + "data/PY": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/PY", "key": "PY", "name": "PARAGUAY", "zip": "\\d{4}", "zipex": "1536,1538,1209"}, + "data/QA": {"id": "data/QA", "key": "QA", "name": "QATAR", "upper": "AC"}, + "data/RE": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/RE", "key": "RE", "name": "REUNION", "posturl": "http://www.laposte.fr/Particulier/Utiliser-nos-outils-pratiques/Outils-et-documents/Trouvez-un-code-postal", "require": "ACZ", "upper": "ACX", "zip": "9[78]4\\d{2}", "zipex": "97400"}, + "data/RO": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/RO", "key": "RO", "name": "ROMANIA", "posturl": "http://www.posta-romana.ro/zip_codes", "upper": "AC", "zip": "\\d{6}", "zipex": "060274,061357,200716"}, + "data/RS": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/RS", "key": "RS", "name": "REPUBLIC OF SERBIA", "posturl": "http://www.posta.rs/struktura/lat/aplikacije/pronadji/nadji-postu.asp", "zip": "\\d{5,6}", "zipex": "106314"}, + "data/RU": {"fmt": "%N%n%O%n%A%n%C%n%S%n%Z", "id": "data/RU", "key": "RU", "lang": "ru", "languages": "ru", "lfmt": "%N%n%O%n%A%n%C%n%S%n%Z", "name": "RUSSIAN FEDERATION", "posturl": "http://info.russianpost.ru/servlet/department", "require": "ACSZ", "state_name_type": "oblast", "sub_isoids": "ALT~AMU~ARK~AST~BEL~BRY~VLA~VGG~VLG~VOR~YEV~ZAB~IVA~IRK~KB~KGD~KLU~KAM~KC~KEM~KIR~KOS~KDA~KYA~KGN~KRS~LEN~LIP~MAG~MOW~MOS~MUR~NEN~NIZ~NGR~NVS~OMS~ORE~ORL~PNZ~PER~PRI~PSK~AD~AL~BA~BU~DA~IN~KL~KR~KO~~ME~MO~SA~SE~TA~TY~UD~KK~ROS~RYA~SAM~SPE~SAR~SAK~SVE~~SMO~STA~TAM~TVE~TOM~TUL~TYU~ULY~KHA~KHM~CHE~CE~CU~CHU~YAN~YAR", "sub_keys": "ÐлтайÑкий край~ÐмурÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐрхангельÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐÑтраханÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~БелгородÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~БрÑнÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВладимирÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВолгоградÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВологодÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВоронежÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЕврейÑÐºÐ°Ñ Ð°Ð²Ñ‚Ð¾Ð½Ð¾Ð¼Ð½Ð°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЗабайкальÑкий край~ИвановÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ИркутÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Кабардино-БалкарÑÐºÐ°Ñ Ð ÐµÑпублика~КалининградÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КалужÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КамчатÑкий край~Карачаево-ЧеркеÑÑÐºÐ°Ñ Ð ÐµÑпублика~КемеровÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КировÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КоÑтромÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КраÑнодарÑкий край~КраÑноÑÑ€Ñкий край~КурганÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КурÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЛенинградÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Ð›Ð¸Ð¿ÐµÑ†ÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~МагаданÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~МоÑква~МоÑковÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~МурманÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Ðенецкий автономный округ~ÐижегородÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐовгородÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐовоÑибирÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ОмÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ОренбургÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ОрловÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ПензенÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ПермÑкий край~ПриморÑкий край~ПÑковÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~РеÑпублика ÐдыгеÑ~РеÑпублика Ðлтай~РеÑпублика БашкортоÑтан~РеÑпублика БурÑтиÑ~РеÑпублика ДагеÑтан~РеÑпублика ИнгушетиÑ~РеÑпублика КалмыкиÑ~РеÑпублика КарелиÑ~РеÑпублика Коми~Ðвтономна РеÑпубліка Крим~РеÑпублика Марий Ðл~РеÑпублика МордовиÑ~РеÑпублика Саха (ЯкутиÑ)~РеÑпублика Ð¡ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐžÑетиÑ-ÐланиÑ~РеÑпублика ТатарÑтан~РеÑпублика Тыва~РеÑпублика УдмуртиÑ~РеÑпублика ХакаÑиÑ~РоÑтовÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Ð ÑзанÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СамарÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Санкт-Петербург~СаратовÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СахалинÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СвердловÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СеваÑтополь~СмоленÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СтавропольÑкий край~ТамбовÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТверÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТомÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТульÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТюменÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~УльÑновÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ХабаровÑкий край~Ханты-МанÑийÑкий автономный округ~ЧелÑбинÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЧеченÑÐºÐ°Ñ Ð ÐµÑпублика~ЧувашÑÐºÐ°Ñ Ð ÐµÑпублика~ЧукотÑкий автономный округ~Ямало-Ðенецкий автономный округ~ЯроÑлавÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ", "sub_lnames": "Altayskiy kray~Amurskaya oblast'~Arkhangelskaya oblast'~Astrakhanskaya oblast'~Belgorodskaya oblast'~Bryanskaya oblast'~Vladimirskaya oblast'~Volgogradskaya oblast'~Vologodskaya oblast'~Voronezhskaya oblast'~Evreyskaya avtonomnaya oblast'~Zabaykalskiy kray~Ivanovskaya oblast'~Irkutskaya oblast'~Kabardino-Balkarskaya Republits~Kaliningradskaya oblast'~Kaluzhskaya oblast'~Kamchatskiy kray~Karachaevo-Cherkesskaya Republits~Kemerovskaya oblast'~Kirovskaya oblast'~Kostromskaya oblast'~Krasnodarskiy kray~Krasnoyarskiy kray~Kurganskaya oblast'~Kurskaya oblast'~Leningradskaya oblast'~Lipetskaya oblast'~Magadanskaya oblast'~Moskva~Moskovskaya oblast'~Murmanskaya oblast'~Nenetskiy~Nizhegorodskaya oblast'~Novgorodskaya oblast'~Novosibirskaya oblast'~Omskaya oblast'~Orenburgskaya oblast'~Orlovskaya oblast'~Penzenskaya oblast'~Permskiy kray~Primorskiy kray~Pskovskaya oblast'~Respublika Adygeya~Altay Republits~Bashkortostan Republits~Buryatiya Republits~Dagestan Republits~Ingushetiya Republits~Respublika Kalmykiya~Kareliya Republits~Komi Republits~Respublika Krym~Respublika Mariy El~Respublika Mordoviya~Sakha (Yakutiya) Republits~Respublika Severnaya Osetiya-Alaniya~Respublika Tatarstan~Tyva Republits~Respublika Udmurtiya~Khakasiya Republits~Rostovskaya oblast'~Ryazanskaya oblast'~Samarskaya oblast'~Sankt-Peterburg~Saratovskaya oblast'~Sakhalinskaya oblast'~Sverdlovskaya oblast'~Sevastopol'~Smolenskaya oblast'~Stavropolskiy kray~Tambovskaya oblast'~Tverskaya oblast'~Tomskaya oblast'~Tulskaya oblast'~Tyumenskaya oblast'~Ulyanovskaya oblast'~Khabarovskiy kray~Khanty-Mansiyskiy avtonomnyy okrug~Chelyabinskaya oblast'~Chechenskaya Republits~Chuvashia~Chukotskiy~Yamalo-Nenetskiy~Yaroslavskaya oblast'", "sub_names": "ÐлтайÑкий край~ÐмурÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐрхангельÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐÑтраханÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~БелгородÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~БрÑнÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВладимирÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВолгоградÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВологодÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ВоронежÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЕврейÑÐºÐ°Ñ Ð°Ð²Ñ‚Ð¾Ð½Ð¾Ð¼Ð½Ð°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЗабайкальÑкий край~ИвановÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ИркутÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Кабардино-БалкарÑÐºÐ°Ñ Ð ÐµÑпублика~КалининградÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КалужÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КамчатÑкий край~Карачаево-ЧеркеÑÑÐºÐ°Ñ Ð ÐµÑпублика~КемеровÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КировÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КоÑтромÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КраÑнодарÑкий край~КраÑноÑÑ€Ñкий край~КурганÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~КурÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЛенинградÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Ð›Ð¸Ð¿ÐµÑ†ÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~МагаданÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~МоÑква~МоÑковÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~МурманÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Ðенецкий автономный округ~ÐижегородÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐовгородÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ÐовоÑибирÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ОмÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ОренбургÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ОрловÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ПензенÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ПермÑкий край~ПриморÑкий край~ПÑковÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~РеÑпублика ÐдыгеÑ~РеÑпублика Ðлтай~РеÑпублика БашкортоÑтан~РеÑпублика БурÑтиÑ~РеÑпублика ДагеÑтан~РеÑпублика ИнгушетиÑ~РеÑпублика КалмыкиÑ~РеÑпублика КарелиÑ~РеÑпублика Коми~РеÑпублика Крым~РеÑпублика Марий Ðл~РеÑпублика МордовиÑ~РеÑпублика Саха (ЯкутиÑ)~РеÑпублика Ð¡ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐžÑетиÑ-ÐланиÑ~РеÑпублика ТатарÑтан~РеÑпублика Тыва~РеÑпублика УдмуртиÑ~РеÑпублика ХакаÑиÑ~РоÑтовÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Ð ÑзанÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СамарÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~Санкт-Петербург~СаратовÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СахалинÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СвердловÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СеваÑтополь~СмоленÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~СтавропольÑкий край~ТамбовÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТверÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТомÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТульÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ТюменÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~УльÑновÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ХабаровÑкий край~Ханты-МанÑийÑкий автономный округ~ЧелÑбинÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ~ЧеченÑÐºÐ°Ñ Ð ÐµÑпублика~ЧувашÑÐºÐ°Ñ Ð ÐµÑпублика~ЧукотÑкий автономный округ~Ямало-Ðенецкий автономный округ~ЯроÑлавÑÐºÐ°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ", "sub_zips": "65[6-9]~67[56]~16[3-5]~41[4-6]~30[89]~24[1-3]~60[0-2]~40[0-4]~16[0-2]~39[4-7]~679~6(?:7[2-4]|87)~15[3-5]~66[4-9]~36[01]~23[6-8]~24[89]~68[348]~369~65[0-4]~61[0-3]~15[67]~35[0-4]~6(?:6[0-3]|4[78])~64[01]~30[5-7]~18[78]~39[89]~68[56]~1(?:0[1-9]|1|2|3[0-5]|4[0-4])~14[0-4]~18[34]~166~60[3-7]~17[3-5]~63[0-3]~64[4-6]~46[0-2]~30[23]~44[0-2]~61[4-9]~69[0-2]~18[0-2]~385~649~45[0-3]~67[01]~36[78]~386~35[89]~18[56]~16[7-9]~29[5-8]~42[45]~43[01]~67[78]~36[23]~42[0-3]~66[78]~42[67]~655~34[4-7]~39[01]~44[3-6]~19~41[0-3]~69[34]~62[0-4]~299~21[4-6]~35[5-7]~39[23]~17[0-2]~63[4-6]~30[01]~62[5-7]~43[23]~68[0-2]~628~45[4-7]~36[4-6]~42[89]~689~629~15[0-2]", "upper": "AC", "zip": "\\d{6}", "zipex": "247112,103375,188300"}, + "data/RW": {"id": "data/RW", "key": "RW", "name": "RWANDA", "upper": "AC"}, + "data/SA": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/SA", "key": "SA", "name": "SAUDI ARABIA", "zip": "\\d{5}", "zipex": "11564,11187,11142"}, + "data/SB": {"id": "data/SB", "key": "SB", "name": "SOLOMON ISLANDS"}, + "data/SC": {"fmt": "%N%n%O%n%A%n%C%n%S", "id": "data/SC", "key": "SC", "name": "SEYCHELLES", "state_name_type": "island", "upper": "S"}, + "data/SD": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/SD", "key": "SD", "locality_name_type": "district", "name": "SUDAN", "zip": "\\d{5}", "zipex": "11042,11113"}, + "data/SE": {"fmt": "%O%n%N%n%A%nSE-%Z %C", "id": "data/SE", "key": "SE", "locality_name_type": "post_town", "name": "SWEDEN", "postprefix": "SE-", "posturl": "http://www.posten.se/sv/Kundservice/Sidor/Sok-postnummer-resultat.aspx", "require": "ACZ", "zip": "\\d{3} ?\\d{2}", "zipex": "11455,12345,10500"}, + "data/SG": {"fmt": "%N%n%O%n%A%nSINGAPORE %Z", "id": "data/SG", "key": "SG", "name": "REP. OF SINGAPORE", "posturl": "https://www.singpost.com/find-postal-code", "require": "AZ", "zip": "\\d{6}", "zipex": "546080,308125,408600"}, + "data/SH": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/SH", "key": "SH", "name": "SAINT HELENA", "require": "ACZ", "upper": "CZ", "zip": "(?:ASCN|STHL) 1ZZ", "zipex": "STHL 1ZZ"}, + "data/SI": {"fmt": "%N%n%O%n%A%nSI-%Z %C", "id": "data/SI", "key": "SI", "name": "SLOVENIA", "postprefix": "SI-", "zip": "\\d{4}", "zipex": "4000,1001,2500"}, + "data/SK": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/SK", "key": "SK", "name": "SLOVAKIA", "posturl": "http://psc.posta.sk", "require": "ACZ", "zip": "\\d{3} ?\\d{2}", "zipex": "010 01,023 14,972 48,921 01,975 99"}, + "data/SL": {"id": "data/SL", "key": "SL", "name": "SIERRA LEONE"}, + "data/SM": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/SM", "key": "SM", "name": "SAN MARINO", "posturl": "http://www.poste.it/online/cercacap/", "require": "AZ", "zip": "4789\\d", "zipex": "47890,47891,47895,47899"}, + "data/SN": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/SN", "key": "SN", "name": "SENEGAL", "zip": "\\d{5}", "zipex": "12500,46024,16556,10000"}, + "data/SO": {"fmt": "%N%n%O%n%A%n%C, %S %Z", "id": "data/SO", "key": "SO", "lang": "so", "languages": "so", "name": "SOMALIA", "require": "ACS", "sub_isoids": "AW~BK~BN~BR~BY~GA~GE~HI~JD~JH~MU~NU~SA~SD~SH~SO~TO~WO", "sub_keys": "AD~BK~BN~BR~BY~GG~GD~HR~JD~JH~MD~NG~SG~SD~SH~SL~TG~WG", "sub_names": "Awdal~Bakool~Banaadir~Bari~Bay~Galguduud~Gedo~Hiiraan~Jubbada Dhexe~Jubbada Hoose~Mudug~Nugaal~Sanaag~Shabeellaha Dhexe~Shabeellaha Hoose~Sool~Togdheer~Woqooyi Galbeed", "upper": "ACS", "zip": "[A-Z]{2} ?\\d{5}", "zipex": "JH 09010,AD 11010"}, + "data/SR": {"fmt": "%N%n%O%n%A%n%C%n%S", "id": "data/SR", "key": "SR", "lang": "nl", "languages": "nl", "name": "SURINAME", "sub_isoids": "BR~CM~CR~MA~NI~PR~PM~SA~SI~WA", "sub_keys": "Brokopondo~Commewijne~Coronie~Marowijne~Nickerie~Para~Paramaribo~Saramacca~Sipaliwini~Wanica", "upper": "AS"}, + "data/SS": {"id": "data/SS", "key": "SS", "name": "SOUTH SUDAN"}, + "data/ST": {"id": "data/ST", "key": "ST", "name": "SAO TOME AND PRINCIPE"}, + "data/SV": {"fmt": "%N%n%O%n%A%n%Z-%C%n%S", "id": "data/SV", "key": "SV", "lang": "es", "languages": "es", "name": "EL SALVADOR", "require": "ACS", "sub_isoids": "AH~CA~CH~CU~LI~PA~UN~MO~SM~SS~SV~SA~SO~US", "sub_keys": "Ahuachapan~Cabanas~Calatenango~Cuscatlan~La Libertad~La Paz~La Union~Morazan~San Miguel~San Salvador~San Vicente~Santa Ana~Sonsonate~Usulutan", "sub_names": "Ahuachapán~Cabañas~Chalatenango~Cuscatlán~La Libertad~La Paz~La Unión~Morazán~San Miguel~San Salvador~San Vicente~Santa Ana~Sonsonate~Usulután", "sub_zipexs": "CP 2101~CP 1201~CP 1301~CP 1401~CP 1501~CP 1601~CP 3101~CP 3201~CP 3301~CP 1101~CP 1701~CP 2201~CP 2301~CP 3401", "sub_zips": "CP 21~CP 12~CP 13~CP 14~CP 15~CP 16~CP 31~CP 32~CP 33~CP 11~CP 17~CP 22~CP 23~CP 34", "upper": "CSZ", "zip": "CP [1-3][1-7][0-2]\\d", "zipex": "CP 1101"}, + "data/SX": {"id": "data/SX", "key": "SX", "name": "SINT MAARTEN"}, + "data/SY": {"id": "data/SY", "key": "SY", "locality_name_type": "district", "name": "SYRIA"}, + "data/SZ": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/SZ", "key": "SZ", "name": "SWAZILAND", "posturl": "http://www.sptc.co.sz/swazipost/codes/index.php", "upper": "ACZ", "zip": "[HLMS]\\d{3}", "zipex": "H100"}, + "data/TC": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/TC", "key": "TC", "name": "TURKS AND CAICOS ISLANDS", "require": "ACZ", "upper": "CZ", "zip": "TKCA 1ZZ", "zipex": "TKCA 1ZZ"}, + "data/TD": {"id": "data/TD", "key": "TD", "name": "CHAD"}, + "data/TF": {"id": "data/TF", "key": "TF", "name": "FRENCH SOUTHERN TERRITORIES"}, + "data/TG": {"id": "data/TG", "key": "TG", "name": "TOGO"}, + "data/TH": {"fmt": "%N%n%O%n%A%n%D %C%n%S %Z", "id": "data/TH", "key": "TH", "lang": "th", "languages": "th", "lfmt": "%N%n%O%n%A%n%D, %C%n%S %Z", "name": "THAILAND", "sub_isoids": "81~10~71~46~62~40~38~22~24~20~18~36~86~57~50~92~23~63~26~73~48~30~80~60~12~96~55~31~13~77~25~94~14~56~82~93~66~65~76~67~54~83~44~49~58~35~95~45~85~21~70~16~52~51~42~33~47~90~91~11~75~74~27~19~17~64~72~84~32~43~39~15~37~41~53~61~34", "sub_keys": "à¸à¸£à¸°à¸šà¸µà¹ˆ~à¸à¸£à¸¸à¸‡à¹€à¸—พมหานคร~à¸à¸²à¸à¸ˆà¸™à¸šà¸¸à¸£à¸µ~à¸à¸²à¸¬à¸ªà¸´à¸™à¸˜à¸¸à¹Œ~à¸à¸³à¹à¸žà¸‡à¹€à¸žà¸Šà¸£~ขà¸à¸™à¹à¸à¹ˆà¸™~จังหวัด บึงà¸à¸²à¸¬~จันทบุรี~ฉะเชิงเทรา~ชลบุรี~ชัยนาท~ชัยภูมิ~ชุมพร~เชียงราย~เชียงใหม่~ตรัง~ตราด~ตาà¸~นครนายà¸~นครปà¸à¸¡~นครพนม~นครราชสีมา~นครศรีธรรมราช~นครสวรรค์~นนทบุรี~นราธิวาส~น่าน~บุรีรัมย์~ปทุมธานี~ประจวบคีรีขันธ์~ปราจีนบุรี~ปัตตานี~พระนครศรีà¸à¸¢à¸¸à¸˜à¸¢à¸²~พะเยา~พังงา~พัทลุง~พิจิตร~พิษณุโลà¸~เพชรบุรี~เพชรบูรณ์~à¹à¸žà¸£à¹ˆ~ภูเà¸à¹‡à¸•~มหาสารคาม~มุà¸à¸”าหาร~à¹à¸¡à¹ˆà¸®à¹ˆà¸à¸‡à¸ªà¸à¸™~ยโสธร~ยะลา~ร้à¸à¸¢à¹€à¸à¹‡à¸”~ระนà¸à¸‡~ระยà¸à¸‡~ราชบุรี~ลพบุรี~ลำปาง~ลำพูน~เลย~ศรีสะเà¸à¸©~สà¸à¸¥à¸™à¸„ร~สงขลา~สตูล~สมุทรปราà¸à¸²à¸£~สมุทรสงคราม~สมุทรสาคร~สระà¹à¸à¹‰à¸§~สระบุรี~สิงห์บุรี~สุโขทัย~สุพรรณบุรี~สุราษฎร์ธานี~สุรินทร์~หนà¸à¸‡à¸„าย~หนà¸à¸‡à¸šà¸±à¸§à¸¥à¸³à¸ ู~à¸à¹ˆà¸²à¸‡à¸—à¸à¸‡~à¸à¸³à¸™à¸²à¸ˆà¹€à¸ˆà¸£à¸´à¸~à¸à¸¸à¸”รธานี~à¸à¸¸à¸•à¸£à¸”ิตถ์~à¸à¸¸à¸—ัยธานี~à¸à¸¸à¸šà¸¥à¸£à¸²à¸Šà¸˜à¸²à¸™à¸µ", "sub_lnames": "Krabi~Bangkok~Kanchanaburi~Kalasin~Kamphaeng Phet~Khon Kaen~Bueng Kan~Chanthaburi~Chachoengsao~Chon Buri~Chai Nat~Chaiyaphum~Chumpon~Chiang Rai~Chiang Mai~Trang~Trat~Tak~Nakhon Nayok~Nakhon Pathom~Nakhon Phanom~Nakhon Ratchasima~Nakhon Si Thammarat~Nakhon Sawan~Nonthaburi~Narathiwat~Nan~Buri Ram~Pathum Thani~Prachuap Khiri Khan~Prachin Buri~Pattani~Phra Nakhon Si Ayutthaya~Phayao~Phang Nga~Phattalung~Phichit~Phitsanulok~Phetchaburi~Phetchabun~Phrae~Phuket~Maha Sarakham~Mukdahan~Mae Hong Son~Yasothon~Yala~Roi Et~Ranong~Rayong~Ratchaburi~Lop Buri~Lampang~Lamphun~Loei~Si Sa Ket~Sakon Nakhon~Songkhla~Satun~Samut Prakan~Samut Songkhram~Samut Sakhon~Sa Kaeo~Saraburi~Sing Buri~Sukhothai~Suphanburi~Surat Thani~Surin~Nong Khai~Nong Bua Lam Phu~Ang Thong~Amnat Charoen~Udon Thani~Uttaradit~Uthai Thani~Ubon Ratchathani", "sub_zips": "81~10~71~46~62~40~~22~24~20~17~36~86~57~50~92~23~63~26~73~48~30~80~60~11~96~55~31~12~77~25~94~13~56~82~93~66~65~76~67~54~83~44~49~58~35~95~45~85~21~70~15~52~51~42~33~47~90~91~10~75~74~27~18~16~64~72~84~32~43~39~14~37~41~53~61~34", "upper": "S", "zip": "\\d{5}", "zipex": "10150,10210"}, + "data/TJ": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/TJ", "key": "TJ", "name": "TAJIKISTAN", "zip": "\\d{6}", "zipex": "735450,734025"}, + "data/TK": {"id": "data/TK", "key": "TK", "name": "TOKELAU"}, + "data/TL": {"id": "data/TL", "key": "TL", "name": "TIMOR-LESTE"}, + "data/TM": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/TM", "key": "TM", "name": "TURKMENISTAN", "zip": "\\d{6}", "zipex": "744000"}, + "data/TN": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/TN", "key": "TN", "name": "TUNISIA", "posturl": "http://www.poste.tn/codes.php", "zip": "\\d{4}", "zipex": "1002,8129,3100,1030"}, + "data/TO": {"id": "data/TO", "key": "TO", "name": "TONGA"}, + "data/TR": {"fmt": "%N%n%O%n%A%n%Z %C/%S", "id": "data/TR", "key": "TR", "lang": "tr", "languages": "tr", "locality_name_type": "district", "name": "TURKEY", "posturl": "http://postakodu.ptt.gov.tr/", "require": "ACZ", "sub_isoids": "01~02~03~04~68~05~06~07~75~08~09~10~74~72~69~11~12~13~14~15~16~17~18~19~20~21~81~22~23~24~25~26~27~28~29~30~31~76~32~34~35~46~78~70~36~37~38~71~39~40~79~41~42~43~44~45~47~33~48~49~50~51~52~80~53~54~55~56~57~58~63~73~59~60~61~62~64~65~77~66~67", "sub_keys": "Adana~Adıyaman~Afyon~AÄŸrı~Aksaray~Amasya~Ankara~Antalya~Ardahan~Artvin~Aydın~Balıkesir~Bartın~Batman~Bayburt~Bilecik~Bingöl~Bitlis~Bolu~Burdur~Bursa~Çanakkale~Çankırı~Çorum~Denizli~Diyarbakır~Düzce~Edirne~Elazığ~Erzincan~Erzurum~EskiÅŸehir~Gaziantep~Giresun~Gümüşhane~Hakkari~Hatay~IÄŸdır~Isparta~Ä°stanbul~Ä°zmir~KahramanmaraÅŸ~Karabük~Karaman~Kars~Kastamonu~Kayseri~Kırıkkale~Kırklareli~KırÅŸehir~Kilis~Kocaeli~Konya~Kütahya~Malatya~Manisa~Mardin~Mersin~MuÄŸla~MuÅŸ~NevÅŸehir~NiÄŸde~Ordu~Osmaniye~Rize~Sakarya~Samsun~Siirt~Sinop~Sivas~Åžanlıurfa~Şırnak~TekirdaÄŸ~Tokat~Trabzon~Tunceli~UÅŸak~Van~Yalova~Yozgat~Zonguldak", "sub_zips": "01~02~03~04~68~05~06~07~75~08~09~10~74~72~69~11~12~13~14~15~16~17~18~19~20~21~81~22~23~24~25~26~27~28~29~30~31~76~32~34~35~46~78~70~36~37~38~71~39~40~79~41~42~43~44~45~47~33~48~49~50~51~52~80~53~54~55~56~57~58~63~73~59~60~61~62~64~65~77~66~67", "zip": "\\d{5}", "zipex": "01960,06101"}, + "data/TT": {"id": "data/TT", "key": "TT", "name": "TRINIDAD AND TOBAGO"}, + "data/TV": {"fmt": "%N%n%O%n%A%n%C%n%S", "id": "data/TV", "key": "TV", "lang": "tyv", "languages": "tyv", "name": "TUVALU", "state_name_type": "island", "sub_isoids": "FUN~NMG~NMA~~NIT~NUI~NKF~NKL~VAI", "sub_keys": "Funafuti~Nanumanga~Nanumea~Niulakita~Niutao~Nui~Nukufetau~Nukulaelae~Vaitupu", "upper": "ACS"}, + "data/TW": {"fmt": "%Z%n%S%C%n%A%n%O%n%N", "id": "data/TW", "key": "TW", "lang": "zh-Hant", "languages": "zh-Hant", "lfmt": "%N%n%O%n%A%n%C, %S %Z", "name": "TAIWAN", "posturl": "http://www.post.gov.tw/post/internet/f_searchzone/index.jsp?ID=190102", "require": "ACSZ", "state_name_type": "county", "sub_isoids": "TXG~TPE~TTT~TNN~ILA~HUA~~NAN~PIF~MIA~TAO~KHH~KEE~~YUN~NWT~HSZ~HSQ~CYI~CYQ~CHA~PEN", "sub_keys": "å°ä¸å¸‚~å°åŒ—市~å°æ±ç¸£~å°å—市~宜è˜ç¸£~花蓮縣~金門縣~å—投縣~å±æ±ç¸£~è‹—æ —ç¸£~桃園市~高雄市~基隆市~連江縣~雲林縣~新北市~新竹市~新竹縣~嘉義市~嘉義縣~彰化縣~澎湖縣", "sub_lnames": "Taichung City~Taipei City~Taitung County~Tainan City~Yilan County~Hualien County~Kinmen County~Nantou County~Pingtung County~Miaoli County~Taoyuan City~Kaohsiung City~Keelung City~Lienchiang County~Yunlin County~New Taipei City~Hsinchu City~Hsinchu County~Chiayi City~Chiayi County~Changhua County~Penghu County", "sub_mores": "true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true~true", "sub_zipexs": "400,408,411,439~100,119~950,966~700,745~260,272~970,983~890,896~540,558~900,947~350,369~320,338~800,815,817,852~200,206~209,212~630,655~207,208,220,253~~302,315~~602,625~500,530~880,885", "sub_zips": "4[0-3]~1[01]~9[56]~7[0-4]~2[67]~9[78]~89~5[45]~9[0-4]~3[56]~3[23]~8[02-5]|81[1-579]~20[0-6]~209|21[012]~6[3-5]~20[78]|2[2345]~300~30[2-8]|31~600~60[1-9]|6[12]~5[0123]~88", "zip": "\\d{3}(?:\\d{2})?", "zipex": "104,106,10603,40867"}, + "data/TZ": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/TZ", "key": "TZ", "name": "TANZANIA (UNITED REP.)", "zip": "\\d{4,5}", "zipex": "6090,34413"}, + "data/UA": {"fmt": "%N%n%O%n%A%n%C%n%S%n%Z", "id": "data/UA", "key": "UA", "lang": "uk", "languages": "uk", "lfmt": "%N%n%O%n%A%n%C%n%S%n%Z", "name": "UKRAINE", "posturl": "http://services.ukrposhta.com/postindex_new/", "require": "ACSZ", "state_name_type": "oblast", "sub_isoids": "43~05~07~12~14~18~21~23~26~30~32~35~09~46~48~51~53~56~40~59~61~63~65~68~71~77~74", "sub_keys": "Ðвтономна РеÑпубліка Крим~Вінницька облаÑÑ‚ÑŒ~ВолинÑька облаÑÑ‚ÑŒ~ДніпропетровÑька облаÑÑ‚ÑŒ~Донецька облаÑÑ‚ÑŒ~ЖитомирÑька облаÑÑ‚ÑŒ~ЗакарпатÑька облаÑÑ‚ÑŒ~Запорізька облаÑÑ‚ÑŒ~Івано-ФранківÑька облаÑÑ‚ÑŒ~міÑто Київ~КиївÑька облаÑÑ‚ÑŒ~КіровоградÑька облаÑÑ‚ÑŒ~ЛуганÑька облаÑÑ‚ÑŒ~ЛьвівÑька облаÑÑ‚ÑŒ~МиколаївÑька облаÑÑ‚ÑŒ~ОдеÑька облаÑÑ‚ÑŒ~ПолтавÑька облаÑÑ‚ÑŒ~РівненÑька облаÑÑ‚ÑŒ~міÑто СеваÑтополь~СумÑька облаÑÑ‚ÑŒ~ТернопільÑька облаÑÑ‚ÑŒ~ХарківÑька облаÑÑ‚ÑŒ~ХерÑонÑька облаÑÑ‚ÑŒ~Хмельницька облаÑÑ‚ÑŒ~ЧеркаÑька облаÑÑ‚ÑŒ~Чернівецька облаÑÑ‚ÑŒ~ЧернігівÑька облаÑÑ‚ÑŒ", "sub_lnames": "Crimea~Vinnyts'ka oblast~Volyns'ka oblast~Dnipropetrovsk oblast~Donetsk oblast~Zhytomyrs'ka oblast~Zakarpats'ka oblast~Zaporiz'ka oblast~Ivano-Frankivs'ka oblast~Kyiv city~Kiev oblast~Kirovohrads'ka oblast~Luhans'ka oblast~Lviv oblast~Mykolaivs'ka oblast~Odessa oblast~Poltavs'ka oblast~Rivnens'ka oblast~Sevastopol' city~Sums'ka oblast~Ternopil's'ka oblast~Kharkiv oblast~Khersons'ka oblast~Khmel'nyts'ka oblast~Cherkas'ka oblast~Chernivets'ka oblast~Chernihivs'ka oblast", "sub_names": "Ðвтономна РеÑпубліка Крим~Вінницька облаÑÑ‚ÑŒ~ВолинÑька облаÑÑ‚ÑŒ~ДніпропетровÑька облаÑÑ‚ÑŒ~Донецька облаÑÑ‚ÑŒ~ЖитомирÑька облаÑÑ‚ÑŒ~ЗакарпатÑька облаÑÑ‚ÑŒ~Запорізька облаÑÑ‚ÑŒ~Івано-ФранківÑька облаÑÑ‚ÑŒ~Київ~КиївÑька облаÑÑ‚ÑŒ~КіровоградÑька облаÑÑ‚ÑŒ~ЛуганÑька облаÑÑ‚ÑŒ~ЛьвівÑька облаÑÑ‚ÑŒ~МиколаївÑька облаÑÑ‚ÑŒ~ОдеÑька облаÑÑ‚ÑŒ~ПолтавÑька облаÑÑ‚ÑŒ~РівненÑька облаÑÑ‚ÑŒ~СеваÑтополь~СумÑька облаÑÑ‚ÑŒ~ТернопільÑька облаÑÑ‚ÑŒ~ХарківÑька облаÑÑ‚ÑŒ~ХерÑонÑька облаÑÑ‚ÑŒ~Хмельницька облаÑÑ‚ÑŒ~ЧеркаÑька облаÑÑ‚ÑŒ~Чернівецька облаÑÑ‚ÑŒ~ЧернігівÑька облаÑÑ‚ÑŒ", "sub_zips": "9[5-8]~2[1-4]~4[3-5]~49|5[0-3]~8[3-7]~1[0-3]~8[89]|90~69|7[0-2]~7[6-8]~0[1-6]~0[7-9]~2[5-8]~9[1-4]~79|8[0-2]~5[4-7]~6[5-8]~3[6-9]~3[3-5]~99~4[0-2]~4[6-8]~6[1-4]~7[3-5]~29|3[0-2]~1[89]|20~5[89]|60~1[4-7]", "zip": "\\d{5}", "zipex": "15432,01055,01001"}, + "data/UG": {"id": "data/UG", "key": "UG", "name": "UGANDA"}, + "data/US": {"fmt": "%N%n%O%n%A%n%C, %S %Z", "id": "data/US", "key": "US", "lang": "en", "languages": "en", "name": "UNITED STATES", "posturl": "https://tools.usps.com/go/ZipLookupAction!input.action", "require": "ACSZ", "state_name_type": "state", "sub_isoids": "AL~AK~~AZ~AR~~~~CA~CO~CT~DE~DC~FL~GA~~HI~ID~IL~IN~IA~KS~KY~LA~ME~~MD~MA~MI~~MN~MS~MO~MT~NE~NV~NH~NJ~NM~NY~NC~ND~~OH~OK~OR~~PA~~RI~SC~SD~TN~TX~UT~VT~~VA~WA~WV~WI~WY", "sub_keys": "AL~AK~AS~AZ~AR~AA~AE~AP~CA~CO~CT~DE~DC~FL~GA~GU~HI~ID~IL~IN~IA~KS~KY~LA~ME~MH~MD~MA~MI~FM~MN~MS~MO~MT~NE~NV~NH~NJ~NM~NY~NC~ND~MP~OH~OK~OR~PW~PA~PR~RI~SC~SD~TN~TX~UT~VT~VI~VA~WA~WV~WI~WY", "sub_names": "Alabama~Alaska~American Samoa~Arizona~Arkansas~Armed Forces (AA)~Armed Forces (AE)~Armed Forces (AP)~California~Colorado~Connecticut~Delaware~District of Columbia~Florida~Georgia~Guam~Hawaii~Idaho~Illinois~Indiana~Iowa~Kansas~Kentucky~Louisiana~Maine~Marshall Islands~Maryland~Massachusetts~Michigan~Micronesia~Minnesota~Mississippi~Missouri~Montana~Nebraska~Nevada~New Hampshire~New Jersey~New Mexico~New York~North Carolina~North Dakota~Northern Mariana Islands~Ohio~Oklahoma~Oregon~Palau~Pennsylvania~Puerto Rico~Rhode Island~South Carolina~South Dakota~Tennessee~Texas~Utah~Vermont~Virgin Islands~Virginia~Washington~West Virginia~Wisconsin~Wyoming", "sub_zipexs": "35000,36999~99500,99999~96799~85000,86999~71600,72999~34000,34099~09000,09999~96200,96699~90000,96199~80000,81999~06000,06999~19700,19999~20000,56999~32000,34999~30000,39901~96910,96932~96700,96899~83200,83999~60000,62999~46000,47999~50000,52999~66000,67999~40000,42799~70000,71599~03900,04999~96960,96979~20600,21999~01000,05544~48000,49999~96941,96944~55000,56799~38600,39799~63000,65999~59000,59999~68000,69999~88900,89999~03000,03899~07000,08999~87000,88499~10000,00544~27000,28999~58000,58999~96950,96952~43000,45999~73000,74999~97000,97999~96940~15000,19699~00600,00999~02800,02999~29000,29999~57000,57999~37000,38599~75000,73344~84000,84999~05000,05999~00800,00899~20100,24699~98000,99499~24700,26999~53000,54999~82000,83414", "sub_zips": "3[56]~99[5-9]~96799~8[56]~71[6-9]|72~340~09~96[2-6]~9[0-5]|96[01]~8[01]~06~19[7-9]~20[02-5]|569~3[23]|34[1-9]~3[01]|398|39901~969([1-2]\\d|3[12])~967[0-8]|9679[0-8]|968~83[2-9]~6[0-2]~4[67]~5[0-2]~6[67]~4[01]|42[0-7]~70|71[0-5]~039|04~969[67]~20[6-9]|21~01|02[0-7]|05501|05544~4[89]~9694[1-4]~55|56[0-7]~38[6-9]|39[0-7]~6[3-5]~59~6[89]~889|89~03[0-8]~0[78]~87|88[0-4]~1[0-4]|06390|00501|00544~2[78]~58~9695[0-2]~4[3-5]~7[34]~97~969(39|40)~1[5-8]|19[0-6]~00[679]~02[89]~29~57~37|38[0-5]~7[5-9]|885|73301|73344~84~05~008~201|2[23]|24[0-6]~98|99[0-4]~24[7-9]|2[56]~5[34]~82|83[01]|83414", "upper": "CS", "zip": "(\\d{5})(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "95014,22162-1010"}, + "data/UY": {"fmt": "%N%n%O%n%A%n%Z %C %S", "id": "data/UY", "key": "UY", "lang": "es", "languages": "es", "name": "URUGUAY", "posturl": "http://www.correo.com.uy/index.asp?codPag=codPost&switchMapa=codPost", "sub_isoids": "AR~CA~CL~CO~DU~FS~FD~LA~MA~MO~PA~RN~RV~RO~SA~SJ~SO~TA~TT", "sub_keys": "Artigas~Canelones~Cerro Largo~Colonia~Durazno~Flores~Florida~Lavalleja~Maldonado~Montevideo~Paysandú~RÃo Negro~Rivera~Rocha~Salto~San José~Soriano~Tacuarembó~Treinta y Tres", "sub_zips": "55~9[01]|1[456]~37~70|75204~97~85~94|9060|97005~30~20~1|91600~60~65|60002~40~27~50~80~75|70003~45~33|30203|30204|30302|37007", "upper": "CS", "zip": "\\d{5}", "zipex": "11600"}, + "data/UZ": {"fmt": "%N%n%O%n%A%n%Z %C%n%S", "id": "data/UZ", "key": "UZ", "name": "UZBEKISTAN", "posturl": "http://www.pochta.uz/ru/uslugi/indexsearch.html", "upper": "CS", "zip": "\\d{6}", "zipex": "702100,700000"}, + "data/VA": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/VA", "key": "VA", "name": "VATICAN", "zip": "00120", "zipex": "00120"}, + "data/VC": {"fmt": "%N%n%O%n%A%n%C %Z", "id": "data/VC", "key": "VC", "name": "SAINT VINCENT AND THE GRENADINES (ANTILLES)", "posturl": "http://www.svgpost.gov.vc/?option=com_content&view=article&id=3&Itemid=16", "zip": "VC\\d{4}", "zipex": "VC0100,VC0110,VC0400"}, + "data/VE": {"fmt": "%N%n%O%n%A%n%C %Z, %S", "id": "data/VE", "key": "VE", "lang": "es", "languages": "es", "name": "VENEZUELA", "posturl": "http://www.ipostel.gob.ve/index.php/oficinas-postales", "require": "ACS", "state_name_type": "state", "sub_isoids": "Z~B~C~D~E~F~G~H~Y~W~A~I~J~K~L~M~N~O~P~R~S~T~X~U~V", "sub_keys": "Amazonas~Anzoátegui~Apure~Aragua~Barinas~BolÃvar~Carabobo~Cojedes~Delta Amacuro~Dependencias Federales~Distrito Federal~Falcón~Guárico~Lara~Mérida~Miranda~Monagas~Nueva Esparta~Portuguesa~Sucre~Táchira~Trujillo~Vargas~Yaracuy~Zulia", "upper": "CS", "zip": "\\d{4}", "zipex": "1010,3001,8011,1020"}, + "data/VG": {"fmt": "%N%n%O%n%A%n%C%n%Z", "id": "data/VG", "key": "VG", "name": "VIRGIN ISLANDS (BRITISH)", "require": "A", "zip": "VG\\d{4}", "zipex": "VG1110,VG1150,VG1160"}, + "data/VI": {"fmt": "%N%n%O%n%A%n%C %S %Z", "id": "data/VI", "key": "VI", "name": "VIRGIN ISLANDS (U.S.)", "posturl": "http://zip4.usps.com/zip4/welcome.jsp", "require": "ACSZ", "state_name_type": "state", "upper": "ACNOS", "zip": "(008(?:(?:[0-4]\\d)|(?:5[01])))(?:[ \\-](\\d{4}))?", "zip_name_type": "zip", "zipex": "00802-1222,00850-9802"}, + "data/VN": {"fmt": "%N%n%O%n%A%n%C%n%S %Z", "id": "data/VN", "key": "VN", "lang": "vi", "languages": "vi", "lfmt": "%N%n%O%n%A%n%C%n%S %Z", "name": "VIET NAM", "posturl": "http://postcode.vnpost.vn/services/search.aspx", "sub_isoids": "44~43~55~54~53~56~50~57~31~58~40~59~04~CT~DN~33~72~71~39~45~30~03~63~HN~23~61~HP~73~14~66~34~47~28~01~09~02~35~41~67~22~18~36~68~32~24~27~29~13~25~52~05~37~20~69~21~SG~26~46~51~07~49~70~06", "sub_keys": "An Giang~Bà Rịa–VÅ©ng Tà u~Bạc Liêu~Bắc Giang~Bắc Kạn~Bắc Ninh~Bến Tre~Bình DÆ°Æ¡ng~Bình Äịnh~Bình PhÆ°á»›c~Bình Thuáºn~Cà Mau~Cao Bằng~Cần ThÆ¡~Äà Nẵng~Äắk Lắk~Äăk Nông~Äiện Biên~Äồng Nai~Äồng Tháp~Gia Lai~Hà Giang~Hà Nam~Hà Ná»™i~Hà TÄ©nh~Hải DÆ°Æ¡ng~Hải Phòng~Háºu Giang~Hòa Bình~HÆ°ng Yên~Khánh Hòa~Kiên Giang~Kon Tum~Lai Châu~Lạng SÆ¡n~Là o Cai~Lâm Äồng~Long An~Nam Äịnh~Nghệ An~Ninh Bình~Ninh Thuáºn~Phú Thá»~Phú Yên~Quảng Bình~Quảng Nam~Quảng Ngãi~Quảng Ninh~Quảng Trị~Sóc Trăng~SÆ¡n La~Tây Ninh~Thái Bình~Thái Nguyên~Thanh Hóa~Thà nh phố Hồ Chà Minh~Thừa Thiên–Huế~Tiá»n Giang~Trà Vinh~Tuyên Quang~VÄ©nh Long~VÄ©nh Phúc~Yên Bái", "sub_lnames": "An Giang Province~Ba Ria-Vung Tau Province~Bac Lieu Province~Bac Giang Province~Bac Kan Province~Bac Ninh Province~Ben Tre Province~Binh Duong Province~Binh Dinh Province~Binh Phuoc Province~Binh Thuan Province~Ca Mau Province~Cao Bang Province~Can Tho City~Da Nang City~Dak Lak Province~Dak Nong Province~Dien Bien Province~Dong Nai Province~Dong Thap Province~Gia Lai Province~Ha Giang Province~Ha Nam Province~Hanoi City~Ha Tinh Province~Hai Duong Province~Haiphong City~Hau Giang Province~Hoa Binh Province~Hung Yen Province~Khanh Hoa Province~Kien Giang Province~Kon Tum Province~Lai Chau Province~Lang Song Province~Lao Cai Province~Lam Dong Province~Long An Province~Nam Dinh Province~Nghe An Province~Ninh Binh Province~Ninh Thuan Province~Phu Tho Province~Phu Yen Province~Quang Binh Province~Quang Nam Province~Quang Ngai Province~Quang Ninh Province~Quang Tri Province~Soc Trang Province~Son La Province~Tay Ninh Province~Thai Binh Province~Thai Nguyen Province~Thanh Hoa Province~Ho Chi Minh City~Thua Thien-Hue Province~Tien Giang Province~Tra Vinh Province~Tuyen Quang Province~Vinh Long Province~Vinh Phuc Province~Yen Bai Province", "zip": "\\d{5}\\d?", "zipex": "70010,55999"}, + "data/VU": {"id": "data/VU", "key": "VU", "name": "VANUATU"}, + "data/WF": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/WF", "key": "WF", "name": "WALLIS AND FUTUNA ISLANDS", "require": "ACZ", "upper": "ACX", "zip": "986\\d{2}", "zipex": "98600"}, + "data/WS": {"id": "data/WS", "key": "WS", "name": "SAMOA"}, + "data/XK": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/XK", "key": "XK", "name": "KOSOVO", "zip": "[1-7]\\d{4}", "zipex": "10000"}, + "data/YE": {"id": "data/YE", "key": "YE", "name": "YEMEN"}, + "data/YT": {"fmt": "%O%n%N%n%A%n%Z %C %X", "id": "data/YT", "key": "YT", "name": "MAYOTTE", "require": "ACZ", "upper": "ACX", "zip": "976\\d{2}", "zipex": "97600"}, + "data/ZA": {"fmt": "%N%n%O%n%A%n%D%n%C%n%Z", "id": "data/ZA", "key": "ZA", "name": "SOUTH AFRICA", "posturl": "https://www.postoffice.co.za/Questions/postalcode.html", "require": "ACZ", "zip": "\\d{4}", "zipex": "0083,1451,0001"}, + "data/ZM": {"fmt": "%N%n%O%n%A%n%Z %C", "id": "data/ZM", "key": "ZM", "name": "ZAMBIA", "zip": "\\d{5}", "zipex": "50100,50101"}, + "data/ZW": {"id": "data/ZW", "key": "ZW", "name": "ZIMBABWE"}, }; diff --git a/browser/extensions/formautofill/addressmetadata/addressReferencesExt.js b/browser/extensions/formautofill/addressmetadata/addressReferencesExt.js index 04bc62af33ef9..68a8ea7aed315 100644 --- a/browser/extensions/formautofill/addressmetadata/addressReferencesExt.js +++ b/browser/extensions/formautofill/addressmetadata/addressReferencesExt.js @@ -7,7 +7,7 @@ "use strict"; -// "addressDataExt" uses the same key as "addressData" in "addressReferences.js" and contains +// "addressDataExt" uses the same key as "addressData" in "addressReferences.js" and // contains the information we need but absent in "libaddressinput" such as alternative names. // TODO: We only support the alternative name of US in MVP. We are going to support more countries in diff --git a/browser/extensions/formautofill/content/autofillEditForms.js b/browser/extensions/formautofill/content/autofillEditForms.js index 37ad5957f409e..610a349a77582 100644 --- a/browser/extensions/formautofill/content/autofillEditForms.js +++ b/browser/extensions/formautofill/content/autofillEditForms.js @@ -122,16 +122,19 @@ class EditAddress extends EditAutofillForm { * @param {object} config * @param {string[]} config.DEFAULT_REGION * @param {function} config.getFormFormat Function to return form layout info for a given country. - * @param {string[]} config.supportedCountries + * @param {string[]} config.countries */ constructor(elements, record, config) { super(elements); Object.assign(this, config); + let {form} = this._elements; Object.assign(this._elements, { - addressLevel1Label: this._elements.form.querySelector("#address-level1-container > span"), - postalCodeLabel: this._elements.form.querySelector("#postal-code-container > span"), - country: this._elements.form.querySelector("#country"), + addressLevel3Label: form.querySelector("#address-level3-container > .label-text"), + addressLevel2Label: form.querySelector("#address-level2-container > .label-text"), + addressLevel1Label: form.querySelector("#address-level1-container > .label-text"), + postalCodeLabel: form.querySelector("#postal-code-container > .label-text"), + country: form.querySelector("#country"), }); this.populateCountries(); @@ -149,7 +152,7 @@ class EditAddress extends EditAutofillForm { this._record = record; if (!record) { record = { - country: this.supportedCountries.find(supported => supported == this.DEFAULT_REGION), + country: this.DEFAULT_REGION, }; } super.loadRecord(record); @@ -205,11 +208,15 @@ class EditAddress extends EditAutofillForm { */ formatForm(country) { const { + addressLevel3Label, + addressLevel2Label, addressLevel1Label, postalCodeLabel, fieldsOrder: mailingFieldsOrder, postalCodePattern, } = this.getFormFormat(country); + this._elements.addressLevel3Label.dataset.localization = addressLevel3Label; + this._elements.addressLevel2Label.dataset.localization = addressLevel2Label; this._elements.addressLevel1Label.dataset.localization = addressLevel1Label; this._elements.postalCodeLabel.dataset.localization = postalCodeLabel; let addressFields = this._elements.form.dataset.addressFields; @@ -228,6 +235,7 @@ class EditAddress extends EditAutofillForm { "name", "organization", "street-address", + "address-level3", "address-level2", "address-level1", "postal-code", @@ -273,10 +281,12 @@ class EditAddress extends EditAutofillForm { populateCountries() { let fragment = document.createDocumentFragment(); - for (let country of this.supportedCountries) { + // Sort countries by their visible names. + let countries = [...this.countries.entries()].sort((e1, e2) => e1[1].localeCompare(e2[1])); + for (let country of countries) { let option = new Option(); - option.value = country; - option.dataset.localizationRegion = country.toLowerCase(); + option.value = country[0]; + option.dataset.localizationRegion = country[0].toLowerCase(); fragment.appendChild(option); } this._elements.country.appendChild(fragment); diff --git a/browser/extensions/formautofill/content/editAddress.xhtml b/browser/extensions/formautofill/content/editAddress.xhtml index b60263b7ff644..2e01e8728a50d 100644 --- a/browser/extensions/formautofill/content/editAddress.xhtml +++ b/browser/extensions/formautofill/content/editAddress.xhtml @@ -44,9 +44,13 @@ <textarea id="street-address" rows="3" required="required"/> <span data-localization="streetAddress" class="label-text"/> </label> + <label id="address-level3-container" class="container"> + <input id="address-level3" type="text" required="required"/> + <span class="label-text"/> + </label> <label id="address-level2-container" class="container"> <input id="address-level2" type="text" required="required"/> - <span data-localization="city" class="label-text"/> + <span class="label-text"/> </label> <label id="address-level1-container" class="container"> <input id="address-level1" type="text" required="required"/> @@ -81,7 +85,7 @@ let { DEFAULT_REGION, - supportedCountries, + countries, } = FormAutofill; let { getFormFormat, @@ -90,12 +94,12 @@ let novalidate = window.arguments && window.arguments[1] == "novalidate"; /* import-globals-from autofillEditForms.js */ - let fieldContainer = new EditAddress({ + var fieldContainer = new EditAddress({ form: document.getElementById("form"), }, record, { DEFAULT_REGION, getFormFormat: getFormFormat.bind(FormAutofillUtils), - supportedCountries, + countries, novalidate, }); diff --git a/browser/extensions/formautofill/locales/en-US/formautofill.properties b/browser/extensions/formautofill/locales/en-US/formautofill.properties index ed76f3802012a..5dd57459b77d0 100644 --- a/browser/extensions/formautofill/locales/en-US/formautofill.properties +++ b/browser/extensions/formautofill/locales/en-US/formautofill.properties @@ -119,11 +119,54 @@ additionalName = Middle Name familyName = Last Name organization2 = Organization streetAddress = Street Address + +## address-level-3 (Sublocality) names +# LOCALIZATION NOTE (neighborhood): Used in IR, MX +neighborhood = Neighborhood +# LOCALIZATION NOTE (village_township): Used in MY +village_township = Village or Township +island = Island +# LOCALIZATION NOTE (townland): Used in IE +townland = Townland + +## address-level-2 names city = City +# LOCALIZATION NOTE (district): Used in HK, SD, SY, TR as Address Level-2 +# and used in KR as Sublocality. +district = District +# LOCALIZATION NOTE (post_town): Used in GB, NO, SE +post_town = Post town +# LOCALIZATION NOTE (suburb): Used in AU as Address Level-2 +# and used in ZZ as Sublocality. +suburb = Suburb + +# address-level-1 names province = Province state = State +county = County +# LOCALIZATION NOTE (parish): Used in BB, JM +parish = Parish +# LOCALIZATION NOTE (prefecture): Used in JP +prefecture = Prefecture +# LOCALIZATION NOTE (area): Used in HK +area = Area +# LOCALIZATION NOTE (do_si): Used in KR +do_si = Do/Si +# LOCALIZATION NOTE (department): Used in NI, CO +department = Department +# LOCALIZATION NOTE (emirate): Used in AE +emirate = Emirate +# LOCALIZATION NOTE (oblast): Used in RU and UA +oblast = Oblast + +# LOCALIZATION NOTE (pin, postalCode, zip, eircode): Postal code name types +# LOCALIZATION NOTE (pin): Used in IN +pin = Pin postalCode = Postal Code zip = ZIP Code +# LOCALIZATION NOTE (eircode): Used in IE +eircode = Eircode + country = Country or Region tel = Phone email = Email diff --git a/browser/extensions/formautofill/skin/shared/editAddress.css b/browser/extensions/formautofill/skin/shared/editAddress.css index db6903a09feeb..19d4992e93b9c 100644 --- a/browser/extensions/formautofill/skin/shared/editAddress.css +++ b/browser/extensions/formautofill/skin/shared/editAddress.css @@ -27,6 +27,8 @@ other fields which are <input>. */ flex-basis: calc(50% - var(--grid-column-row-gap)); flex-grow: 0; + /* Country names can be longer than 50% which ruins the symmetry in the grid. */ + max-width: calc(50% - var(--grid-column-row-gap)); } diff --git a/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js b/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js index ac4105941cddc..e73e39ebbbb25 100644 --- a/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js +++ b/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js @@ -1,5 +1,7 @@ "use strict"; +requestLongerTimeout(6); + add_task(async function setup_supportedCountries() { await SpecialPowers.pushPrefEnv({set: [ [SUPPORTED_COUNTRIES_PREF, "US,CA,DE"], @@ -49,9 +51,9 @@ add_task(async function test_saveAddress() { await testDialog(EDIT_ADDRESS_DIALOG_URL, win => { let doc = win.document; // Verify labels - is(doc.querySelector("#address-level1-container > span").textContent, "State", + is(doc.querySelector("#address-level1-container > .label-text").textContent, "State", "US address-level1 label should be 'State'"); - is(doc.querySelector("#postal-code-container > span").textContent, "ZIP Code", + is(doc.querySelector("#postal-code-container > .label-text").textContent, "ZIP Code", "US postal-code label should be 'ZIP Code'"); // Input address info and verify move through form with tab keys const keyInputs = [ @@ -72,7 +74,7 @@ add_task(async function test_saveAddress() { "VK_TAB", TEST_ADDRESS_1.organization, "VK_TAB", - TEST_ADDRESS_1.country, + // TEST_ADDRESS_1.country, // Country is already US "VK_TAB", TEST_ADDRESS_1.tel, "VK_TAB", @@ -118,12 +120,15 @@ add_task(async function test_saveAddressCA() { EventUtils.synthesizeKey("Canada", {}, win); await TestUtils.waitForCondition(() => { - return doc.querySelector("#address-level1-container > span").textContent == "Province"; + return doc.querySelector("#address-level1-container > .label-text").textContent == "Province"; }, "Wait for the mutation observer to change the labels"); - is(doc.querySelector("#address-level1-container > span").textContent, "Province", + is(doc.querySelector("#address-level1-container > .label-text").textContent, "Province", "CA address-level1 label should be 'Province'"); - is(doc.querySelector("#postal-code-container > span").textContent, "Postal Code", + is(doc.querySelector("#postal-code-container > .label-text").textContent, "Postal Code", "CA postal-code label should be 'Postal Code'"); + is(doc.querySelector("#address-level3-container").style.display, "none", + "CA address-level3 should be hidden"); + // Input address info and verify move through form with tab keys doc.querySelector("#given-name").focus(); const keyInputs = [ @@ -143,7 +148,7 @@ add_task(async function test_saveAddressCA() { "VK_TAB", TEST_ADDRESS_CA_1["postal-code"], "VK_TAB", - TEST_ADDRESS_CA_1.country, + // TEST_ADDRESS_1.country, // Country is already selected above "VK_TAB", TEST_ADDRESS_CA_1.tel, "VK_TAB", @@ -168,12 +173,14 @@ add_task(async function test_saveAddressDE() { doc.querySelector("#country").focus(); EventUtils.synthesizeKey("Germany", {}, win); await TestUtils.waitForCondition(() => { - return doc.querySelector("#postal-code-container > span").textContent == "Postal Code"; + return doc.querySelector("#postal-code-container > .label-text").textContent == "Postal Code"; }, "Wait for the mutation observer to change the labels"); - is(doc.querySelector("#postal-code-container > span").textContent, "Postal Code", + is(doc.querySelector("#postal-code-container > .label-text").textContent, "Postal Code", "DE postal-code label should be 'Postal Code'"); is(doc.querySelector("#address-level1-container").style.display, "none", "DE address-level1 should be hidden"); + is(doc.querySelector("#address-level3-container").style.display, "none", + "DE address-level3 should be hidden"); // Input address info and verify move through form with tab keys doc.querySelector("#given-name").focus(); const keyInputs = [ @@ -191,7 +198,7 @@ add_task(async function test_saveAddressDE() { "VK_TAB", TEST_ADDRESS_DE_1["address-level2"], "VK_TAB", - TEST_ADDRESS_DE_1.country, + // TEST_ADDRESS_1.country, // Country is already selected above "VK_TAB", TEST_ADDRESS_DE_1.tel, "VK_TAB", @@ -209,6 +216,105 @@ add_task(async function test_saveAddressDE() { await removeAllRecords(); }); +add_task(async function test_saveAddressIE() { + await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => { + let doc = win.document; + // Change country to verify labels + doc.querySelector("#country").focus(); + EventUtils.synthesizeKey("Ireland", {}, win); + await TestUtils.waitForCondition(() => { + return doc.querySelector("#postal-code-container > .label-text").textContent == "Eircode"; + }, "Wait for the mutation observer to change the labels"); + is(doc.querySelector("#postal-code-container > .label-text").textContent, "Eircode", + "IE postal-code label should be 'Eircode'"); + is(doc.querySelector("#address-level1-container > .label-text").textContent, "County", + "IE address-level1 should be 'County'"); + is(doc.querySelector("#address-level3-container > .label-text").textContent, "Townland", + "IE address-level3 should be 'Townland'"); + + // Input address info and verify move through form with tab keys + doc.querySelector("#given-name").focus(); + const keyInputs = [ + TEST_ADDRESS_IE_1["given-name"], + "VK_TAB", + TEST_ADDRESS_IE_1["additional-name"], + "VK_TAB", + TEST_ADDRESS_IE_1["family-name"], + "VK_TAB", + TEST_ADDRESS_IE_1.organization, + "VK_TAB", + TEST_ADDRESS_IE_1["street-address"], + "VK_TAB", + TEST_ADDRESS_IE_1["address-level3"], + "VK_TAB", + TEST_ADDRESS_IE_1["address-level2"], + "VK_TAB", + TEST_ADDRESS_IE_1["address-level1"], + "VK_TAB", + TEST_ADDRESS_IE_1["postal-code"], + "VK_TAB", + // TEST_ADDRESS_1.country, // Country is already selected above + "VK_TAB", + TEST_ADDRESS_IE_1.tel, + "VK_TAB", + TEST_ADDRESS_IE_1.email, + "VK_TAB", + "VK_TAB", + "VK_RETURN", + ]; + keyInputs.forEach(input => EventUtils.synthesizeKey(input, {}, win)); + }); + + let addresses = await getAddresses(); + for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_IE_1)) { + is(addresses[0][fieldName], fieldValue, "check " + fieldName); + } + await removeAllRecords(); +}); + +add_task(async function test_countryFieldLabels() { + await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => { + let doc = win.document; + // Change country to verify labels + doc.querySelector("#country").focus(); + + let mutatableLabels = [ + "postal-code-container", + "address-level1-container", + "address-level2-container", + "address-level3-container", + ].map(containerID => doc.getElementById(containerID).querySelector(":scope > .label-text")); + + for (let countryOption of doc.querySelector("#country").options) { + if (countryOption.value == "") { + info("Skipping the empty option"); + continue; + } + + // Clear L10N attributes and textContent to not leave leftovers between country tests + for (let labelEl of mutatableLabels) { + labelEl.textContent = ""; + delete labelEl.dataset.localization; + } + + info(`Selecting '${countryOption.label}' (${countryOption.value})`); + EventUtils.synthesizeKey(countryOption.label, {}, win); + + // Check that the labels were filled + for (let labelEl of mutatableLabels) { + await TestUtils.waitForCondition(() => labelEl.textContent, + "Wait for label to be populated by the mutation observer"); + isnot(labelEl.textContent, "", + "Ensure textContent is non-empty for: " + countryOption.value); + is(labelEl.dataset.localization, undefined, + "Ensure data-localization was removed: " + countryOption.value); + } + } + + doc.querySelector("#cancel").click(); + }); +}); + add_task(async function test_combined_name_fields() { await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => { let doc = win.document; diff --git a/browser/extensions/formautofill/test/browser/head.js b/browser/extensions/formautofill/test/browser/head.js index b9fb721bc821b..bdd3bda08897b 100644 --- a/browser/extensions/formautofill/test/browser/head.js +++ b/browser/extensions/formautofill/test/browser/head.js @@ -1,5 +1,6 @@ /* exported MANAGE_ADDRESSES_DIALOG_URL, MANAGE_CREDIT_CARDS_DIALOG_URL, EDIT_ADDRESS_DIALOG_URL, EDIT_CREDIT_CARD_DIALOG_URL, BASE_URL, TEST_ADDRESS_1, TEST_ADDRESS_2, TEST_ADDRESS_3, TEST_ADDRESS_4, TEST_ADDRESS_5, TEST_ADDRESS_CA_1, TEST_ADDRESS_DE_1, + TEST_ADDRESS_IE_1, TEST_CREDIT_CARD_1, TEST_CREDIT_CARD_2, TEST_CREDIT_CARD_3, FORM_URL, CREDITCARD_FORM_URL, FTU_PREF, ENABLED_AUTOFILL_ADDRESSES_PREF, AUTOFILL_CREDITCARDS_AVAILABLE_PREF, ENABLED_AUTOFILL_CREDITCARDS_PREF, SUPPORTED_COUNTRIES_PREF, @@ -99,6 +100,21 @@ const TEST_ADDRESS_DE_1 = { email: "timbl@w3.org", }; +const TEST_ADDRESS_IE_1 = { + "given-name": "Bob", + "additional-name": "Z.", + "family-name": "Builder", + organization: "Best Co.", + "street-address": "123 Kilkenny St.", + "address-level3": "Some Townland", + "address-level2": "Dublin", + "address-level1": "Co. Dublin", + "postal-code": "A65 F4E2", + country: "IE", + tel: "+13534564947391", + email: "ie@example.com", +}; + const TEST_CREDIT_CARD_1 = { "cc-name": "John Doe", "cc-number": "4111111111111111", diff --git a/browser/extensions/formautofill/test/unit/test_createRecords.js b/browser/extensions/formautofill/test/unit/test_createRecords.js index c3254cd72ae14..db150fb42a725 100644 --- a/browser/extensions/formautofill/test/unit/test_createRecords.js +++ b/browser/extensions/formautofill/test/unit/test_createRecords.js @@ -69,11 +69,8 @@ const TESTCASES = [ "country": "United States", }, expectedRecord: { - address: [{ - "given-name": "John", - "organization": "Mozilla", - "country": "United States", - }], + // "United States" is not a valid country, only country-name. See isRecordCreatable. + address: [], creditCard: [], }, }, @@ -132,14 +129,14 @@ const TESTCASES = [ formValue: { "given-name": "John", "organization": "Mozilla", - "country": "United States", + "country": "US", "tel": "1234", }, expectedRecord: { address: [{ "given-name": "John", "organization": "Mozilla", - "country": "United States", + "country": "US", "tel": "", }], creditCard: [], @@ -156,14 +153,14 @@ const TESTCASES = [ formValue: { "given-name": "John", "organization": "Mozilla", - "country": "United States", + "country": "US", "tel": "1234567890123456", }, expectedRecord: { address: [{ "given-name": "John", "organization": "Mozilla", - "country": "United States", + "country": "US", "tel": "", }], creditCard: [], @@ -180,14 +177,14 @@ const TESTCASES = [ formValue: { "given-name": "John", "organization": "Mozilla", - "country": "United States", + "country": "US", "tel": "12345###!!!", }, expectedRecord: { address: [{ "given-name": "John", "organization": "Mozilla", - "country": "United States", + "country": "US", "tel": "", }], creditCard: [], diff --git a/browser/extensions/formautofill/test/unit/test_onFormSubmitted.js b/browser/extensions/formautofill/test/unit/test_onFormSubmitted.js index 4634f2c500fbe..773ad126a8e2f 100644 --- a/browser/extensions/formautofill/test/unit/test_onFormSubmitted.js +++ b/browser/extensions/formautofill/test/unit/test_onFormSubmitted.js @@ -58,7 +58,7 @@ const TESTCASES = [ description: "Trigger address saving", formValue: { "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "tel": "1-650-903-0800", }, expectedResult: { @@ -70,7 +70,7 @@ const TESTCASES = [ "street-address": "331 E. Evelyn Avenue", "address-level1": "", "address-level2": "", - "country": "USA", + "country": "US", "email": "", "tel": "1-650-903-0800", }, @@ -109,7 +109,7 @@ const TESTCASES = [ description: "Trigger address and credit card saving", formValue: { "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "tel": "1-650-903-0800", "cc-name": "John Doe", "cc-number": "5105105105105100", @@ -125,7 +125,7 @@ const TESTCASES = [ "street-address": "331 E. Evelyn Avenue", "address-level1": "", "address-level2": "", - "country": "USA", + "country": "US", "email": "", "tel": "1-650-903-0800", }, @@ -148,7 +148,7 @@ const TESTCASES = [ description: "Profile saved with trimmed string", formValue: { "street-addr": "331 E. Evelyn Avenue ", - "country": "USA", + "country": "US", "tel": " 1-650-903-0800", }, expectedResult: { @@ -160,7 +160,7 @@ const TESTCASES = [ "street-address": "331 E. Evelyn Avenue", "address-level1": "", "address-level2": "", - "country": "USA", + "country": "US", "email": "", "tel": "1-650-903-0800", }, @@ -174,7 +174,7 @@ const TESTCASES = [ description: "Eliminate the field that is empty after trimmed", formValue: { "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": " ", "tel": "1-650-903-0800", }, @@ -187,7 +187,7 @@ const TESTCASES = [ "street-address": "331 E. Evelyn Avenue", "address-level1": "", "address-level2": "", - "country": "USA", + "country": "US", "email": "", "tel": "1-650-903-0800", }, @@ -202,7 +202,7 @@ const TESTCASES = [ formValue: { "address-level1": "CA", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", }, expectedResult: { formSubmission: true, @@ -213,7 +213,7 @@ const TESTCASES = [ "address-level1": "CA", "address-level2": "", "street-address": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": "", "tel": "", }, @@ -228,7 +228,7 @@ const TESTCASES = [ formValue: { "address-level1": "ca", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", }, expectedResult: { formSubmission: true, @@ -239,7 +239,7 @@ const TESTCASES = [ "address-level1": "CA", "address-level2": "", "street-address": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": "", "tel": "", }, @@ -254,7 +254,7 @@ const TESTCASES = [ formValue: { "address-level1": "AR", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", }, expectedResult: { formSubmission: true, @@ -265,7 +265,7 @@ const TESTCASES = [ "address-level1": "AR", "address-level2": "", "street-address": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": "", "tel": "", }, @@ -280,7 +280,7 @@ const TESTCASES = [ formValue: { "address-level1": "US-CA", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", }, expectedResult: { formSubmission: true, @@ -291,7 +291,7 @@ const TESTCASES = [ "address-level1": "CA", "address-level2": "", "street-address": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": "", "tel": "", }, @@ -306,7 +306,7 @@ const TESTCASES = [ formValue: { "address-level1": "US-AZ", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", }, expectedResult: { formSubmission: true, @@ -317,7 +317,7 @@ const TESTCASES = [ "address-level1": "AZ", "address-level2": "", "street-address": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": "", "tel": "", }, @@ -332,7 +332,7 @@ const TESTCASES = [ formValue: { "address-level1": "Ariz", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", }, expectedResult: { formSubmission: true, @@ -343,7 +343,7 @@ const TESTCASES = [ "address-level1": "Arizonac", "address-level2": "", "street-address": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "email": "", "tel": "", }, @@ -358,7 +358,7 @@ const TESTCASES = [ formValue: { "address-level1": ["AL", "AK", "AP"], "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "tel": "1-650-903-0800", }, expectedResult: { @@ -370,7 +370,7 @@ const TESTCASES = [ "street-address": "331 E. Evelyn Avenue", "address-level1": "", "address-level2": "", - "country": "USA", + "country": "US", "tel": "1-650-903-0800", "email": "", }, @@ -385,7 +385,7 @@ const TESTCASES = [ formValue: { "address-level1": "", "street-addr": "331 E. Evelyn Avenue", - "country": "USA", + "country": "US", "tel": "1-650-903-0800", }, expectedResult: { @@ -397,7 +397,7 @@ const TESTCASES = [ "street-address": "331 E. Evelyn Avenue", "address-level1": "", "address-level2": "", - "country": "USA", + "country": "US", "tel": "1-650-903-0800", "email": "", }, @@ -584,7 +584,8 @@ TESTCASES.forEach(testcase => { FormAutofillContent.notify(form); Assert.equal(FormAutofillContent._onFormSubmit.called, - testcase.expectedResult.formSubmission); + testcase.expectedResult.formSubmission, + "Check expected onFormSubmit.called"); if (FormAutofillContent._onFormSubmit.called) { Assert.deepEqual(FormAutofillContent._onFormSubmit.args[0][0], testcase.expectedResult.records); diff --git a/browser/extensions/formautofill/test/unit/test_parseAddressFormat.js b/browser/extensions/formautofill/test/unit/test_parseAddressFormat.js index e3573ab14ff50..e592db003ce08 100644 --- a/browser/extensions/formautofill/test/unit/test_parseAddressFormat.js +++ b/browser/extensions/formautofill/test/unit/test_parseAddressFormat.js @@ -38,6 +38,18 @@ add_task(async function test_parseAddressFormat() { {fieldId: "address-level2"}, ], }, + { + fmt: "%N%n%O%n%A%n%D%n%C%n%S %Z", // IE + parsed: [ + {fieldId: "name", newLine: true}, + {fieldId: "organization", newLine: true}, + {fieldId: "street-address", newLine: true}, + {fieldId: "address-level3", newLine: true}, + {fieldId: "address-level2", newLine: true}, + {fieldId: "address-level1"}, + {fieldId: "postal-code"}, + ], + }, ]; Assert.throws(() => FormAutofillUtils.parseAddressFormat(), diff --git a/browser/extensions/formautofill/test/unit/test_transformFields.js b/browser/extensions/formautofill/test/unit/test_transformFields.js index 61003f17b89a3..8a3f345ba3751 100644 --- a/browser/extensions/formautofill/test/unit/test_transformFields.js +++ b/browser/extensions/formautofill/test/unit/test_transformFields.js @@ -414,7 +414,7 @@ const ADDRESS_NORMALIZE_TESTCASES = [ description: "Has unsupported \"country\"", address: { "given-name": "John", // Make sure it won't be an empty record. - "country": "TV", + "country": "XX", }, expectedResult: { "country": undefined, diff --git a/toolkit/components/mozintl/mozIMozIntl.idl b/toolkit/components/mozintl/mozIMozIntl.idl index d195fb439f284..8499a905d3ff2 100644 --- a/toolkit/components/mozintl/mozIMozIntl.idl +++ b/toolkit/components/mozintl/mozIMozIntl.idl @@ -50,11 +50,20 @@ interface mozIMozIntl : nsISupports */ jsval getLanguageDisplayNames(in jsval locales, in jsval langCodes); + /** + * Returns a list of region codes. + * + * Example: + * let regs = getRegions(undefined); + * regs === new Map([["US", "United States"], ["CA", "Canada"], ["MX", "Mexico"]]) + */ + jsval getRegions(in jsval locales); + /** * Returns a list of region names formatted for display. * * Example: - * let regs = getLanguageDisplayNames(["pl"], ["US", "CA", "MX"]); + * let regs = getRegionDisplayNames(["pl"], ["US", "CA", "MX"]); * regs === ["Stany Zjednoczone", "Kanada", "Meksyk"] */ jsval getRegionDisplayNames(in jsval locales, in jsval regionCodes); @@ -63,7 +72,7 @@ interface mozIMozIntl : nsISupports * Returns a list of locale names formatted for display. * * Example: - * let locs = getLanguageDisplayNames(["pl"], ["sr-RU", "es-MX", "fr-CA"]); + * let locs = getLocaleDisplayNames(["pl"], ["sr-RU", "es-MX", "fr-CA"]); * locs === ["Serbski (Rosja)", "HiszpaÅ„ski (Meksyk)", "Francuski (Kanada)"] */ jsval getLocaleDisplayNames(in jsval locales, in jsval localeCodes); diff --git a/toolkit/components/mozintl/mozIntl.js b/toolkit/components/mozintl/mozIntl.js index eca985fcdb3e2..927623fffa278 100644 --- a/toolkit/components/mozintl/mozIntl.js +++ b/toolkit/components/mozintl/mozIntl.js @@ -199,19 +199,44 @@ class MozIntl { }); } + getRegions(locales) { + if (locales !== undefined) { + throw new Error("First argument support not implemented yet"); + } + + if (!this._cache.hasOwnProperty("regionBundle")) { + const regionBundle = Services.strings.createBundle( + "chrome://global/locale/regionNames.properties"); + this._cache.regionBundle = regionBundle; + } + + if (!this._cache.hasOwnProperty("regionMap")) { + this._cache.regionMap = new Map([...this._cache.regionBundle.getSimpleEnumeration()].map(prop => { + prop.QueryInterface(Ci.nsIPropertyElement); + return [prop.key.toUpperCase(), prop.value]; + })); + } + + return this._cache.regionMap; + } + getRegionDisplayNames(locales, regionCodes) { if (locales !== undefined) { throw new Error("First argument support not implemented yet"); } - const regionBundle = Services.strings.createBundle( - "chrome://global/locale/regionNames.properties"); + + if (!this._cache.hasOwnProperty("regionBundle")) { + const regionBundle = Services.strings.createBundle( + "chrome://global/locale/regionNames.properties"); + this._cache.regionBundle = regionBundle; + } return regionCodes.map(regionCode => { if (typeof regionCode !== "string") { throw new TypeError("All region codes must be strings."); } try { - return regionBundle.GetStringFromName(regionCode.toLowerCase()); + return this._cache.regionBundle.GetStringFromName(regionCode.toLowerCase()); } catch (e) { return regionCode.toUpperCase(); // Fall back to raw region subtag. } diff --git a/toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js b/toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js index b8027f55ad7af..47d0af6443ede 100644 --- a/toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js +++ b/toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js @@ -5,6 +5,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); const gLangDN = Services.intl.getLanguageDisplayNames.bind(Services.intl, undefined); +const gReg = Services.intl.getRegions.bind(Services.intl, undefined); const gRegDN = Services.intl.getRegionDisplayNames.bind(Services.intl, undefined); const gLocDN = Services.intl.getLocaleDisplayNames.bind(Services.intl, undefined); @@ -81,3 +82,10 @@ add_test(function test_invalid_regions() { Assert.throws(() => gRegDN([true]), /All region codes must be strings/); run_next_test(); }); + +add_test(function test_region() { + let regions = gReg(undefined); + equal(regions[Symbol.toStringTag], "Map", "Check type is Map"); + equal(regions.get("US"), "United States", "Check US name"); + run_next_test(); +}); -- GitLab