Bug 1481972 - Add remaining countries to address autofill countries list. r=MattN
authorJared Wein <jwein@mozilla.com>
Sun, 23 Sep 2018 23:50:03 -0700
changeset 493586 29e7b5d5f5e4252ab268e176ee5576f4db146f7a
parent 493585 5313921e7dee83ab65f358b723f4228b46937686
child 493587 095ec59a8800360154df6668394803e5a84d031c
child 493611 2defd19a1467b02aa6fcf130cfada6dcc994ce0d
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1481972
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
browser/app/profile/firefox.js
browser/components/payments/content/paymentDialogFrameScript.js
browser/components/payments/content/paymentDialogWrapper.js
browser/components/payments/res/containers/address-form.js
browser/components/payments/res/unprivileged-fallbacks.js
browser/components/payments/test/browser/head.js
browser/extensions/formautofill/FormAutofill.jsm
browser/extensions/formautofill/FormAutofillHandler.jsm
browser/extensions/formautofill/FormAutofillParent.jsm
browser/extensions/formautofill/FormAutofillStorage.jsm
browser/extensions/formautofill/FormAutofillUtils.jsm
browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
browser/extensions/formautofill/addressmetadata/addressReferences.js
browser/extensions/formautofill/addressmetadata/addressReferencesExt.js
browser/extensions/formautofill/content/autofillEditForms.js
browser/extensions/formautofill/content/editAddress.xhtml
browser/extensions/formautofill/locales/en-US/formautofill.properties
browser/extensions/formautofill/skin/shared/editAddress.css
browser/extensions/formautofill/test/browser/browser_editAddressDialog.js
browser/extensions/formautofill/test/browser/head.js
browser/extensions/formautofill/test/unit/test_createRecords.js
browser/extensions/formautofill/test/unit/test_onFormSubmitted.js
browser/extensions/formautofill/test/unit/test_parseAddressFormat.js
browser/extensions/formautofill/test/unit/test_transformFields.js
toolkit/components/mozintl/mozIMozIntl.idl
toolkit/components/mozintl/mozIntl.js
toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1679,18 +1679,17 @@ pref("extensions.formautofill.creditCard
 // 3: submitted an autofill'ed credit card form
 pref("extensions.formautofill.creditCards.used", 0);
 pref("extensions.formautofill.firstTimeUse", true);
 pref("extensions.formautofill.heuristics.enabled", true);
 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
 pref("extensions.formautofill.supportedCountries", "US");
 pref("extensions.formautofill.supportRTL", false);
 #endif
 
 // Whether or not to restore a session with lazy-browser tabs.
--- a/browser/components/payments/content/paymentDialogFrameScript.js
+++ b/browser/components/payments/content/paymentDialogFrameScript.js
@@ -69,17 +69,17 @@ let PaymentFrameScript = {
 
   /**
    * Expose privileged utility functions to the unprivileged page.
    */
   exposeUtilityFunctions() {
     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);
       },
 
       getCreditCardNetworks() {
         let networks = FormAutofillUtils.getCreditCardNetworks();
         return Cu.cloneInto(networks, waivedContent);
--- a/browser/components/payments/content/paymentDialogWrapper.js
+++ b/browser/components/payments/content/paymentDialogWrapper.js
@@ -131,16 +131,17 @@ var paymentDialogWrapper = {
       throw new Error(`Shipping address not found: ${guid}`);
     }
 
     let address = this.createPaymentAddress({
       country: addressData.country,
       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,
       phone: addressData.tel,
     });
 
     return address;
   },
--- a/browser/components/payments/res/containers/address-form.js
+++ b/browser/components/payments/res/containers/address-form.js
@@ -83,17 +83,17 @@ export default class AddressForm extends
       this.body.appendChild(form);
 
       let record = {};
       this.formHandler = new EditAddress({
         form,
       }, 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,
       // which update field validity. By adding our event listeners after this constructor,
       // validity will be updated before our handlers get the event
       this.form.addEventListener("input", this);
       this.form.addEventListener("invalid", this);
       this.form.addEventListener("change", this);
--- a/browser/components/payments/res/unprivileged-fallbacks.js
+++ b/browser/components/payments/res/unprivileged-fallbacks.js
@@ -45,20 +45,22 @@ var PaymentDialogUtils = {
       "unionpay",
       "visa",
     ];
   },
   isCCNumber(str) {
     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: [
           {
             fieldId: "name",
             newLine: true,
           },
           {
@@ -72,29 +74,31 @@ var PaymentDialogUtils = {
           {fieldId: "postal-code"},
           {fieldId: "address-level2"},
         ],
         postalCodePattern: "\\d{5}",
       };
     }
 
     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"},
         {fieldId: "address-level1"},
         {fieldId: "postal-code"},
         {fieldId: "organization"},
       ],
       // 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() {
     let prefValues = {
       saveCreditCardDefaultChecked: false,
       saveAddressDefaultChecked: true,
     };
     return prefValues;
--- a/browser/components/payments/test/browser/head.js
+++ b/browser/components/payments/test/browser/head.js
@@ -382,17 +382,17 @@ async function navigateToAddAddressPage(
   addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] a.add-link",
   initialPageId: "payment-summary",
 }) {
   await spawnPaymentDialogTask(frame, async (options) => {
     let {
       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;
     }, "Check summary page state");
 
     // click through to add/edit address page
     info("navigateToAddAddressPage: click the link");
     let addLink = content.document.querySelector(options.addLinkSelector);
--- a/browser/extensions/formautofill/FormAutofill.jsm
+++ b/browser/extensions/formautofill/FormAutofill.jsm
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 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";
 const CREDITCARDS_USED_STATUS_PREF = "extensions.formautofill.creditCards.used";
 const DEFAULT_REGION_PREF = "browser.search.region";
 const ENABLED_AUTOFILL_ADDRESSES_PREF = "extensions.formautofill.addresses.enabled";
 const ENABLED_AUTOFILL_CREDITCARDS_PREF = "extensions.formautofill.creditCards.enabled";
 const SUPPORTED_COUNTRIES_PREF = "extensions.formautofill.supportedCountries";
@@ -68,8 +69,12 @@ XPCOMUtils.defineLazyPreferenceGetter(Fo
                                       "_isAutofillCreditCardsEnabled", ENABLED_AUTOFILL_CREDITCARDS_PREF);
 XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
                                       "isAutofillAddressesFirstTimeUse", ADDRESSES_FIRST_TIME_USE_PREF);
 XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
                                       "AutofillCreditCardsUsedStatus", CREDITCARDS_USED_STATUS_PREF);
 XPCOMUtils.defineLazyPreferenceGetter(FormAutofill,
                                       "supportedCountries", SUPPORTED_COUNTRIES_PREF, null, null,
                                       val => val.split(","));
+
+XPCOMUtils.defineLazyGetter(FormAutofill, "countries", () => {
+  return Services.intl.getRegions(undefined);
+});
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -550,16 +550,23 @@ class FormAutofillAddressSection extends
     return this.fieldDetails.length >= FormAutofillUtils.AUTOFILL_FIELDS_THRESHOLD;
   }
 
   isEnabled() {
     return FormAutofill.isAutofillAddressesEnabled;
   }
 
   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)) {
       if (!record[key]) {
         continue;
       }
       if (FormAutofillUtils.getCategoryFromFieldName(key) == "name") {
         hasName = 1;
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -49,16 +49,17 @@ this.log = null;
 FormAutofill.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]);
 
 const {
   ENABLED_AUTOFILL_ADDRESSES_PREF,
   ENABLED_AUTOFILL_CREDITCARDS_PREF,
 } = FormAutofill;
 
 const {
+  ADDRESSES_COLLECTION_NAME,
   CREDITCARDS_COLLECTION_NAME,
 } = FormAutofillUtils;
 
 function FormAutofillParent() {
   // Lazily load the storage JSM to avoid disk I/O until absolutely needed.
   // Once storage is loaded we need to update saved field names and inform content processes.
   XPCOMUtils.defineLazyGetter(this, "formAutofillStorage", () => {
     let {formAutofillStorage} = ChromeUtils.import("resource://formautofill/FormAutofillStorage.jsm", {});
@@ -340,19 +341,27 @@ FormAutofillParent.prototype = {
         record["cc-number-decrypted"] = await MasterPassword.decrypt(record["cc-number-encrypted"]);
       }
 
       // Filter "cc-number" based on the decrypted one.
       if (info.fieldName == "cc-number") {
         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);
   },
 
   _updateSavedFieldNames() {
     log.debug("_updateSavedFieldNames");
 
--- a/browser/extensions/formautofill/FormAutofillStorage.jsm
+++ b/browser/extensions/formautofill/FormAutofillStorage.jsm
@@ -17,16 +17,17 @@
  *       version,              // schema version in integer
  *
  *       // address fields
  *       given-name,
  *       additional-name,
  *       family-name,
  *       organization,         // Company
  *       street-address,       // (Multiline)
+ *       address-level3,       // Suburb/Sublocality
  *       address-level2,       // City/Town
  *       address-level1,       // Province (Standardized code if possible)
  *       postal-code,
  *       country,              // ISO 3166
  *       tel,                  // Stored in E.164 format
  *       email,
  *
  *       // computed fields (These fields are computed based on the above fields
@@ -160,16 +161,17 @@ const ADDRESS_SCHEMA_VERSION = 1;
 const CREDIT_CARD_SCHEMA_VERSION = 1;
 
 const VALID_ADDRESS_FIELDS = [
   "given-name",
   "additional-name",
   "family-name",
   "organization",
   "street-address",
+  "address-level3",
   "address-level2",
   "address-level1",
   "postal-code",
   "country",
   "tel",
   "email",
 ];
 
@@ -1292,17 +1294,17 @@ class AutofillRecords {
 }
 
 class Addresses extends AutofillRecords {
   constructor(store) {
     super(store, "addresses", VALID_ADDRESS_FIELDS, VALID_ADDRESS_COMPUTED_FIELDS, ADDRESS_SCHEMA_VERSION);
   }
 
   _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"];
     }
   }
 
   async computeFields(address) {
     // NOTE: Remember to bump the schema version number if any of the existing
     //       computing algorithm changes. (No need to bump when just adding new
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -67,17 +67,22 @@ let AddressDataLoader = {
     } catch (e) {
       // Will return only address references if extension loading failed or empty sandbox if
       // address references loading failed.
       return sandbox;
     }
 
     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;
   },
 
   /**
    * Convert certain properties' string value into array. We should make sure
    * the cached data is parsed.
@@ -265,16 +270,17 @@ this.FormAutofillUtils = {
    */
   getAddressLabel(address, addressFields = null) {
     // TODO: Implement a smarter way for deciding what to display
     //       as option text. Possibly improve the algorithm in
     //       ProfileAutoCompleteResult.jsm and reuse it here.
     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)
       "country-name",    // Country name
       "postal-code",     // Postal code
       "tel",             // Phone number
       "email",           // Email address
     ];
@@ -366,20 +372,20 @@ this.FormAutofillUtils = {
 
   /**
    * Get country address data and fallback to US if not found.
    * See AddressDataLoader._loadData for more details of addressData structure.
    * @param {string} [country=FormAutofill.DEFAULT_REGION]
    *        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) {
     let metadata = AddressDataLoader.getData(country, level1);
     if (!metadata) {
       if (level1) {
         return null;
       }
@@ -397,28 +403,34 @@ this.FormAutofillUtils = {
     return metadata;
   },
 
   /**
    * Get country address data with default locale.
    * @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);
     return metadata && metadata.defaultLocale;
   },
 
   /**
    * Get country address data with all locales.
    * @param {string} country
    * @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);
     return metadata && [metadata.defaultLocale, ...metadata.locales];
   },
 
   /**
    * Get the collators based on the specified country.
@@ -459,16 +471,17 @@ this.FormAutofillUtils = {
     // Based on the list of fields abbreviations in
     // https://github.com/googlei18n/libaddressinput/wiki/AddressValidationMetadata
     const fieldsLookup = {
       N: "name",
       O: "organization",
       A: "street-address",
       S: "address-level1",
       C: "address-level2",
+      D: "address-level3",
       Z: "postal-code",
       n: "newLine",
     };
 
     return fmt.match(/%[^%]/g).reduce((parsed, part) => {
       // Take the first letter of each segment and try to identify it
       let fieldId = fieldsLookup[part[1]];
       // Early return if cannot identify part.
@@ -491,22 +504,30 @@ this.FormAutofillUtils = {
    * Use alternative country name list to identify a country code from a
    * specified country name.
    * @param   {string} countryName A country name to be identified
    * @param   {string} [countrySpecified] A country code indicating that we only
    *                                      search its alternative names if specified.
    * @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) {
         reAlternativeCountryNames = this._reAlternativeCountryNames[country] = [];
       }
 
       for (let i = 0; i < alternativeCountryNames.length; i++) {
         let name = alternativeCountryNames[i];
@@ -771,28 +792,37 @@ this.FormAutofillUtils = {
     return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
   },
 
   /**
    * Get formatting information of a given country
    * @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,
     };
   },
 
   /**
    * Localize "data-localization" or "data-localization-region" attributes.
    * @param {Element} element
    * @param {string} attributeName
    */
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -215,16 +215,17 @@ class AddressResult extends ProfileAutoC
         "tel-local-prefix",
         "tel-local-suffix",
       ],
     };
 
     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)
       "country-name",    // Country name
       "postal-code",     // Postal code
       "tel",             // Phone number
       "email",           // Email address
     ];
--- a/browser/extensions/formautofill/addressmetadata/addressReferences.js
+++ b/browser/extensions/formautofill/addressmetadata/addressReferences.js
@@ -5,19 +5,270 @@
 /* exported addressData */
 /* eslint max-len: 0 */
 
 "use strict";
 
 // 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"},
 };
--- a/browser/extensions/formautofill/addressmetadata/addressReferencesExt.js
+++ b/browser/extensions/formautofill/addressmetadata/addressReferencesExt.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* exported addressDataExt */
 /* eslint max-len: 0 */
 
 "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
 //       bug 1370193.
 var addressDataExt = {
   "data/US": {
     alternative_names: ["US", "United States of America", "United States", "America", "U.S.", "USA", "U.S.A.", "U.S.A"],
     fmt: "%N%n%A%n%C%S%n%Z%O",
--- a/browser/extensions/formautofill/content/autofillEditForms.js
+++ b/browser/extensions/formautofill/content/autofillEditForms.js
@@ -117,26 +117,29 @@ class EditAutofillForm {
 
 class EditAddress extends EditAutofillForm {
   /**
    * @param {HTMLElement[]} elements
    * @param {object} record
    * @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();
     // Need to populate the countries before trying to set the initial country.
     // Also need to use this._record so it has the default country selected.
     this.loadRecord(record);
     this.attachEventListeners();
 
@@ -144,17 +147,17 @@ class EditAddress extends EditAutofillFo
       this.form.setAttribute("novalidate", "true");
     }
   }
 
   loadRecord(record) {
     this._record = record;
     if (!record) {
       record = {
-        country: this.supportedCountries.find(supported => supported == this.DEFAULT_REGION),
+        country: this.DEFAULT_REGION,
       };
     }
     super.loadRecord(record);
     this.formatForm(record.country);
   }
 
   /**
    * `mailing-address` is a special attribute token to indicate mailing fields + country.
@@ -200,21 +203,25 @@ class EditAddress extends EditAutofillFo
 
   /**
    * Format the form based on country. The address-level1 and postal-code labels
    * should be specific to the given country.
    * @param  {string} country
    */
   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;
     let fieldClasses = EditAddress.computeVisibleFields(mailingFieldsOrder, addressFields);
     this.arrangeFields(fieldClasses);
     this.updatePostalCodeValidation(postalCodePattern);
   }
 
@@ -223,16 +230,17 @@ class EditAddress extends EditAutofillFo
    *
    * @param {object[]} fieldsOrder array of objects with `fieldId` and optional `newLine` properties
    */
   arrangeFields(fieldsOrder) {
     let fields = [
       "name",
       "organization",
       "street-address",
+      "address-level3",
       "address-level2",
       "address-level1",
       "postal-code",
       "country",
       "tel",
       "email",
     ];
     let inputs = [];
@@ -268,20 +276,22 @@ class EditAddress extends EditAutofillFo
       postalCodeInput.setAttribute("pattern", postalCodePattern);
     } else {
       postalCodeInput.removeAttribute("pattern");
     }
   }
 
   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);
   }
 
   handleChange(event) {
     if (event.target == this._elements.country) {
       this.formatForm(event.target.value);
--- a/browser/extensions/formautofill/content/editAddress.xhtml
+++ b/browser/extensions/formautofill/content/editAddress.xhtml
@@ -39,19 +39,23 @@
     <label id="organization-container" class="container">
       <input id="organization" type="text"/>
       <span data-localization="organization2" class="label-text"/>
     </label>
     <label id="street-address-container" class="container">
       <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"/>
       <span class="label-text"/>
     </label>
     <label id="postal-code-container" class="container">
       <input id="postal-code" type="text" required="required"/>
       <span class="label-text"/>
@@ -76,31 +80,31 @@
     <button id="save" disabled="disabled" data-localization="saveBtnLabel"/>
     <span id="country-warning-message" data-localization="countryWarningMessage2"/>
   </div>
   <script type="application/javascript"><![CDATA[
     "use strict";
 
     let {
       DEFAULT_REGION,
-      supportedCountries,
+      countries,
     } = FormAutofill;
     let {
       getFormFormat,
     } = FormAutofillUtils;
     let record = window.arguments && window.arguments[0];
     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,
     });
 
     /* import-globals-from editDialog.js */
     new EditAddressDialog({
       title: document.querySelector("title"),
       fieldContainer,
       controlsContainer: document.getElementById("controls-container"),
--- a/browser/extensions/formautofill/locales/en-US/formautofill.properties
+++ b/browser/extensions/formautofill/locales/en-US/formautofill.properties
@@ -114,21 +114,64 @@ manageDialogsWidth = 560px
 # in browser preferences.
 addNewAddressTitle = Add New Address
 editAddressTitle = Edit Address
 givenName = First Name
 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
 cancelBtnLabel = Cancel
 saveBtnLabel = Save
 countryWarningMessage2 = Form Autofill is currently available only for certain countries.
 
 # LOCALIZATION NOTE (addNewCreditCardTitle, editCreditCardTitle): The dialog title for creating or editing
--- a/browser/extensions/formautofill/skin/shared/editAddress.css
+++ b/browser/extensions/formautofill/skin/shared/editAddress.css
@@ -22,16 +22,18 @@
   flex-grow: 1;
 }
 
 #country-container {
   /* The country dropdown has a different intrinsic (content) width than the
      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));
 }
 
 
 /* Begin name field rules */
 
 #name-container input {
   /* Override the default @size="20" on <input>, which acts like a min-width, not
    * allowing the fields to shrink with flexbox as small as they need to to match
--- a/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js
+++ b/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js
@@ -1,10 +1,12 @@
 "use strict";
 
+requestLongerTimeout(6);
+
 add_task(async function setup_supportedCountries() {
   await SpecialPowers.pushPrefEnv({set: [
     [SUPPORTED_COUNTRIES_PREF, "US,CA,DE"],
   ]});
 });
 
 
 add_task(async function test_cancelEditAddressDialog() {
@@ -44,19 +46,19 @@ add_task(async function test_defaultCoun
   });
   SpecialPowers.pushPrefEnv({set: [[DEFAULT_REGION_PREF, "US"]]});
 });
 
 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 = [
       "VK_TAB",
       TEST_ADDRESS_1["given-name"],
       "VK_TAB",
       TEST_ADDRESS_1["additional-name"],
       "VK_TAB",
@@ -67,17 +69,17 @@ add_task(async function test_saveAddress
       TEST_ADDRESS_1["address-level2"],
       "VK_TAB",
       TEST_ADDRESS_1["address-level1"],
       "VK_TAB",
       TEST_ADDRESS_1["postal-code"],
       "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",
       TEST_ADDRESS_1.email,
       "VK_TAB",
       "VK_TAB",
       "VK_RETURN",
     ];
@@ -113,22 +115,25 @@ add_task(async function test_editAddress
 add_task(async function test_saveAddressCA() {
   await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => {
     let doc = win.document;
     // Change country to verify labels
     doc.querySelector("#country").focus();
     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 = [
       TEST_ADDRESS_CA_1["given-name"],
       "VK_TAB",
       TEST_ADDRESS_CA_1["additional-name"],
       "VK_TAB",
       TEST_ADDRESS_CA_1["family-name"],
@@ -138,17 +143,17 @@ add_task(async function test_saveAddress
       TEST_ADDRESS_CA_1["street-address"],
       "VK_TAB",
       TEST_ADDRESS_CA_1["address-level2"],
       "VK_TAB",
       TEST_ADDRESS_CA_1["address-level1"],
       "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",
       TEST_ADDRESS_CA_1.email,
       "VK_TAB",
       "VK_TAB",
       "VK_RETURN",
     ];
@@ -163,22 +168,24 @@ add_task(async function test_saveAddress
 
 add_task(async function test_saveAddressDE() {
   await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => {
     let doc = win.document;
     // Change country to verify labels
     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 = [
       TEST_ADDRESS_DE_1["given-name"],
       "VK_TAB",
       TEST_ADDRESS_DE_1["additional-name"],
       "VK_TAB",
       TEST_ADDRESS_DE_1["family-name"],
@@ -186,17 +193,17 @@ add_task(async function test_saveAddress
       TEST_ADDRESS_DE_1.organization,
       "VK_TAB",
       TEST_ADDRESS_DE_1["street-address"],
       "VK_TAB",
       TEST_ADDRESS_DE_1["postal-code"],
       "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",
       TEST_ADDRESS_DE_1.email,
       "VK_TAB",
       "VK_TAB",
       "VK_RETURN",
     ];
@@ -204,16 +211,115 @@ add_task(async function test_saveAddress
   });
   let addresses = await getAddresses();
   for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_DE_1)) {
     is(addresses[0][fieldName], fieldValue, "check " + fieldName);
   }
   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;
     let givenNameField = doc.querySelector("#given-name");
     let addtlNameField = doc.querySelector("#additional-name");
     let familyNameField = doc.querySelector("#family-name");
 
     function getComputedPropertyValue(field, property) {
--- a/browser/extensions/formautofill/test/browser/head.js
+++ b/browser/extensions/formautofill/test/browser/head.js
@@ -1,10 +1,11 @@
 /* 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,
             SYNC_USERNAME_PREF, SYNC_ADDRESSES_PREF, SYNC_CREDITCARDS_PREF, SYNC_CREDITCARDS_AVAILABLE_PREF, CREDITCARDS_USED_STATUS_PREF,
             DEFAULT_REGION_PREF,
             sleep, expectPopupOpen, openPopupOn, expectPopupClose, closePopup, clickDoorhangerButton,
             getAddresses, saveAddress, removeAddresses, saveCreditCard,
             getDisplayedPopupItems, getDoorhangerCheckbox, waitForMasterPasswordDialog,
@@ -94,16 +95,31 @@ const TEST_ADDRESS_DE_1 = {
   "street-address": "Geb\u00E4ude 3, 4. Obergeschoss\nSchlesische Stra\u00DFe 27",
   "address-level2": "Berlin",
   "postal-code": "10997",
   country: "DE",
   tel: "+4930983333000",
   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",
   "cc-exp-month": 4,
   "cc-exp-year": new Date().getFullYear(),
   "cc-type": "visa",
 };
 
--- a/browser/extensions/formautofill/test/unit/test_createRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_createRecords.js
@@ -64,21 +64,18 @@ const TESTCASES = [
                 <input id="country" autocomplete="country">
                </form>`,
     formValue: {
       "given-name": "John",
       "organization": "Mozilla",
       "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: [],
     },
   },
   {
     description: "\"country\" using heuristics should be identified aggressively",
     document: `<form>
                 <input id="given-name" autocomplete="given-name">
                 <input id="organization" autocomplete="organization">
@@ -127,72 +124,72 @@ const TESTCASES = [
                 <input id="given-name" autocomplete="given-name">
                 <input id="organization" autocomplete="organization">
                 <input id="country" autocomplete="country">
                 <input id="tel" autocomplete="tel-national">
                </form>`,
     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: [],
     },
   },
   {
     description: "\"tel\" should be removed if it's too long",
     document: `<form>
                 <input id="given-name" autocomplete="given-name">
                 <input id="organization" autocomplete="organization">
                 <input id="country" autocomplete="country">
                 <input id="tel" autocomplete="tel-national">
                </form>`,
     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: [],
     },
   },
   {
     description: "\"tel\" should be removed if it contains invalid characters",
     document: `<form>
                 <input id="given-name" autocomplete="given-name">
                 <input id="organization" autocomplete="organization">
                 <input id="country" autocomplete="country">
                 <input id="tel" autocomplete="tel-national">
                </form>`,
     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: [],
     },
   },
   {
     description: "All name related fields should be counted as 1 field only.",
     document: `<form>
--- a/browser/extensions/formautofill/test/unit/test_onFormSubmitted.js
+++ b/browser/extensions/formautofill/test/unit/test_onFormSubmitted.js
@@ -53,29 +53,29 @@ const TESTCASES = [
     expectedResult: {
       formSubmission: false,
     },
   },
   {
     description: "Trigger address saving",
     formValue: {
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
       "tel": "1-650-903-0800",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "street-address": "331 E. Evelyn Avenue",
             "address-level1": "",
             "address-level2": "",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "1-650-903-0800",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
@@ -104,33 +104,33 @@ 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",
       "cc-exp-month": 12,
       "cc-exp-year": 2000,
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "street-address": "331 E. Evelyn Avenue",
             "address-level1": "",
             "address-level2": "",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "1-650-903-0800",
           },
           untouchedFields: [],
         }],
         creditCard: [{
           guid: null,
           record: {
@@ -143,266 +143,266 @@ 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: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "street-address": "331 E. Evelyn Avenue",
             "address-level1": "",
             "address-level2": "",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "1-650-903-0800",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     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",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "street-address": "331 E. Evelyn Avenue",
             "address-level1": "",
             "address-level2": "",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "1-650-903-0800",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Save state with regular select option",
     formValue: {
       "address-level1": "CA",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "address-level1": "CA",
             "address-level2": "",
             "street-address": "331 E. Evelyn Avenue",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Save state with lowercase value",
     formValue: {
       "address-level1": "ca",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "address-level1": "CA",
             "address-level2": "",
             "street-address": "331 E. Evelyn Avenue",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Save state with a country code prefixed to the label",
     formValue: {
       "address-level1": "AR",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "address-level1": "AR",
             "address-level2": "",
             "street-address": "331 E. Evelyn Avenue",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Save state with a country code prefixed to the value",
     formValue: {
       "address-level1": "US-CA",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "address-level1": "CA",
             "address-level2": "",
             "street-address": "331 E. Evelyn Avenue",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Save state with a country code prefixed to the value and label",
     formValue: {
       "address-level1": "US-AZ",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "address-level1": "AZ",
             "address-level2": "",
             "street-address": "331 E. Evelyn Avenue",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Should save select label instead when failed to abbreviate the value",
     formValue: {
       "address-level1": "Ariz",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "address-level1": "Arizonac",
             "address-level2": "",
             "street-address": "331 E. Evelyn Avenue",
-            "country": "USA",
+            "country": "US",
             "email": "",
             "tel": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Shouldn't save select with multiple selections",
     formValue: {
       "address-level1": ["AL", "AK", "AP"],
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
       "tel": "1-650-903-0800",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "street-address": "331 E. Evelyn Avenue",
             "address-level1": "",
             "address-level2": "",
-            "country": "USA",
+            "country": "US",
             "tel": "1-650-903-0800",
             "email": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
   },
   {
     description: "Shouldn't save select with empty value",
     formValue: {
       "address-level1": "",
       "street-addr": "331 E. Evelyn Avenue",
-      "country": "USA",
+      "country": "US",
       "tel": "1-650-903-0800",
     },
     expectedResult: {
       formSubmission: true,
       records: {
         address: [{
           guid: null,
           record: {
             "street-address": "331 E. Evelyn Avenue",
             "address-level1": "",
             "address-level2": "",
-            "country": "USA",
+            "country": "US",
             "tel": "1-650-903-0800",
             "email": "",
           },
           untouchedFields: [],
         }],
         creditCard: [],
       },
     },
@@ -579,16 +579,17 @@ TESTCASES.forEach(testcase => {
     }
     sinon.stub(FormAutofillContent, "_onFormSubmit");
 
     let element = MOCK_DOC.getElementById(TARGET_ELEMENT_ID);
     FormAutofillContent.identifyAutofillFields(element);
     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);
     }
     FormAutofillContent._onFormSubmit.restore();
   });
 });
--- a/browser/extensions/formautofill/test/unit/test_parseAddressFormat.js
+++ b/browser/extensions/formautofill/test/unit/test_parseAddressFormat.js
@@ -33,16 +33,28 @@ add_task(async function test_parseAddres
       parsed: [
         {fieldId: "name", newLine: true},
         {fieldId: "organization", newLine: true},
         {fieldId: "street-address", newLine: true},
         {fieldId: "postal-code"},
         {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(),
                 /fmt string is missing./,
                 "Should throw if fmt is empty");
   for (let tc of TEST_CASES) {
     Assert.deepEqual(FormAutofillUtils.parseAddressFormat(tc.fmt), tc.parsed);
   }
--- a/browser/extensions/formautofill/test/unit/test_transformFields.js
+++ b/browser/extensions/formautofill/test/unit/test_transformFields.js
@@ -409,17 +409,17 @@ const ADDRESS_NORMALIZE_TESTCASES = [
       "country": undefined,
       "country-name": undefined,
     },
   },
   {
     description: "Has unsupported \"country\"",
     address: {
       "given-name": "John", // Make sure it won't be an empty record.
-      "country": "TV",
+      "country": "XX",
     },
     expectedResult: {
       "country": undefined,
       "country-name": undefined,
     },
   },
 
   // Tel
--- a/toolkit/components/mozintl/mozIMozIntl.idl
+++ b/toolkit/components/mozintl/mozIMozIntl.idl
@@ -46,29 +46,38 @@ interface mozIMozIntl : nsISupports
    *
    * Example:
    *   let langs = getLanguageDisplayNames(["pl"], ["fr", "de", "en"]);
    *   langs === ["Francuski", "Niemiecki", "Angielski"]
    */
   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);
 
   /**
    * 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);
 
   readonly attribute jsval DateTimeFormat;
   readonly attribute jsval NumberFormat;
   readonly attribute jsval Collator;
   readonly attribute jsval PluralRules;
--- a/toolkit/components/mozintl/mozIntl.js
+++ b/toolkit/components/mozintl/mozIntl.js
@@ -194,29 +194,54 @@ class MozIntl {
       try {
         return languageBundle.GetStringFromName(langCode.toLowerCase());
       } catch (e) {
         return langCode.toLowerCase(); // Fall back to raw language subtag.
       }
     });
   }
 
+  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.
       }
     });
   }
 
   getLocaleDisplayNames(locales, localeCodes) {
     if (locales !== undefined) {
--- a/toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js
+++ b/toolkit/components/mozintl/test/test_mozintl_getLocaleDisplayNames.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 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);
 
 add_test(function test_valid_language_tag() {
   deepEqual(gLocDN([]), []);
   deepEqual(gLocDN(["en"]), ["English"]);
   deepEqual(gLocDN(["und"]), ["und"]);
   run_next_test();
@@ -76,8 +77,15 @@ add_test(function test_region_only() {
 add_test(function test_invalid_regions() {
   deepEqual(gRegDN(["2"]), ["2"]);
   deepEqual(gRegDN([""]), [""]);
   Assert.throws(() => gRegDN([2]), /All region codes must be strings/);
   Assert.throws(() => gRegDN([{}]), /All region codes must be strings/);
   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();
+});