summaryrefslogtreecommitdiffstats
path: root/toolkit/components/formautofill/shared
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
commit40a355a42d4a9444dc753c04c6608dade2f06a23 (patch)
tree871fc667d2de662f171103ce5ec067014ef85e61 /toolkit/components/formautofill/shared
parentAdding upstream version 124.0.1. (diff)
downloadfirefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz
firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/formautofill/shared')
-rw-r--r--toolkit/components/formautofill/shared/AddressComponent.sys.mjs10
-rw-r--r--toolkit/components/formautofill/shared/AddressParser.sys.mjs2
-rw-r--r--toolkit/components/formautofill/shared/AddressRecord.sys.mjs119
-rw-r--r--toolkit/components/formautofill/shared/AutofillTelemetry.sys.mjs629
-rw-r--r--toolkit/components/formautofill/shared/FieldScanner.sys.mjs13
-rw-r--r--toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs72
-rw-r--r--toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs24
-rw-r--r--toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs39
-rw-r--r--toolkit/components/formautofill/shared/FormStateManager.sys.mjs2
-rw-r--r--toolkit/components/formautofill/shared/PhoneNumber.sys.mjs474
-rw-r--r--toolkit/components/formautofill/shared/PhoneNumberMetaData.sys.mjs291
-rw-r--r--toolkit/components/formautofill/shared/PhoneNumberNormalizer.sys.mjs67
12 files changed, 1674 insertions, 68 deletions
diff --git a/toolkit/components/formautofill/shared/AddressComponent.sys.mjs b/toolkit/components/formautofill/shared/AddressComponent.sys.mjs
index a849e889b2..40e00b66a0 100644
--- a/toolkit/components/formautofill/shared/AddressComponent.sys.mjs
+++ b/toolkit/components/formautofill/shared/AddressComponent.sys.mjs
@@ -11,9 +11,9 @@ ChromeUtils.defineESModuleGetters(lazy, {
FormAutofillNameUtils:
"resource://gre/modules/shared/FormAutofillNameUtils.sys.mjs",
FormAutofillUtils: "resource://gre/modules/shared/FormAutofillUtils.sys.mjs",
- PhoneNumber: "resource://autofill/phonenumberutils/PhoneNumber.sys.mjs",
+ PhoneNumber: "resource://gre/modules/shared/PhoneNumber.sys.mjs",
PhoneNumberNormalizer:
- "resource://autofill/phonenumberutils/PhoneNumberNormalizer.sys.mjs",
+ "resource://gre/modules/shared/PhoneNumberNormalizer.sys.mjs",
});
/**
@@ -201,7 +201,7 @@ class StreetAddress extends AddressField {
super(value, region);
this.#structuredStreetAddress = lazy.AddressParser.parseStreetAddress(
- lazy.AddressParser.replaceControlCharacters(this.userValue, " ")
+ lazy.AddressParser.replaceControlCharacters(this.userValue)
);
}
@@ -491,7 +491,7 @@ class Country extends AddressField {
return this.country_code == other.country_code;
}
- contains(other) {
+ contains(_other) {
return false;
}
@@ -841,7 +841,7 @@ class Email extends AddressField {
);
}
- contains(other) {
+ contains(_other) {
return false;
}
diff --git a/toolkit/components/formautofill/shared/AddressParser.sys.mjs b/toolkit/components/formautofill/shared/AddressParser.sys.mjs
index 5cb76934c1..1d36b71bba 100644
--- a/toolkit/components/formautofill/shared/AddressParser.sys.mjs
+++ b/toolkit/components/formautofill/shared/AddressParser.sys.mjs
@@ -271,7 +271,7 @@ export class AddressParser {
return s?.replace(/[.,\/#!$%\^&\*;:{}=\-_~()]/g, "");
}
- static replaceControlCharacters(s, replace) {
+ static replaceControlCharacters(s) {
return s?.replace(/[\t\n\r]/g, " ");
}
diff --git a/toolkit/components/formautofill/shared/AddressRecord.sys.mjs b/toolkit/components/formautofill/shared/AddressRecord.sys.mjs
new file mode 100644
index 0000000000..599a802dcd
--- /dev/null
+++ b/toolkit/components/formautofill/shared/AddressRecord.sys.mjs
@@ -0,0 +1,119 @@
+/* eslint-disable no-useless-concat */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+import { FormAutofillNameUtils } from "resource://gre/modules/shared/FormAutofillNameUtils.sys.mjs";
+import { FormAutofillUtils } from "resource://gre/modules/shared/FormAutofillUtils.sys.mjs";
+import { PhoneNumber } from "resource://gre/modules/shared/PhoneNumber.sys.mjs";
+import { FormAutofill } from "resource://autofill/FormAutofill.sys.mjs";
+
+/**
+ * The AddressRecord class serves to handle and normalize internal address records.
+ * AddressRecord is used for processing and consistent data representation.
+ */
+export class AddressRecord {
+ static NAME_COMPONENTS = ["given-name", "additional-name", "family-name"];
+
+ static STREET_ADDRESS_COMPONENTS = [
+ "address-line1",
+ "address-line2",
+ "address-line3",
+ ];
+ static TEL_COMPONENTS = [
+ "tel-country-code",
+ "tel-national",
+ "tel-area-code",
+ "tel-local",
+ "tel-local-prefix",
+ "tel-local-suffix",
+ ];
+
+ static computeFields(address) {
+ this.#computeNameFields(address);
+ this.#computeAddressLineFields(address);
+ this.#computeCountryFields(address);
+ this.#computeTelFields(address);
+ }
+
+ static #computeNameFields(address) {
+ // Compute split names
+ if (!("given-name" in address)) {
+ const nameParts = FormAutofillNameUtils.splitName(address.name);
+ address["given-name"] = nameParts.given;
+ address["additional-name"] = nameParts.middle;
+ address["family-name"] = nameParts.family;
+ }
+ }
+
+ static #computeAddressLineFields(address) {
+ // Compute address lines
+ if (!("address-line1" in address)) {
+ let streetAddress = [];
+ if (address["street-address"]) {
+ streetAddress = address["street-address"]
+ .split("\n")
+ .map(s => s.trim());
+ }
+ for (let i = 0; i < 3; i++) {
+ address[`address-line${i + 1}`] = streetAddress[i] || "";
+ }
+ if (streetAddress.length > 3) {
+ address["address-line3"] = FormAutofillUtils.toOneLineAddress(
+ streetAddress.slice(2)
+ );
+ }
+ }
+ }
+
+ static #computeCountryFields(address) {
+ // Compute country name
+ if (!("country-name" in address)) {
+ address["country-name"] =
+ FormAutofill.countries.get(address.country) ?? "";
+ }
+ }
+
+ static #computeTelFields(address) {
+ // Compute tel
+ if (!("tel-national" in address)) {
+ if (address.tel) {
+ let tel = PhoneNumber.Parse(
+ address.tel,
+ address.country || FormAutofill.DEFAULT_REGION
+ );
+ if (tel) {
+ if (tel.countryCode) {
+ address["tel-country-code"] = tel.countryCode;
+ }
+ if (tel.nationalNumber) {
+ address["tel-national"] = tel.nationalNumber;
+ }
+
+ // PhoneNumberUtils doesn't support parsing the components of a telephone
+ // number so we hard coded the parser for US numbers only. We will need
+ // to figure out how to parse numbers from other regions when we support
+ // new countries in the future.
+ if (tel.nationalNumber && tel.countryCode == "+1") {
+ let telComponents = tel.nationalNumber.match(
+ /(\d{3})((\d{3})(\d{4}))$/
+ );
+ if (telComponents) {
+ address["tel-area-code"] = telComponents[1];
+ address["tel-local"] = telComponents[2];
+ address["tel-local-prefix"] = telComponents[3];
+ address["tel-local-suffix"] = telComponents[4];
+ }
+ }
+ } else {
+ // Treat "tel" as "tel-national" directly if it can't be parsed.
+ address["tel-national"] = address.tel;
+ }
+ }
+
+ this.TEL_COMPONENTS.forEach(c => {
+ address[c] = address[c] || "";
+ });
+ }
+ }
+}
diff --git a/toolkit/components/formautofill/shared/AutofillTelemetry.sys.mjs b/toolkit/components/formautofill/shared/AutofillTelemetry.sys.mjs
new file mode 100644
index 0000000000..6a1fa974cc
--- /dev/null
+++ b/toolkit/components/formautofill/shared/AutofillTelemetry.sys.mjs
@@ -0,0 +1,629 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+import { FormAutofillUtils } from "resource://gre/modules/shared/FormAutofillUtils.sys.mjs";
+import { FormAutofillCreditCardSection } from "resource://gre/modules/shared/FormAutofillSection.sys.mjs";
+
+const { FIELD_STATES } = FormAutofillUtils;
+
+class AutofillTelemetryBase {
+ SUPPORTED_FIELDS = {};
+
+ EVENT_CATEGORY = null;
+ EVENT_OBJECT_FORM_INTERACTION = null;
+
+ SCALAR_DETECTED_SECTION_COUNT = null;
+ SCALAR_SUBMITTED_SECTION_COUNT = null;
+
+ HISTOGRAM_NUM_USES = null;
+ HISTOGRAM_PROFILE_NUM_USES = null;
+ HISTOGRAM_PROFILE_NUM_USES_KEY = null;
+
+ #initFormEventExtra(value) {
+ let extra = {};
+ for (const field of Object.values(this.SUPPORTED_FIELDS)) {
+ extra[field] = value;
+ }
+ return extra;
+ }
+
+ #setFormEventExtra(extra, key, value) {
+ if (!this.SUPPORTED_FIELDS[key]) {
+ return;
+ }
+
+ extra[this.SUPPORTED_FIELDS[key]] = value;
+ }
+
+ /**
+ * Building the extra keys object that is included in the Legacy Telemetry event `cc_form_v2`
+ * or `address_form` event and the Glean event `cc_form`, and `address_form`.
+ * It indicates the detected credit card or address fields and which method (autocomplete property, regular expression heuristics or fathom) identified them.
+ *
+ * @param {object} section Using section.fieldDetails to extract which fields were identified and how
+ * @param {string} undetected Default value when a field is not detected: 'undetected' (Glean) and 'false' in (Legacy)
+ * @param {string} autocomplete Value when a field is identified with autocomplete property: 'autocomplete' (Glean), 'true' (Legacy)
+ * @param {string} regexp Value when a field is identified with regex expression heuristics: 'regexp' (Glean), '0' (Legacy)
+ * @param {boolean} includeMultiPart Include multi part data or not
+ * @returns {object} Extra keys to include in the form event
+ */
+ #buildFormDetectedEventExtra(
+ section,
+ undetected,
+ autocomplete,
+ regexp,
+ includeMultiPart
+ ) {
+ let extra = this.#initFormEventExtra(undetected);
+
+ let identified = new Set();
+ section.fieldDetails.forEach(detail => {
+ identified.add(detail.fieldName);
+
+ if (detail.reason == "autocomplete") {
+ this.#setFormEventExtra(extra, detail.fieldName, autocomplete);
+ } else {
+ // confidence exists only when a field is identified by fathom.
+ let confidence =
+ detail.confidence > 0 ? Math.floor(100 * detail.confidence) / 100 : 0;
+
+ this.#setFormEventExtra(
+ extra,
+ detail.fieldName,
+ confidence ? confidence.toString() : regexp
+ );
+ }
+
+ if (
+ detail.fieldName === "cc-number" &&
+ this.SUPPORTED_FIELDS[detail.fieldName] &&
+ includeMultiPart
+ ) {
+ extra.cc_number_multi_parts = detail.part ?? 1;
+ }
+ });
+ return extra;
+ }
+
+ recordFormDetected(section) {
+ this.recordFormEvent(
+ "detected",
+ section.flowId,
+ this.#buildFormDetectedEventExtra(section, "false", "true", "0", false)
+ );
+
+ this.recordGleanFormEvent(
+ "formDetected",
+ section.flowId,
+ this.#buildFormDetectedEventExtra(
+ section,
+ "undetected",
+ "autocomplete",
+ "regexp",
+ true
+ )
+ );
+ }
+
+ recordPopupShown(section, fieldName) {
+ const extra = { field_name: fieldName };
+ this.recordFormEvent("popup_shown", section.flowId, extra);
+ this.recordGleanFormEvent("formPopupShown", section.flowId, extra);
+ }
+
+ recordFormFilled(section, profile) {
+ // Calculate values for telemetry
+ let extra = this.#initFormEventExtra("unavailable");
+
+ for (let fieldDetail of section.fieldDetails) {
+ let element = fieldDetail.element;
+ let state = profile[fieldDetail.fieldName] ? "filled" : "not_filled";
+ if (
+ section.handler.getFilledStateByElement(element) ==
+ FIELD_STATES.NORMAL &&
+ (HTMLSelectElement.isInstance(element) ||
+ (HTMLInputElement.isInstance(element) && element.value.length))
+ ) {
+ state = "user_filled";
+ }
+ this.#setFormEventExtra(extra, fieldDetail.fieldName, state);
+ }
+
+ this.recordFormEvent("filled", section.flowId, extra);
+ this.recordGleanFormEvent("formFilled", section.flowId, extra);
+ }
+
+ recordFilledModified(section, fieldName) {
+ const extra = { field_name: fieldName };
+ this.recordFormEvent("filled_modified", section.flowId, extra);
+ this.recordGleanFormEvent("formFilledModified", section.flowId, extra);
+ }
+
+ recordFormSubmitted(section, record, _form) {
+ let extra = this.#initFormEventExtra("unavailable");
+
+ if (record.guid !== null) {
+ // If the `guid` is not null, it means we're editing an existing record.
+ // In that case, all fields in the record are autofilled, and fields in
+ // `untouchedFields` are unmodified.
+ for (const [fieldName, value] of Object.entries(record.record)) {
+ if (record.untouchedFields?.includes(fieldName)) {
+ this.#setFormEventExtra(extra, fieldName, "autofilled");
+ } else if (value) {
+ this.#setFormEventExtra(extra, fieldName, "user_filled");
+ } else {
+ this.#setFormEventExtra(extra, fieldName, "not_filled");
+ }
+ }
+ } else {
+ Object.keys(record.record).forEach(fieldName =>
+ this.#setFormEventExtra(extra, fieldName, "user_filled")
+ );
+ }
+
+ this.recordFormEvent("submitted", section.flowId, extra);
+ this.recordGleanFormEvent("formSubmitted", section.flowId, extra);
+ }
+
+ recordFormCleared(section, fieldName) {
+ const extra = { field_name: fieldName };
+
+ // Note that when a form is cleared, we also record `filled_modified` events
+ // for all the fields that have been cleared.
+ this.recordFormEvent("cleared", section.flowId, extra);
+ this.recordGleanFormEvent("formCleared", section.flowId, extra);
+ }
+
+ recordFormEvent(method, flowId, extra) {
+ Services.telemetry.recordEvent(
+ this.EVENT_CATEGORY,
+ method,
+ this.EVENT_OBJECT_FORM_INTERACTION,
+ flowId,
+ extra
+ );
+ }
+
+ recordGleanFormEvent(_eventName, _flowId, _extra) {
+ throw new Error("Not implemented.");
+ }
+
+ recordFormInteractionEvent(
+ method,
+ section,
+ { fieldName, profile, record, form } = {}
+ ) {
+ if (!this.EVENT_OBJECT_FORM_INTERACTION) {
+ return undefined;
+ }
+ switch (method) {
+ case "detected":
+ return this.recordFormDetected(section);
+ case "popup_shown":
+ return this.recordPopupShown(section, fieldName);
+ case "filled":
+ return this.recordFormFilled(section, profile);
+ case "filled_modified":
+ return this.recordFilledModified(section, fieldName);
+ case "submitted":
+ return this.recordFormSubmitted(section, record, form);
+ case "cleared":
+ return this.recordFormCleared(section, fieldName);
+ }
+ return undefined;
+ }
+
+ recordDoorhangerEvent(method, object, flowId) {
+ Services.telemetry.recordEvent(this.EVENT_CATEGORY, method, object, flowId);
+ }
+
+ recordManageEvent(method) {
+ Services.telemetry.recordEvent(this.EVENT_CATEGORY, method, "manage");
+ }
+
+ recordAutofillProfileCount(_count) {
+ throw new Error("Not implemented.");
+ }
+
+ recordDetectedSectionCount() {
+ if (!this.SCALAR_DETECTED_SECTION_COUNT) {
+ return;
+ }
+
+ Services.telemetry.scalarAdd(this.SCALAR_DETECTED_SECTION_COUNT, 1);
+ }
+
+ recordSubmittedSectionCount(count) {
+ if (!this.SCALAR_SUBMITTED_SECTION_COUNT || !count) {
+ return;
+ }
+
+ Services.telemetry.scalarAdd(this.SCALAR_SUBMITTED_SECTION_COUNT, count);
+ }
+
+ recordNumberOfUse(records) {
+ let histogram = Services.telemetry.getKeyedHistogramById(
+ this.HISTOGRAM_PROFILE_NUM_USES
+ );
+ histogram.clear();
+
+ for (let record of records) {
+ histogram.add(this.HISTOGRAM_PROFILE_NUM_USES_KEY, record.timesUsed);
+ }
+ }
+}
+
+export class AddressTelemetry extends AutofillTelemetryBase {
+ EVENT_CATEGORY = "address";
+ EVENT_OBJECT_FORM_INTERACTION = "address_form";
+ EVENT_OBJECT_FORM_INTERACTION_EXT = "address_form_ext";
+
+ SCALAR_DETECTED_SECTION_COUNT =
+ "formautofill.addresses.detected_sections_count";
+ SCALAR_SUBMITTED_SECTION_COUNT =
+ "formautofill.addresses.submitted_sections_count";
+ SCALAR_AUTOFILL_PROFILE_COUNT =
+ "formautofill.addresses.autofill_profiles_count";
+
+ HISTOGRAM_PROFILE_NUM_USES = "AUTOFILL_PROFILE_NUM_USES";
+ HISTOGRAM_PROFILE_NUM_USES_KEY = "address";
+
+ // Fields that are record in `address_form` and `address_form_ext` telemetry
+ SUPPORTED_FIELDS = {
+ "street-address": "street_address",
+ "address-line1": "address_line1",
+ "address-line2": "address_line2",
+ "address-line3": "address_line3",
+ "address-level1": "address_level1",
+ "address-level2": "address_level2",
+ "postal-code": "postal_code",
+ country: "country",
+ name: "name",
+ "given-name": "given_name",
+ "additional-name": "additional_name",
+ "family-name": "family_name",
+ email: "email",
+ organization: "organization",
+ tel: "tel",
+ };
+
+ // Fields that are record in `address_form` event telemetry extra_keys
+ static SUPPORTED_FIELDS_IN_FORM = [
+ "street_address",
+ "address_line1",
+ "address_line2",
+ "address_line3",
+ "address_level2",
+ "address_level1",
+ "postal_code",
+ "country",
+ ];
+
+ // Fields that are record in `address_form_ext` event telemetry extra_keys
+ static SUPPORTED_FIELDS_IN_FORM_EXT = [
+ "name",
+ "given_name",
+ "additional_name",
+ "family_name",
+ "email",
+ "organization",
+ "tel",
+ ];
+
+ recordGleanFormEvent(_eventName, _flowId, _extra) {
+ // To be implemented when migrating the legacy event address.address_form to Glean
+ }
+
+ recordFormEvent(method, flowId, extra) {
+ let extExtra = {};
+ if (["detected", "filled", "submitted"].includes(method)) {
+ for (const [key, value] of Object.entries(extra)) {
+ if (AddressTelemetry.SUPPORTED_FIELDS_IN_FORM_EXT.includes(key)) {
+ extExtra[key] = value;
+ delete extra[key];
+ }
+ }
+ }
+
+ Services.telemetry.recordEvent(
+ this.EVENT_CATEGORY,
+ method,
+ this.EVENT_OBJECT_FORM_INTERACTION,
+ flowId,
+ extra
+ );
+
+ if (Object.keys(extExtra).length) {
+ Services.telemetry.recordEvent(
+ this.EVENT_CATEGORY,
+ method,
+ this.EVENT_OBJECT_FORM_INTERACTION_EXT,
+ flowId,
+ extExtra
+ );
+ }
+ }
+
+ recordAutofillProfileCount(count) {
+ Services.telemetry.scalarSet(this.SCALAR_AUTOFILL_PROFILE_COUNT, count);
+ }
+}
+
+class CreditCardTelemetry extends AutofillTelemetryBase {
+ EVENT_CATEGORY = "creditcard";
+ EVENT_OBJECT_FORM_INTERACTION = "cc_form_v2";
+
+ SCALAR_DETECTED_SECTION_COUNT =
+ "formautofill.creditCards.detected_sections_count";
+ SCALAR_SUBMITTED_SECTION_COUNT =
+ "formautofill.creditCards.submitted_sections_count";
+
+ HISTOGRAM_NUM_USES = "CREDITCARD_NUM_USES";
+ HISTOGRAM_PROFILE_NUM_USES = "AUTOFILL_PROFILE_NUM_USES";
+ HISTOGRAM_PROFILE_NUM_USES_KEY = "credit_card";
+
+ // Mapping of field name used in formautofill code to the field name
+ // used in the telemetry.
+ SUPPORTED_FIELDS = {
+ "cc-name": "cc_name",
+ "cc-number": "cc_number",
+ "cc-type": "cc_type",
+ "cc-exp": "cc_exp",
+ "cc-exp-month": "cc_exp_month",
+ "cc-exp-year": "cc_exp_year",
+ };
+
+ recordLegacyFormEvent(method, flowId, extra = null) {
+ Services.telemetry.recordEvent(
+ this.EVENT_CATEGORY,
+ method,
+ "cc_form",
+ flowId,
+ extra
+ );
+ }
+
+ recordGleanFormEvent(eventName, flowId, extra) {
+ extra.flow_id = flowId;
+ Glean.formautofillCreditcards[eventName].record(extra);
+ }
+
+ recordFormDetected(section) {
+ super.recordFormDetected(section);
+
+ let identified = new Set();
+ section.fieldDetails.forEach(detail => {
+ identified.add(detail.fieldName);
+ });
+ let extra = {
+ cc_name_found: identified.has("cc-name") ? "true" : "false",
+ cc_number_found: identified.has("cc-number") ? "true" : "false",
+ cc_exp_found:
+ identified.has("cc-exp") ||
+ (identified.has("cc-exp-month") && identified.has("cc-exp-year"))
+ ? "true"
+ : "false",
+ };
+
+ this.recordLegacyFormEvent("detected", section.flowId, extra);
+ }
+
+ recordPopupShown(section, fieldName) {
+ super.recordPopupShown(section, fieldName);
+
+ this.recordLegacyFormEvent("popup_shown", section.flowId);
+ }
+
+ recordFormFilled(section, profile) {
+ super.recordFormFilled(section, profile);
+ // Calculate values for telemetry
+ let extra = {
+ cc_name: "unavailable",
+ cc_number: "unavailable",
+ cc_exp: "unavailable",
+ };
+
+ for (let fieldDetail of section.fieldDetails) {
+ let element = fieldDetail.element;
+ let state = profile[fieldDetail.fieldName] ? "filled" : "not_filled";
+ if (
+ section.handler.getFilledStateByElement(element) ==
+ FIELD_STATES.NORMAL &&
+ (HTMLSelectElement.isInstance(element) ||
+ (HTMLInputElement.isInstance(element) && element.value.length))
+ ) {
+ state = "user_filled";
+ }
+ switch (fieldDetail.fieldName) {
+ case "cc-name":
+ extra.cc_name = state;
+ break;
+ case "cc-number":
+ extra.cc_number = state;
+ break;
+ case "cc-exp":
+ case "cc-exp-month":
+ case "cc-exp-year":
+ extra.cc_exp = state;
+ break;
+ }
+ }
+
+ this.recordLegacyFormEvent("filled", section.flowId, extra);
+ }
+
+ recordFilledModified(section, fieldName) {
+ super.recordFilledModified(section, fieldName);
+
+ let extra = { field_name: fieldName };
+ this.recordLegacyFormEvent("filled_modified", section.flowId, extra);
+ }
+
+ /**
+ * Called when a credit card form is submitted
+ *
+ * @param {object} section Section that produces this record
+ * @param {object} record Credit card record filled in the form.
+ * @param {Array<HTMLForm>} form Form that contains the section
+ */
+ recordFormSubmitted(section, record, form) {
+ super.recordFormSubmitted(section, record, form);
+
+ // For legacy cc_form event telemetry
+ let extra = {
+ fields_not_auto: "0",
+ fields_auto: "0",
+ fields_modified: "0",
+ };
+
+ if (record.guid !== null) {
+ let totalCount = form.elements.length;
+ let autofilledCount = Object.keys(record.record).length;
+ let unmodifiedCount = record.untouchedFields.length;
+
+ extra.fields_not_auto = (totalCount - autofilledCount).toString();
+ extra.fields_auto = autofilledCount.toString();
+ extra.fields_modified = (autofilledCount - unmodifiedCount).toString();
+ } else {
+ // If the `guid` is null, we're filling a new form.
+ // In that case, all not-null fields are manually filled.
+ extra.fields_not_auto = Array.from(form.elements)
+ .filter(element => !!element.value?.trim().length)
+ .length.toString();
+ }
+
+ this.recordLegacyFormEvent("submitted", section.flowId, extra);
+ }
+
+ recordNumberOfUse(records) {
+ super.recordNumberOfUse(records);
+
+ if (!this.HISTOGRAM_NUM_USES) {
+ return;
+ }
+
+ let histogram = Services.telemetry.getHistogramById(
+ this.HISTOGRAM_NUM_USES
+ );
+ histogram.clear();
+
+ for (let record of records) {
+ histogram.add(record.timesUsed);
+ }
+ }
+
+ recordAutofillProfileCount(count) {
+ Glean.formautofillCreditcards.autofillProfilesCount.set(count);
+ }
+}
+
+export class AutofillTelemetry {
+ static #creditCardTelemetry = new CreditCardTelemetry();
+ static #addressTelemetry = new AddressTelemetry();
+
+ // const for `type` parameter used in the utility functions
+ static ADDRESS = "address";
+ static CREDIT_CARD = "creditcard";
+
+ static #getTelemetryBySection(section) {
+ return section instanceof FormAutofillCreditCardSection
+ ? this.#creditCardTelemetry
+ : this.#addressTelemetry;
+ }
+
+ static #getTelemetryByType(type) {
+ return type == AutofillTelemetry.CREDIT_CARD
+ ? this.#creditCardTelemetry
+ : this.#addressTelemetry;
+ }
+
+ /**
+ * Utility functions for `doorhanger` event (defined in Events.yaml)
+ *
+ * Category: address or creditcard
+ * Event name: doorhanger
+ */
+ static recordDoorhangerShown(type, object, flowId) {
+ const telemetry = this.#getTelemetryByType(type);
+ telemetry.recordDoorhangerEvent("show", object, flowId);
+ }
+
+ static recordDoorhangerClicked(type, method, object, flowId) {
+ const telemetry = this.#getTelemetryByType(type);
+
+ // We don't have `create` method in telemetry, we treat `create` as `save`
+ switch (method) {
+ case "create":
+ method = "save";
+ break;
+ case "open-pref":
+ method = "pref";
+ break;
+ case "learn-more":
+ method = "learn_more";
+ break;
+ }
+
+ telemetry.recordDoorhangerEvent(method, object, flowId);
+ }
+
+ /**
+ * Utility functions for form event (defined in Events.yaml)
+ *
+ * Category: address or creditcard
+ * Event name: cc_form, cc_form_v2, or address_form
+ */
+
+ static recordFormInteractionEvent(
+ method,
+ section,
+ { fieldName, profile, record, form } = {}
+ ) {
+ const telemetry = this.#getTelemetryBySection(section);
+ telemetry.recordFormInteractionEvent(method, section, {
+ fieldName,
+ profile,
+ record,
+ form,
+ });
+ }
+
+ /**
+ * Utility functions for submitted section count scalar (defined in Scalars.yaml)
+ *
+ * Category: formautofill.creditCards or formautofill.addresses
+ * Scalar name: submitted_sections_count
+ */
+ static recordDetectedSectionCount(section) {
+ const telemetry = this.#getTelemetryBySection(section);
+ telemetry.recordDetectedSectionCount();
+ }
+
+ static recordSubmittedSectionCount(type, count) {
+ const telemetry = this.#getTelemetryByType(type);
+ telemetry.recordSubmittedSectionCount(count);
+ }
+
+ static recordManageEvent(type, method) {
+ const telemetry = this.#getTelemetryByType(type);
+ telemetry.recordManageEvent(method);
+ }
+
+ static recordAutofillProfileCount(type, count) {
+ const telemetry = this.#getTelemetryByType(type);
+ telemetry.recordAutofillProfileCount(count);
+ }
+
+ /**
+ * Utility functions for address/credit card number of use
+ */
+ static recordNumberOfUse(type, records) {
+ const telemetry = this.#getTelemetryByType(type);
+ telemetry.recordNumberOfUse(records);
+ }
+
+ static recordFormSubmissionHeuristicCount(label) {
+ Glean.formautofill.formSubmissionHeuristic[label].add(1);
+ }
+}
diff --git a/toolkit/components/formautofill/shared/FieldScanner.sys.mjs b/toolkit/components/formautofill/shared/FieldScanner.sys.mjs
index 22adfdabe8..2118de3de8 100644
--- a/toolkit/components/formautofill/shared/FieldScanner.sys.mjs
+++ b/toolkit/components/formautofill/shared/FieldScanner.sys.mjs
@@ -2,6 +2,11 @@
* 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/. */
+const lazy = {};
+ChromeUtils.defineESModuleGetters(lazy, {
+ FormAutofillUtils: "resource://gre/modules/shared/FormAutofillUtils.sys.mjs",
+});
+
/**
* Represents the detailed information about a form field, including
* the inferred field name, the approach used for inferring, and additional metadata.
@@ -73,6 +78,14 @@ export class FieldDetail {
get sectionName() {
return this.section || this.addressType;
}
+
+ #isVisible = null;
+ get isVisible() {
+ if (this.#isVisible == null) {
+ this.#isVisible = lazy.FormAutofillUtils.isFieldVisible(this.element);
+ }
+ return this.#isVisible;
+ }
}
/**
diff --git a/toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs b/toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs
index 4ee1fc1fe1..fb96e47cae 100644
--- a/toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs
+++ b/toolkit/components/formautofill/shared/FormAutofillHeuristics.sys.mjs
@@ -182,7 +182,7 @@ export const FormAutofillHeuristics = {
* Return true if there is any field can be recognized in the parser,
* otherwise false.
*/
- _parsePhoneFields(scanner, detail) {
+ _parsePhoneFields(scanner, _fieldDetail) {
let matchingResult;
const GRAMMARS = this.PHONE_FIELD_GRAMMARS;
@@ -277,7 +277,7 @@ export const FormAutofillHeuristics = {
* Return true if there is any field can be recognized in the parser,
* otherwise false.
*/
- _parseStreetAddressFields(scanner, fieldDetail) {
+ _parseStreetAddressFields(scanner, _fieldDetail) {
const INTERESTED_FIELDS = [
"street-address",
"address-line1",
@@ -547,7 +547,9 @@ export const FormAutofillHeuristics = {
* all sections within its field details in the form.
*/
getFormInfo(form) {
- let elements = this.getFormElements(form);
+ const elements = Array.from(form.elements).filter(element =>
+ lazy.FormAutofillUtils.isCreditCardOrAddressFieldType(element)
+ );
const scanner = new lazy.FieldScanner(elements, element =>
this.inferFieldInfo(element, elements)
@@ -597,22 +599,6 @@ export const FormAutofillHeuristics = {
},
/**
- * Get focusable form elements that are of credit card or address type
- *
- * @param {HTMLElement} form
- * @returns {Array<HTMLElement>} focusable elements
- */
- getFormElements(form) {
- let elements = Array.from(form.elements).filter(
- element =>
- lazy.FormAutofillUtils.isCreditCardOrAddressFieldType(element) &&
- lazy.FormAutofillUtils.isFieldFocusable(element)
- );
-
- return elements;
- },
-
- /**
* The result is an array contains the sections with its belonging field details.
*
* @param {Array<FieldDetails>} fieldDetails field detail array to be classified
@@ -621,46 +607,54 @@ export const FormAutofillHeuristics = {
_classifySections(fieldDetails) {
let sections = [];
for (let i = 0; i < fieldDetails.length; i++) {
- const fieldName = fieldDetails[i].fieldName;
- const sectionName = fieldDetails[i].sectionName;
-
+ const cur = fieldDetails[i];
const [currentSection] = sections.slice(-1);
- // The section this field might belong to
+ // The section this field might be placed into.
let candidateSection = null;
- // If the field doesn't have a section name, MAYBE put it to the previous
- // section if exists. If the field has a section name, maybe put it to the
- // nearest section that either has the same name or it doesn't has a name.
- // Otherwise, create a new section.
- if (!currentSection || !sectionName) {
+ // Use name group from autocomplete attribute (ex, section-xxx) to look for the section
+ // we might place this field into.
+ // If the field doesn't have a section name, the candidate section is the previous section.
+ if (!currentSection || !cur.sectionName) {
candidateSection = currentSection;
- } else if (sectionName) {
+ } else if (cur.sectionName) {
+ // If the field has a section name, the candidate section is the nearest section that
+ // either shares the same name or lacks a name.
for (let idx = sections.length - 1; idx >= 0; idx--) {
- if (!sections[idx].name || sections[idx].name == sectionName) {
+ if (!sections[idx].name || sections[idx].name == cur.sectionName) {
candidateSection = sections[idx];
break;
}
}
}
- // We got an candidate section to put the field to, check whether the section
- // already has a field with the same field name. If yes, only add the field to when
- // the type of the field might appear multiple times in a row.
if (candidateSection) {
let createNewSection = true;
- if (candidateSection.fieldDetails.find(f => f.fieldName == fieldName)) {
+
+ // We might create a new section instead of placing the field in the candiate section if
+ // the section already has a field with the same field name.
+ // We also check visibility for both the fields with the same field name because we don't
+ // wanht to create a new section for an invisible field.
+ if (
+ candidateSection.fieldDetails.find(
+ f => f.fieldName == cur.fieldName && f.isVisible && cur.isVisible
+ )
+ ) {
+ // For some field type, it is common to have multiple fields in one section, for example,
+ // email. In that case, we will not create a new section even when the candidate section
+ // already has a field with the same field name.
const [lastFieldDetail] = candidateSection.fieldDetails.slice(-1);
- if (lastFieldDetail.fieldName == fieldName) {
- if (MULTI_FIELD_NAMES.includes(fieldName)) {
+ if (lastFieldDetail.fieldName == cur.fieldName) {
+ if (MULTI_FIELD_NAMES.includes(cur.fieldName)) {
createNewSection = false;
- } else if (fieldName in MULTI_N_FIELD_NAMES) {
+ } else if (cur.fieldName in MULTI_N_FIELD_NAMES) {
// This is the heuristic to handle special cases where we can have multiple
// fields in one section, but only if the field has appeared N times in a row.
// For example, websites can use 4 consecutive 4-digit `cc-number` fields
// instead of one 16-digit `cc-number` field.
- const N = MULTI_N_FIELD_NAMES[fieldName];
+ const N = MULTI_N_FIELD_NAMES[cur.fieldName];
if (lastFieldDetail.part) {
// If `part` is set, we have already identified this field can be
// merged previously
@@ -673,7 +667,7 @@ export const FormAutofillHeuristics = {
N == 2 ||
fieldDetails
.slice(i + 1, i + N - 1)
- .every(f => f.fieldName == fieldName)
+ .every(f => f.fieldName == cur.fieldName)
) {
lastFieldDetail.part = 1;
fieldDetails[i].part = 2;
diff --git a/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs b/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs
index 1c7696432a..7bda4c167b 100644
--- a/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs
+++ b/toolkit/components/formautofill/shared/FormAutofillSection.sys.mjs
@@ -7,7 +7,7 @@ import { FormAutofill } from "resource://autofill/FormAutofill.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
- AutofillTelemetry: "resource://autofill/AutofillTelemetry.sys.mjs",
+ AutofillTelemetry: "resource://gre/modules/shared/AutofillTelemetry.sys.mjs",
CreditCard: "resource://gre/modules/CreditCard.sys.mjs",
FormAutofillNameUtils:
"resource://gre/modules/shared/FormAutofillNameUtils.sys.mjs",
@@ -79,40 +79,40 @@ export class FormAutofillSection {
* Examine the section is createable for storing the profile. This method
* must be overrided.
*
- * @param {Object} record The record for examining createable
+ * @param {Object} _record The record for examining createable
* @returns {boolean} True for the record is createable, otherwise false
*
*/
- isRecordCreatable(record) {
+ isRecordCreatable(_record) {
throw new TypeError("isRecordCreatable method must be overridden");
}
/**
* Override this method if the profile is needed to apply some transformers.
*
- * @param {object} profile
+ * @param {object} _profile
* A profile should be converted based on the specific requirement.
*/
- applyTransformers(profile) {}
+ applyTransformers(_profile) {}
/**
* Override this method if the profile is needed to be customized for
* previewing values.
*
- * @param {object} profile
+ * @param {object} _profile
* A profile for pre-processing before previewing values.
*/
- preparePreviewProfile(profile) {}
+ preparePreviewProfile(_profile) {}
/**
* Override this method if the profile is needed to be customized for filling
* values.
*
- * @param {object} profile
+ * @param {object} _profile
* A profile for pre-processing before filling values.
* @returns {boolean} Whether the profile should be filled.
*/
- async prepareFillingProfile(profile) {
+ async prepareFillingProfile(_profile) {
return true;
}
@@ -846,6 +846,10 @@ export class FormAutofillAddressSection extends FormAutofillSection {
value =
FormAutofillUtils.getAbbreviatedSubregionName([value, text]) || text;
}
+ } else if (fieldDetail.fieldName == "country") {
+ // This is a temporary fix. Ideally we should have either case-insensitive comparaison of country codes
+ // or handle this elsewhere see Bug 1889234 for more context.
+ value = value.toUpperCase();
}
return value;
}
@@ -884,7 +888,7 @@ export class FormAutofillCreditCardSection extends FormAutofillSection {
}
}
- _handlePageHide(event) {
+ _handlePageHide(_event) {
this.handler.window.removeEventListener(
"pagehide",
this._handlePageHide.bind(this)
diff --git a/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs b/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs
index ce10c71ce1..e86f14975c 100644
--- a/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs
+++ b/toolkit/components/formautofill/shared/FormAutofillUtils.sys.mjs
@@ -192,7 +192,7 @@ FormAutofillUtils = {
getAddressLabel(address) {
// TODO: Implement a smarter way for deciding what to display
// as option text. Possibly improve the algorithm in
- // ProfileAutoCompleteResult.jsm and reuse it here.
+ // ProfileAutoCompleteResult.sys.mjs and reuse it here.
let fieldOrder = [
"name",
"-moz-street-address-one-line", // Street address
@@ -302,20 +302,27 @@ FormAutofillUtils = {
},
/**
- * Determines if an element is focusable
- * and accessible via keyboard navigation or not.
+ * Determines if an element is visually hidden or not.
*
* @param {HTMLElement} element
- *
- * @returns {bool} true if the element is focusable and accessible
+ * @param {boolean} visibilityCheck true to run visiblity check against
+ * element.checkVisibility API. Otherwise, test by only checking
+ * `hidden` and `display` attributes
+ * @returns {boolean} true if the element is visible
*/
- isFieldFocusable(element) {
- return (
- // The Services.focus.elementIsFocusable API considers elements with
- // tabIndex="-1" set as focusable. But since they are not accessible
- // via keyboard navigation we treat them as non-interactive
- Services.focus.elementIsFocusable(element, 0) && element.tabIndex != "-1"
- );
+ isFieldVisible(element, visibilityCheck = true) {
+ if (
+ visibilityCheck &&
+ element.checkVisibility &&
+ !FormAutofillUtils.ignoreVisibilityCheck
+ ) {
+ return element.checkVisibility({
+ checkOpacity: true,
+ checkVisibilityCSS: true,
+ });
+ }
+
+ return !element.hidden && element.style.display != "none";
},
/**
@@ -1127,3 +1134,11 @@ XPCOMUtils.defineLazyPreferenceGetter(
"extensions.formautofill.focusOnAutofill",
true
);
+
+// This is only used for testing
+XPCOMUtils.defineLazyPreferenceGetter(
+ FormAutofillUtils,
+ "ignoreVisibilityCheck",
+ "extensions.formautofill.test.ignoreVisibilityCheck",
+ false
+);
diff --git a/toolkit/components/formautofill/shared/FormStateManager.sys.mjs b/toolkit/components/formautofill/shared/FormStateManager.sys.mjs
index 064b4e5356..7481a5981c 100644
--- a/toolkit/components/formautofill/shared/FormStateManager.sys.mjs
+++ b/toolkit/components/formautofill/shared/FormStateManager.sys.mjs
@@ -150,7 +150,7 @@ export class FormStateManager {
}
didDestroy() {
- this._activeItems = null;
+ this._activeItems = {};
}
}
diff --git a/toolkit/components/formautofill/shared/PhoneNumber.sys.mjs b/toolkit/components/formautofill/shared/PhoneNumber.sys.mjs
new file mode 100644
index 0000000000..5288765181
--- /dev/null
+++ b/toolkit/components/formautofill/shared/PhoneNumber.sys.mjs
@@ -0,0 +1,474 @@
+/* This Source Code Form is subject to the terms of the Apache License, Version
+ * 2.0. If a copy of the Apache License was not distributed with this file, You
+ * can obtain one at https://www.apache.org/licenses/LICENSE-2.0 */
+
+// This library came from https://github.com/andreasgal/PhoneNumber.js but will
+// be further maintained by our own in Form Autofill codebase.
+
+import { PHONE_NUMBER_META_DATA } from "resource://gre/modules/shared/PhoneNumberMetaData.sys.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ PhoneNumberNormalizer:
+ "resource://gre/modules/shared/PhoneNumberNormalizer.sys.mjs",
+});
+
+export var PhoneNumber = (function (dataBase) {
+ const MAX_PHONE_NUMBER_LENGTH = 50;
+ const NON_ALPHA_CHARS = /[^a-zA-Z]/g;
+ const NON_DIALABLE_CHARS = /[^,#+\*\d]/g;
+ const NON_DIALABLE_CHARS_ONCE = new RegExp(NON_DIALABLE_CHARS.source);
+ const SPLIT_FIRST_GROUP = /^(\d+)(.*)$/;
+ const LEADING_PLUS_CHARS_PATTERN = /^[+\uFF0B]+/g;
+
+ // Format of the string encoded meta data. If the name contains "^" or "$"
+ // we will generate a regular expression from the value, with those special
+ // characters as prefix/suffix.
+ const META_DATA_ENCODING = [
+ "region",
+ "^(?:internationalPrefix)",
+ "nationalPrefix",
+ "^(?:nationalPrefixForParsing)",
+ "nationalPrefixTransformRule",
+ "nationalPrefixFormattingRule",
+ "^possiblePattern$",
+ "^nationalPattern$",
+ "formats",
+ ];
+
+ const FORMAT_ENCODING = [
+ "^pattern$",
+ "nationalFormat",
+ "^leadingDigits",
+ "nationalPrefixFormattingRule",
+ "internationalFormat",
+ ];
+
+ let regionCache = Object.create(null);
+
+ // Parse an array of strings into a convenient object. We store meta
+ // data as arrays since thats much more compact than JSON.
+ function ParseArray(array, encoding, obj) {
+ for (let n = 0; n < encoding.length; ++n) {
+ let value = array[n];
+ if (!value) {
+ continue;
+ }
+ let field = encoding[n];
+ let fieldAlpha = field.replace(NON_ALPHA_CHARS, "");
+ if (field != fieldAlpha) {
+ value = new RegExp(field.replace(fieldAlpha, value));
+ }
+ obj[fieldAlpha] = value;
+ }
+ return obj;
+ }
+
+ // Parse string encoded meta data into a convenient object
+ // representation.
+ function ParseMetaData(countryCode, md) {
+ let array = JSON.parse(md);
+ md = ParseArray(array, META_DATA_ENCODING, { countryCode });
+ regionCache[md.region] = md;
+ return md;
+ }
+
+ // Parse string encoded format data into a convenient object
+ // representation.
+ function ParseFormat(md) {
+ let formats = md.formats;
+ if (!formats) {
+ return;
+ }
+ // Bail if we already parsed the format definitions.
+ if (!Array.isArray(formats[0])) {
+ return;
+ }
+ for (let n = 0; n < formats.length; ++n) {
+ formats[n] = ParseArray(formats[n], FORMAT_ENCODING, {});
+ }
+ }
+
+ // Search for the meta data associated with a region identifier ("US") in
+ // our database, which is indexed by country code ("1"). Since we have
+ // to walk the entire database for this, we cache the result of the lookup
+ // for future reference.
+ function FindMetaDataForRegion(region) {
+ // Check in the region cache first. This will find all entries we have
+ // already resolved (parsed from a string encoding).
+ let md = regionCache[region];
+ if (md) {
+ return md;
+ }
+ for (let countryCode in dataBase) {
+ let entry = dataBase[countryCode];
+ // Each entry is a string encoded object of the form '["US..', or
+ // an array of strings. We don't want to parse the string here
+ // to save memory, so we just substring the region identifier
+ // and compare it. For arrays, we compare against all region
+ // identifiers with that country code. We skip entries that are
+ // of type object, because they were already resolved (parsed into
+ // an object), and their country code should have been in the cache.
+ if (Array.isArray(entry)) {
+ for (let n = 0; n < entry.length; n++) {
+ if (typeof entry[n] == "string" && entry[n].substr(2, 2) == region) {
+ if (n > 0) {
+ // Only the first entry has the formats field set.
+ // Parse the main country if we haven't already and use
+ // the formats field from the main country.
+ if (typeof entry[0] == "string") {
+ entry[0] = ParseMetaData(countryCode, entry[0]);
+ }
+ let formats = entry[0].formats;
+ let current = ParseMetaData(countryCode, entry[n]);
+ current.formats = formats;
+ entry[n] = current;
+ return entry[n];
+ }
+
+ entry[n] = ParseMetaData(countryCode, entry[n]);
+ return entry[n];
+ }
+ }
+ continue;
+ }
+ if (typeof entry == "string" && entry.substr(2, 2) == region) {
+ dataBase[countryCode] = ParseMetaData(countryCode, entry);
+ return dataBase[countryCode];
+ }
+ }
+ }
+
+ // Format a national number for a given region. The boolean flag "intl"
+ // indicates whether we want the national or international format.
+ function FormatNumber(regionMetaData, number, intl) {
+ // We lazily parse the format description in the meta data for the region,
+ // so make sure to parse it now if we haven't already done so.
+ ParseFormat(regionMetaData);
+ let formats = regionMetaData.formats;
+ if (!formats) {
+ return null;
+ }
+ for (let n = 0; n < formats.length; ++n) {
+ let format = formats[n];
+ // The leading digits field is optional. If we don't have it, just
+ // use the matching pattern to qualify numbers.
+ if (format.leadingDigits && !format.leadingDigits.test(number)) {
+ continue;
+ }
+ if (!format.pattern.test(number)) {
+ continue;
+ }
+ if (intl) {
+ // If there is no international format, just fall back to the national
+ // format.
+ let internationalFormat = format.internationalFormat;
+ if (!internationalFormat) {
+ internationalFormat = format.nationalFormat;
+ }
+ // Some regions have numbers that can't be dialed from outside the
+ // country, indicated by "NA" for the international format of that
+ // number format pattern.
+ if (internationalFormat == "NA") {
+ return null;
+ }
+ // Prepend "+" and the country code.
+ number =
+ "+" +
+ regionMetaData.countryCode +
+ " " +
+ number.replace(format.pattern, internationalFormat);
+ } else {
+ number = number.replace(format.pattern, format.nationalFormat);
+ // The region has a national prefix formatting rule, and it can be overwritten
+ // by each actual number format rule.
+ let nationalPrefixFormattingRule =
+ regionMetaData.nationalPrefixFormattingRule;
+ if (format.nationalPrefixFormattingRule) {
+ nationalPrefixFormattingRule = format.nationalPrefixFormattingRule;
+ }
+ if (nationalPrefixFormattingRule) {
+ // The prefix formatting rule contains two magic markers, "$NP" and "$FG".
+ // "$NP" will be replaced by the national prefix, and "$FG" with the
+ // first group of numbers.
+ let match = number.match(SPLIT_FIRST_GROUP);
+ if (match) {
+ let firstGroup = match[1];
+ let rest = match[2];
+ let prefix = nationalPrefixFormattingRule;
+ prefix = prefix.replace("$NP", regionMetaData.nationalPrefix);
+ prefix = prefix.replace("$FG", firstGroup);
+ number = prefix + rest;
+ }
+ }
+ }
+ return number == "NA" ? null : number;
+ }
+ return null;
+ }
+
+ function NationalNumber(regionMetaData, number) {
+ this.region = regionMetaData.region;
+ this.regionMetaData = regionMetaData;
+ this.number = number;
+ }
+
+ // NationalNumber represents the result of parsing a phone number. We have
+ // three getters on the prototype that format the number in national and
+ // international format. Once called, the getters put a direct property
+ // onto the object, caching the result.
+ NationalNumber.prototype = {
+ // +1 949-726-2896
+ get internationalFormat() {
+ let value = FormatNumber(this.regionMetaData, this.number, true);
+ Object.defineProperty(this, "internationalFormat", {
+ value,
+ enumerable: true,
+ });
+ return value;
+ },
+ // (949) 726-2896
+ get nationalFormat() {
+ let value = FormatNumber(this.regionMetaData, this.number, false);
+ Object.defineProperty(this, "nationalFormat", {
+ value,
+ enumerable: true,
+ });
+ return value;
+ },
+ // +19497262896
+ get internationalNumber() {
+ let value = this.internationalFormat
+ ? this.internationalFormat.replace(NON_DIALABLE_CHARS, "")
+ : null;
+ Object.defineProperty(this, "internationalNumber", {
+ value,
+ enumerable: true,
+ });
+ return value;
+ },
+ // 9497262896
+ get nationalNumber() {
+ let value = this.nationalFormat
+ ? this.nationalFormat.replace(NON_DIALABLE_CHARS, "")
+ : null;
+ Object.defineProperty(this, "nationalNumber", {
+ value,
+ enumerable: true,
+ });
+ return value;
+ },
+ // country name 'US'
+ get countryName() {
+ let value = this.region ? this.region : null;
+ Object.defineProperty(this, "countryName", { value, enumerable: true });
+ return value;
+ },
+ // country code '+1'
+ get countryCode() {
+ let value = this.regionMetaData.countryCode
+ ? "+" + this.regionMetaData.countryCode
+ : null;
+ Object.defineProperty(this, "countryCode", { value, enumerable: true });
+ return value;
+ },
+ };
+
+ // Check whether the number is valid for the given region.
+ function IsValidNumber(number, md) {
+ return md.possiblePattern.test(number);
+ }
+
+ // Check whether the number is a valid national number for the given region.
+ /* eslint-disable no-unused-vars */
+ function IsNationalNumber(number, md) {
+ return IsValidNumber(number, md) && md.nationalPattern.test(number);
+ }
+
+ // Determine the country code a number starts with, or return null if
+ // its not a valid country code.
+ function ParseCountryCode(number) {
+ for (let n = 1; n <= 3; ++n) {
+ let cc = number.substr(0, n);
+ if (dataBase[cc]) {
+ return cc;
+ }
+ }
+ return null;
+ }
+
+ // Parse a national number for a specific region. Return null if the
+ // number is not a valid national number (it might still be a possible
+ // number for parts of that region).
+ function ParseNationalNumber(number, md) {
+ if (!md.possiblePattern.test(number) || !md.nationalPattern.test(number)) {
+ return null;
+ }
+ // Success.
+ return new NationalNumber(md, number);
+ }
+
+ function ParseNationalNumberAndCheckNationalPrefix(number, md) {
+ let ret;
+
+ // This is not an international number. See if its a national one for
+ // the current region. National numbers can start with the national
+ // prefix, or without.
+ if (md.nationalPrefixForParsing) {
+ // Some regions have specific national prefix parse rules. Apply those.
+ let withoutPrefix = number.replace(
+ md.nationalPrefixForParsing,
+ md.nationalPrefixTransformRule || ""
+ );
+ ret = ParseNationalNumber(withoutPrefix, md);
+ if (ret) {
+ return ret;
+ }
+ } else {
+ // If there is no specific national prefix rule, just strip off the
+ // national prefix from the beginning of the number (if there is one).
+ let nationalPrefix = md.nationalPrefix;
+ if (
+ nationalPrefix &&
+ number.indexOf(nationalPrefix) == 0 &&
+ (ret = ParseNationalNumber(number.substr(nationalPrefix.length), md))
+ ) {
+ return ret;
+ }
+ }
+ ret = ParseNationalNumber(number, md);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ function ParseNumberByCountryCode(number, countryCode) {
+ let ret;
+
+ // Lookup the meta data for the region (or regions) and if the rest of
+ // the number parses for that region, return the parsed number.
+ let entry = dataBase[countryCode];
+ if (Array.isArray(entry)) {
+ for (let n = 0; n < entry.length; ++n) {
+ if (typeof entry[n] == "string") {
+ entry[n] = ParseMetaData(countryCode, entry[n]);
+ }
+ if (n > 0) {
+ entry[n].formats = entry[0].formats;
+ }
+ ret = ParseNationalNumberAndCheckNationalPrefix(number, entry[n]);
+ if (ret) {
+ return ret;
+ }
+ }
+ return null;
+ }
+ if (typeof entry == "string") {
+ entry = dataBase[countryCode] = ParseMetaData(countryCode, entry);
+ }
+ return ParseNationalNumberAndCheckNationalPrefix(number, entry);
+ }
+
+ // Parse an international number that starts with the country code. Return
+ // null if the number is not a valid international number.
+ function ParseInternationalNumber(number) {
+ // Parse and strip the country code.
+ let countryCode = ParseCountryCode(number);
+ if (!countryCode) {
+ return null;
+ }
+ number = number.substr(countryCode.length);
+
+ return ParseNumberByCountryCode(number, countryCode);
+ }
+
+ // Parse a number and transform it into the national format, removing any
+ // international dial prefixes and country codes.
+ function ParseNumber(number, defaultRegion) {
+ let ret;
+
+ // Remove formating characters and whitespace.
+ number = lazy.PhoneNumberNormalizer.Normalize(number);
+
+ // If there is no defaultRegion or the defaultRegion is the global region,
+ // we can't parse international access codes.
+ if ((!defaultRegion || defaultRegion === "001") && number[0] !== "+") {
+ return null;
+ }
+
+ // Detect and strip leading '+'.
+ if (number[0] === "+") {
+ return ParseInternationalNumber(
+ number.replace(LEADING_PLUS_CHARS_PATTERN, "")
+ );
+ }
+
+ // If "defaultRegion" is a country code, use it to parse the number directly.
+ let matches = String(defaultRegion).match(/^\+?(\d+)/);
+ if (matches) {
+ let countryCode = ParseCountryCode(matches[1]);
+ if (!countryCode) {
+ return null;
+ }
+ return ParseNumberByCountryCode(number, countryCode);
+ }
+
+ // Lookup the meta data for the given region.
+ let md = FindMetaDataForRegion(defaultRegion.toUpperCase());
+ if (!md) {
+ dump("Couldn't find Meta Data for region: " + defaultRegion + "\n");
+ return null;
+ }
+
+ // See if the number starts with an international prefix, and if the
+ // number resulting from stripping the code is valid, then remove the
+ // prefix and flag the number as international.
+ if (md.internationalPrefix.test(number)) {
+ let possibleNumber = number.replace(md.internationalPrefix, "");
+ ret = ParseInternationalNumber(possibleNumber);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ ret = ParseNationalNumberAndCheckNationalPrefix(number, md);
+ if (ret) {
+ return ret;
+ }
+
+ // Now lets see if maybe its an international number after all, but
+ // without '+' or the international prefix.
+ ret = ParseInternationalNumber(number);
+ if (ret) {
+ return ret;
+ }
+
+ // If the number matches the possible numbers of the current region,
+ // return it as a possible number.
+ if (md.possiblePattern.test(number)) {
+ return new NationalNumber(md, number);
+ }
+
+ // We couldn't parse the number at all.
+ return null;
+ }
+
+ function IsPlainPhoneNumber(number) {
+ if (typeof number !== "string") {
+ return false;
+ }
+
+ let length = number.length;
+ let isTooLong = length > MAX_PHONE_NUMBER_LENGTH;
+ let isEmpty = length === 0;
+ return !(isTooLong || isEmpty || NON_DIALABLE_CHARS_ONCE.test(number));
+ }
+
+ return {
+ IsPlain: IsPlainPhoneNumber,
+ IsValid: IsValidNumber,
+ Parse: ParseNumber,
+ FindMetaDataForRegion,
+ };
+})(PHONE_NUMBER_META_DATA);
diff --git a/toolkit/components/formautofill/shared/PhoneNumberMetaData.sys.mjs b/toolkit/components/formautofill/shared/PhoneNumberMetaData.sys.mjs
new file mode 100644
index 0000000000..3338ce7c16
--- /dev/null
+++ b/toolkit/components/formautofill/shared/PhoneNumberMetaData.sys.mjs
@@ -0,0 +1,291 @@
+/* This Source Code Form is subject to the terms of the Apache License, Version
+ * 2.0. If a copy of the Apache License was not distributed with this file, You
+ * can obtain one at https://www.apache.org/licenses/LICENSE-2.0 */
+
+/*
+ * This data was generated base on libphonenumber v8.4.1 via the script in
+ * https://github.com/andreasgal/PhoneNumber.js
+ *
+ * The XML format of libphonenumber has changed since v8.4.2 so we can only stay
+ * in this version for now.
+ */
+
+export var PHONE_NUMBER_META_DATA = {
+ 46: '["SE","00","0",null,null,"$NP$FG","\\\\d{6,12}","[1-35-9]\\\\d{5,11}|4\\\\d{6,8}",[["(8)(\\\\d{2,3})(\\\\d{2,3})(\\\\d{2})","$1-$2 $3 $4","8",null,"$1 $2 $3 $4"],["([1-69]\\\\d)(\\\\d{2,3})(\\\\d{2})(\\\\d{2})","$1-$2 $3 $4","1[013689]|2[0136]|3[1356]|4[0246]|54|6[03]|90",null,"$1 $2 $3 $4"],["([1-469]\\\\d)(\\\\d{3})(\\\\d{2})","$1-$2 $3","1[136]|2[136]|3[356]|4[0246]|6[03]|90",null,"$1 $2 $3"],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1-$2 $3 $4","1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[0-5]|4[0-3])",null,"$1 $2 $3 $4"],["(\\\\d{3})(\\\\d{2,3})(\\\\d{2})","$1-$2 $3","1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[0-5]|4[0-3])",null,"$1 $2 $3"],["(7\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1-$2 $3 $4","7",null,"$1 $2 $3 $4"],["(77)(\\\\d{2})(\\\\d{2})","$1-$2$3","7",null,"$1 $2 $3"],["(20)(\\\\d{2,3})(\\\\d{2})","$1-$2 $3","20",null,"$1 $2 $3"],["(9[034]\\\\d)(\\\\d{2})(\\\\d{2})(\\\\d{3})","$1-$2 $3 $4","9[034]",null,"$1 $2 $3 $4"],["(9[034]\\\\d)(\\\\d{4})","$1-$2","9[034]",null,"$1 $2"],["(\\\\d{3})(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1-$2 $3 $4 $5","25[245]|67[3-6]",null,"$1 $2 $3 $4 $5"]]]',
+ 299: '["GL","00",null,null,null,null,"\\\\d{6}","[1-689]\\\\d{5}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3",null,null]]]',
+ 385: '["HR","00","0",null,null,"$NP$FG","\\\\d{6,9}","[1-7]\\\\d{5,8}|[89]\\\\d{6,8}",[["(1)(\\\\d{4})(\\\\d{3})","$1 $2 $3","1",null],["([2-5]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[2-5]",null],["(9\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","9",null],["(6[01])(\\\\d{2})(\\\\d{2,3})","$1 $2 $3","6[01]",null],["([67]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[67]",null],["(80[01])(\\\\d{2})(\\\\d{2,3})","$1 $2 $3","8",null],["(80[01])(\\\\d{3})(\\\\d{3})","$1 $2 $3","8",null]]]',
+ 670: '["TL","00",null,null,null,null,"\\\\d{7,8}","[2-489]\\\\d{6}|7\\\\d{6,7}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[2-489]",null],["(\\\\d{4})(\\\\d{4})","$1 $2","7",null]]]',
+ 258: '["MZ","00",null,null,null,null,"\\\\d{8,9}","[28]\\\\d{7,8}",[["([28]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","2|8[2-7]",null],["(80\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","80",null]]]',
+ 359: '["BG","00","0",null,null,"$NP$FG","\\\\d{5,9}","[23567]\\\\d{5,7}|[489]\\\\d{6,8}",[["(2)(\\\\d)(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","2",null],["(2)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","2",null],["(\\\\d{3})(\\\\d{4})","$1 $2","43[124-7]|70[1-9]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{2})","$1 $2 $3","43[124-7]|70[1-9]",null],["(\\\\d{3})(\\\\d{2})(\\\\d{3})","$1 $2 $3","[78]00",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","999",null],["(\\\\d{2})(\\\\d{3})(\\\\d{2,3})","$1 $2 $3","[356]|4[124-7]|7[1-9]|8[1-6]|9[1-7]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","48|8[7-9]|9[08]",null]]]',
+ 682: '["CK","00",null,null,null,null,"\\\\d{5}","[2-8]\\\\d{4}",[["(\\\\d{2})(\\\\d{3})","$1 $2",null,null]]]',
+ 852: '["HK","00(?:[126-9]|30|5[09])?",null,null,null,null,"\\\\d{5,11}","[235-7]\\\\d{7}|8\\\\d{7,8}|9\\\\d{4,10}",[["(\\\\d{4})(\\\\d{4})","$1 $2","[235-7]|[89](?:0[1-9]|[1-9])",null],["(800)(\\\\d{3})(\\\\d{3})","$1 $2 $3","800",null],["(900)(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","900",null],["(900)(\\\\d{2,5})","$1 $2","900",null]]]',
+ 998: '["UZ","810","8",null,null,"$NP $FG","\\\\d{7,9}","[679]\\\\d{8}",[["([679]\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 291: '["ER","00","0",null,null,"$NP$FG","\\\\d{6,7}","[178]\\\\d{6}",[["(\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3",null,null]]]',
+ 95: '["MM","00","0",null,null,"$NP$FG","\\\\d{5,10}","[1478]\\\\d{5,7}|[256]\\\\d{5,8}|9(?:[279]\\\\d{0,2}|[58]|[34]\\\\d{1,2}|6\\\\d?)\\\\d{6}",[["(\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","1|2[245]",null],["(2)(\\\\d{4})(\\\\d{4})","$1 $2 $3","251",null],["(\\\\d)(\\\\d{2})(\\\\d{3})","$1 $2 $3","16|2",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","67|81",null],["(\\\\d{2})(\\\\d{2})(\\\\d{3,4})","$1 $2 $3","[4-8]",null],["(9)(\\\\d{3})(\\\\d{4,6})","$1 $2 $3","9(?:2[0-4]|[35-9]|4[137-9])",null],["(9)([34]\\\\d{4})(\\\\d{4})","$1 $2 $3","9(?:3[0-36]|4[0-57-9])",null],["(9)(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","92[56]",null],["(9)(\\\\d{3})(\\\\d{3})(\\\\d{2})","$1 $2 $3 $4","93",null]]]',
+ 266: '["LS","00",null,null,null,null,"\\\\d{8}","[2568]\\\\d{7}",[["(\\\\d{4})(\\\\d{4})","$1 $2",null,null]]]',
+ 245: '["GW","00",null,null,null,null,"\\\\d{7,9}","(?:4(?:0\\\\d{5}|4\\\\d{7})|9\\\\d{8})",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","44|9[567]",null],["(\\\\d{3})(\\\\d{4})","$1 $2","40",null]]]',
+ 374: '["AM","00","0",null,null,"($NP$FG)","\\\\d{5,8}","[1-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{6})","$1 $2","1|47",null],["(\\\\d{2})(\\\\d{6})","$1 $2","4[1349]|[5-7]|9[1-9]","$NP$FG"],["(\\\\d{3})(\\\\d{5})","$1 $2","[23]",null],["(\\\\d{3})(\\\\d{2})(\\\\d{3})","$1 $2 $3","8|90","$NP $FG"]]]',
+ 61: [
+ '["AU","(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]","0",null,null,null,"\\\\d{6,10}","1\\\\d{4,9}|[2-578]\\\\d{8}",[["([2378])(\\\\d{4})(\\\\d{4})","$1 $2 $3","[2378]","($NP$FG)"],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[45]|14","$NP$FG"],["(16)(\\\\d{3,4})","$1 $2","16","$NP$FG"],["(16)(\\\\d{3})(\\\\d{2,4})","$1 $2 $3","16","$NP$FG"],["(1[389]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","1(?:[38]0|90)","$FG"],["(180)(2\\\\d{3})","$1 $2","180","$FG"],["(19\\\\d)(\\\\d{3})","$1 $2","19[13]","$FG"],["(19\\\\d{2})(\\\\d{4})","$1 $2","19[679]","$FG"],["(13)(\\\\d{2})(\\\\d{2})","$1 $2 $3","13[1-9]","$FG"]]]',
+ '["CC","(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]","0",null,null,null,"\\\\d{6,10}","[1458]\\\\d{5,9}"]',
+ '["CX","(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]","0",null,null,null,"\\\\d{6,10}","[1458]\\\\d{5,9}"]',
+ ],
+ 500: '["FK","00",null,null,null,null,"\\\\d{5}","[2-7]\\\\d{4}"]',
+ 261: '["MG","00","0",null,null,"$NP$FG","\\\\d{7,9}","[23]\\\\d{8}",[["([23]\\\\d)(\\\\d{2})(\\\\d{3})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 92: '["PK","00","0",null,null,"($NP$FG)","\\\\d{6,12}","1\\\\d{8}|[2-8]\\\\d{5,11}|9(?:[013-9]\\\\d{4,9}|2\\\\d(?:111\\\\d{6}|\\\\d{3,7}))",[["(\\\\d{2})(111)(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)1",null],["(\\\\d{3})(111)(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","2[349]|45|54|60|72|8[2-5]|9[2-9]",null],["(\\\\d{2})(\\\\d{7,8})","$1 $2","(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]",null],["(\\\\d{3})(\\\\d{6,7})","$1 $2","2[349]|45|54|60|72|8[2-5]|9[2-9]",null],["(3\\\\d{2})(\\\\d{7})","$1 $2","3","$NP$FG"],["([15]\\\\d{3})(\\\\d{5,6})","$1 $2","58[12]|1",null],["(586\\\\d{2})(\\\\d{5})","$1 $2","586",null],["([89]00)(\\\\d{3})(\\\\d{2})","$1 $2 $3","[89]00","$NP$FG"]]]',
+ 234: '["NG","009","0",null,null,"$NP$FG","\\\\d{5,14}","[1-6]\\\\d{5,8}|9\\\\d{5,9}|[78]\\\\d{5,13}",[["(\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[12]|9(?:0[3-9]|[1-9])",null],["(\\\\d{2})(\\\\d{3})(\\\\d{2,3})","$1 $2 $3","[3-6]|7(?:[1-79]|0[1-9])|8[2-9]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","70|8[01]|90[235-9]",null],["([78]00)(\\\\d{4})(\\\\d{4,5})","$1 $2 $3","[78]00",null],["([78]00)(\\\\d{5})(\\\\d{5,6})","$1 $2 $3","[78]00",null],["(78)(\\\\d{2})(\\\\d{3})","$1 $2 $3","78",null]]]',
+ 350: '["GI","00",null,null,null,null,"\\\\d{8}","[2568]\\\\d{7}",[["(\\\\d{3})(\\\\d{5})","$1 $2","2",null]]]',
+ 45: '["DK","00",null,null,null,null,"\\\\d{8}","[2-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 963: '["SY","00","0",null,null,"$NP$FG","\\\\d{6,9}","[1-59]\\\\d{7,8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[1-5]",null],["(9\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","9",null]]]',
+ 226: '["BF","00",null,null,null,null,"\\\\d{8}","[25-7]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 974: '["QA","00",null,null,null,null,"\\\\d{7,8}","[2-8]\\\\d{6,7}",[["([28]\\\\d{2})(\\\\d{4})","$1 $2","[28]",null],["([3-7]\\\\d{3})(\\\\d{4})","$1 $2","[3-7]",null]]]',
+ 218: '["LY","00","0",null,null,"$NP$FG","\\\\d{7,9}","[25679]\\\\d{8}",[["([25679]\\\\d)(\\\\d{7})","$1-$2",null,null]]]',
+ 51: '["PE","19(?:1[124]|77|90)00","0",null,null,"($NP$FG)","\\\\d{6,9}","[14-9]\\\\d{7,8}",[["(1)(\\\\d{7})","$1 $2","1",null],["([4-8]\\\\d)(\\\\d{6})","$1 $2","[4-7]|8[2-4]",null],["(\\\\d{3})(\\\\d{5})","$1 $2","80",null],["(9\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","9","$FG"]]]',
+ 62: '["ID","0(?:0[1789]|10(?:00|1[67]))","0",null,null,"$NP$FG","\\\\d{5,12}","(?:[1-79]\\\\d{6,10}|8\\\\d{7,11})",[["(\\\\d{2})(\\\\d{5,8})","$1 $2","2[124]|[36]1","($NP$FG)"],["(\\\\d{3})(\\\\d{5,8})","$1 $2","[4579]|2[035-9]|[36][02-9]","($NP$FG)"],["(8\\\\d{2})(\\\\d{3,4})(\\\\d{3})","$1-$2-$3","8[1-35-9]",null],["(8\\\\d{2})(\\\\d{4})(\\\\d{4,5})","$1-$2-$3","8[1-35-9]",null],["(1)(500)(\\\\d{3})","$1 $2 $3","15","$FG"],["(177)(\\\\d{6,8})","$1 $2","17",null],["(800)(\\\\d{5,7})","$1 $2","800",null],["(804)(\\\\d{3})(\\\\d{4})","$1 $2 $3","804",null],["(80\\\\d)(\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","80[79]",null]]]',
+ 298: '["FO","00",null,"(10(?:01|[12]0|88))",null,null,"\\\\d{6}","[2-9]\\\\d{5}",[["(\\\\d{6})","$1",null,null]]]',
+ 381: '["RS","00","0",null,null,"$NP$FG","\\\\d{5,12}","[126-9]\\\\d{4,11}|3(?:[0-79]\\\\d{3,10}|8[2-9]\\\\d{2,9})",[["([23]\\\\d{2})(\\\\d{4,9})","$1 $2","(?:2[389]|39)0",null],["([1-3]\\\\d)(\\\\d{5,10})","$1 $2","1|2(?:[0-24-7]|[389][1-9])|3(?:[0-8]|9[1-9])",null],["(6\\\\d)(\\\\d{6,8})","$1 $2","6",null],["([89]\\\\d{2})(\\\\d{3,9})","$1 $2","[89]",null],["(7[26])(\\\\d{4,9})","$1 $2","7[26]",null],["(7[08]\\\\d)(\\\\d{4,9})","$1 $2","7[08]",null]]]',
+ 975: '["BT","00",null,null,null,null,"\\\\d{6,8}","[1-8]\\\\d{6,7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","1|77",null],["([2-8])(\\\\d{3})(\\\\d{3})","$1 $2 $3","[2-68]|7[246]",null]]]',
+ 34: '["ES","00",null,null,null,null,"\\\\d{9}","[5-9]\\\\d{8}",[["([89]00)(\\\\d{3})(\\\\d{3})","$1 $2 $3","[89]00",null],["([5-9]\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[568]|[79][0-8]",null]]]',
+ 881: '["001",null,null,null,null,null,"\\\\d{9}","[67]\\\\d{8}",[["(\\\\d)(\\\\d{3})(\\\\d{5})","$1 $2 $3","[67]",null]]]',
+ 855: '["KH","00[14-9]","0",null,null,null,"\\\\d{6,10}","[1-9]\\\\d{7,9}",[["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","1\\\\d[1-9]|[2-9]","$NP$FG"],["(1[89]00)(\\\\d{3})(\\\\d{3})","$1 $2 $3","1[89]0",null]]]',
+ 420: '["CZ","00",null,null,null,null,"\\\\d{9,12}","[2-8]\\\\d{8}|9\\\\d{8,11}",[["([2-9]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[2-8]|9[015-7]",null],["(96\\\\d)(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","96",null],["(9\\\\d)(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","9[36]",null]]]',
+ 216: '["TN","00",null,null,null,null,"\\\\d{8}","[2-57-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3",null,null]]]',
+ 673: '["BN","00",null,null,null,null,"\\\\d{7}","[2-578]\\\\d{6}",[["([2-578]\\\\d{2})(\\\\d{4})","$1 $2",null,null]]]',
+ 290: [
+ '["SH","00",null,null,null,null,"\\\\d{4,5}","[256]\\\\d{4}"]',
+ '["TA","00",null,null,null,null,"\\\\d{4}","8\\\\d{3}"]',
+ ],
+ 882: '["001",null,null,null,null,null,"\\\\d{7,12}","[13]\\\\d{6,11}",[["(\\\\d{2})(\\\\d{4})(\\\\d{3})","$1 $2 $3","3[23]",null],["(\\\\d{2})(\\\\d{5})","$1 $2","16|342",null],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1 $2 $3","34[57]",null],["(\\\\d{3})(\\\\d{4})(\\\\d{4})","$1 $2 $3","348",null],["(\\\\d{2})(\\\\d{2})(\\\\d{4})","$1 $2 $3","1",null],["(\\\\d{2})(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","16",null],["(\\\\d{2})(\\\\d{4,5})(\\\\d{5})","$1 $2 $3","16|39",null]]]',
+ 267: '["BW","00",null,null,null,null,"\\\\d{7,8}","[2-79]\\\\d{6,7}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[2-6]",null],["(7\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","7",null],["(90)(\\\\d{5})","$1 $2","9",null]]]',
+ 94: '["LK","00","0",null,null,"$NP$FG","\\\\d{7,9}","[1-9]\\\\d{8}",[["(\\\\d{2})(\\\\d{1})(\\\\d{6})","$1 $2 $3","[1-689]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","7",null]]]',
+ 356: '["MT","00",null,null,null,null,"\\\\d{8}","[2357-9]\\\\d{7}",[["(\\\\d{4})(\\\\d{4})","$1 $2",null,null]]]',
+ 375: '["BY","810","8","8?0?",null,null,"\\\\d{5,11}","[1-4]\\\\d{8}|800\\\\d{3,7}|[89]\\\\d{9,10}",[["(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2-$3-$4","17[0-3589]|2[4-9]|[34]","$NP 0$FG"],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2-$3-$4","1(?:5[24]|6[235]|7[467])|2(?:1[246]|2[25]|3[26])","$NP 0$FG"],["(\\\\d{4})(\\\\d{2})(\\\\d{3})","$1 $2-$3","1(?:5[169]|6[3-5]|7[179])|2(?:1[35]|2[34]|3[3-5])","$NP 0$FG"],["([89]\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","8[01]|9","$NP $FG"],["(82\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3","82","$NP $FG"],["(800)(\\\\d{3})","$1 $2","800","$NP $FG"],["(800)(\\\\d{2})(\\\\d{2,4})","$1 $2 $3","800","$NP $FG"]]]',
+ 690: '["TK","00",null,null,null,null,"\\\\d{4,7}","[2-47]\\\\d{3,6}"]',
+ 507: '["PA","00",null,null,null,null,"\\\\d{7,8}","[1-9]\\\\d{6,7}",[["(\\\\d{3})(\\\\d{4})","$1-$2","[1-57-9]",null],["(\\\\d{4})(\\\\d{4})","$1-$2","6",null]]]',
+ 692: '["MH","011","1",null,null,null,"\\\\d{7}","[2-6]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1-$2",null,null]]]',
+ 250: '["RW","00","0",null,null,null,"\\\\d{8,9}","[027-9]\\\\d{7,8}",[["(2\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","2","$FG"],["([7-9]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[7-9]","$NP$FG"],["(0\\\\d)(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","0",null]]]',
+ 81: '["JP","010","0",null,null,"$NP$FG","\\\\d{8,17}","[1-9]\\\\d{8,9}|00(?:[36]\\\\d{7,14}|7\\\\d{5,7}|8\\\\d{7})",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1-$2-$3","(?:12|57|99)0",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1-$2-$3","800",null],["(\\\\d{4})(\\\\d{4})","$1-$2","0077","$FG","NA"],["(\\\\d{4})(\\\\d{2})(\\\\d{3,4})","$1-$2-$3","0077","$FG","NA"],["(\\\\d{4})(\\\\d{2})(\\\\d{4})","$1-$2-$3","0088","$FG","NA"],["(\\\\d{4})(\\\\d{3})(\\\\d{3,4})","$1-$2-$3","00(?:37|66)","$FG","NA"],["(\\\\d{4})(\\\\d{4})(\\\\d{4,5})","$1-$2-$3","00(?:37|66)","$FG","NA"],["(\\\\d{4})(\\\\d{5})(\\\\d{5,6})","$1-$2-$3","00(?:37|66)","$FG","NA"],["(\\\\d{4})(\\\\d{6})(\\\\d{6,7})","$1-$2-$3","00(?:37|66)","$FG","NA"],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1-$2-$3","[2579]0|80[1-9]",null],["(\\\\d{4})(\\\\d)(\\\\d{4})","$1-$2-$3","1(?:26|3[79]|4[56]|5[4-68]|6[3-5])|5(?:76|97)|499|746|8(?:3[89]|63|47|51)|9(?:49|80|9[16])",null],["(\\\\d{3})(\\\\d{2})(\\\\d{4})","$1-$2-$3","1(?:2[3-6]|3[3-9]|4[2-6]|5[2-8]|[68][2-7]|7[2-689]|9[1-578])|2(?:2[03-689]|3[3-58]|4[0-468]|5[04-8]|6[013-8]|7[06-9]|8[02-57-9]|9[13])|4(?:2[28]|3[689]|6[035-7]|7[05689]|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9[4-9])|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9[014-9])|8(?:2[49]|3[3-8]|4[5-8]|5[2-9]|6[35-9]|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9[3-7])",null],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1-$2-$3","1|2(?:2[37]|5[5-9]|64|78|8[39]|91)|4(?:2[2689]|64|7[347])|5(?:[2-589]|39)|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93)",null],["(\\\\d{3})(\\\\d{2})(\\\\d{4})","$1-$2-$3","2(?:9[14-79]|74|[34]7|[56]9)|82|993",null],["(\\\\d)(\\\\d{4})(\\\\d{4})","$1-$2-$3","3|4(?:2[09]|7[01])|6[1-9]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1-$2-$3","[2479][1-9]",null]]]',
+ 237: '["CM","00",null,null,null,null,"\\\\d{8,9}","[2368]\\\\d{7,8}",[["([26])(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4 $5","[26]",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[23]|88",null],["(800)(\\\\d{2})(\\\\d{3})","$1 $2 $3","80",null]]]',
+ 351: '["PT","00",null,null,null,null,"\\\\d{9}","[2-46-9]\\\\d{8}",[["(2\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","2[12]",null],["([2-46-9]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","2[3-9]|[346-9]",null]]]',
+ 246: '["IO","00",null,null,null,null,"\\\\d{7}","3\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 227: '["NE","00",null,null,null,null,"\\\\d{8}","[0289]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[289]|09",null],["(08)(\\\\d{3})(\\\\d{3})","$1 $2 $3","08",null]]]',
+ 27: '["ZA","00","0",null,null,"$NP$FG","\\\\d{5,9}","[1-79]\\\\d{8}|8\\\\d{4,8}",[["(860)(\\\\d{3})(\\\\d{3})","$1 $2 $3","860",null],["(\\\\d{2})(\\\\d{3,4})","$1 $2","8[1-4]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{2,3})","$1 $2 $3","8[1-4]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[1-79]|8(?:[0-57]|6[1-9])",null]]]',
+ 962: '["JO","00","0",null,null,"$NP$FG","\\\\d{8,9}","[235-9]\\\\d{7,8}",[["(\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","[2356]|87","($NP$FG)"],["(7)(\\\\d{4})(\\\\d{4})","$1 $2 $3","7[457-9]",null],["(\\\\d{3})(\\\\d{5,6})","$1 $2","70|8[0158]|9",null]]]',
+ 387: '["BA","00","0",null,null,"$NP$FG","\\\\d{6,9}","[3-9]\\\\d{7,8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2-$3","[3-5]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","6[1-356]|[7-9]",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3 $4","6[047]",null]]]',
+ 33: '["FR","00","0",null,null,"$NP$FG","\\\\d{9}","[1-9]\\\\d{8}",[["([1-79])(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4 $5","[1-79]",null],["(1\\\\d{2})(\\\\d{3})","$1 $2","11","$FG","NA"],["(8\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","8","$NP $FG"]]]',
+ 972: '["IL","0(?:0|1[2-9])","0",null,null,"$FG","\\\\d{4,12}","1\\\\d{6,11}|[2-589]\\\\d{3}(?:\\\\d{3,6})?|6\\\\d{3}|7\\\\d{6,9}",[["([2-489])(\\\\d{3})(\\\\d{4})","$1-$2-$3","[2-489]","$NP$FG"],["([57]\\\\d)(\\\\d{3})(\\\\d{4})","$1-$2-$3","[57]","$NP$FG"],["(153)(\\\\d{1,2})(\\\\d{3})(\\\\d{4})","$1 $2 $3 $4","153",null],["(1)([7-9]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1-$2-$3-$4","1[7-9]",null],["(1255)(\\\\d{3})","$1-$2","125",null],["(1200)(\\\\d{3})(\\\\d{3})","$1-$2-$3","120",null],["(1212)(\\\\d{2})(\\\\d{2})","$1-$2-$3","121",null],["(1599)(\\\\d{6})","$1-$2","15",null],["(\\\\d{4})","*$1","[2-689]",null]]]',
+ 248: '["SC","0(?:[02]|10?)",null,null,null,null,"\\\\d{6,7}","[24689]\\\\d{5,6}",[["(\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","[246]",null]]]',
+ 297: '["AW","00",null,null,null,null,"\\\\d{7}","[25-9]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 421: '["SK","00","0",null,null,"$NP$FG","\\\\d{6,9}","(?:[2-68]\\\\d{5,8}|9\\\\d{6,8})",[["(2)(1[67])(\\\\d{3,4})","$1 $2 $3","21[67]",null],["([3-5]\\\\d)(1[67])(\\\\d{2,3})","$1 $2 $3","[3-5]",null],["(2)(\\\\d{3})(\\\\d{3})(\\\\d{2})","$1/$2 $3 $4","2",null],["([3-5]\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1/$2 $3 $4","[3-5]",null],["([689]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[689]",null],["(9090)(\\\\d{3})","$1 $2","9090",null]]]',
+ 672: '["NF","00",null,null,null,null,"\\\\d{5,6}","[13]\\\\d{5}",[["(\\\\d{2})(\\\\d{4})","$1 $2","1",null],["(\\\\d)(\\\\d{5})","$1 $2","3",null]]]',
+ 870: '["001",null,null,null,null,null,"\\\\d{9}","[35-7]\\\\d{8}",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3",null,null]]]',
+ 883: '["001",null,null,null,null,null,"\\\\d{9}(?:\\\\d{3})?","51\\\\d{7}(?:\\\\d{3})?",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","510",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","510",null],["(\\\\d{4})(\\\\d{4})(\\\\d{4})","$1 $2 $3","51[13]",null]]]',
+ 264: '["NA","00","0",null,null,"$NP$FG","\\\\d{8,9}","[68]\\\\d{7,8}",[["(8\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","8[1235]",null],["(6\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","6",null],["(88)(\\\\d{3})(\\\\d{3})","$1 $2 $3","88",null],["(870)(\\\\d{3})(\\\\d{3})","$1 $2 $3","870",null]]]',
+ 878: '["001",null,null,null,null,null,"\\\\d{12}","1\\\\d{11}",[["(\\\\d{2})(\\\\d{5})(\\\\d{5})","$1 $2 $3",null,null]]]',
+ 239: '["ST","00",null,null,null,null,"\\\\d{7}","[29]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 357: '["CY","00",null,null,null,null,"\\\\d{8}","[257-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{6})","$1 $2",null,null]]]',
+ 240: '["GQ","00",null,null,null,null,"\\\\d{9}","[23589]\\\\d{8}",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[235]",null],["(\\\\d{3})(\\\\d{6})","$1 $2","[89]",null]]]',
+ 506: '["CR","00",null,"(19(?:0[012468]|1[09]|20|66|77|99))",null,null,"\\\\d{8,10}","[24-9]\\\\d{7,9}",[["(\\\\d{4})(\\\\d{4})","$1 $2","[24-7]|8[3-9]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1-$2-$3","[89]0",null]]]',
+ 86: '["CN","(1(?:[129]\\\\d{3}|79\\\\d{2}))?00","0","(1(?:[129]\\\\d{3}|79\\\\d{2}))|0",null,null,"\\\\d{4,12}","[1-7]\\\\d{6,11}|8[0-357-9]\\\\d{6,9}|9\\\\d{7,10}",[["(80\\\\d{2})(\\\\d{4})","$1 $2","80[2678]","$NP$FG"],["([48]00)(\\\\d{3})(\\\\d{4})","$1 $2 $3","[48]00",null],["(\\\\d{5,6})","$1","100|95",null,"NA"],["(\\\\d{2})(\\\\d{5,6})","$1 $2","(?:10|2\\\\d)[19]","$NP$FG"],["(\\\\d{3})(\\\\d{5,6})","$1 $2","[3-9]","$NP$FG"],["(\\\\d{3,4})(\\\\d{4})","$1 $2","[2-9]",null,"NA"],["(21)(\\\\d{4})(\\\\d{4,6})","$1 $2 $3","21","$NP$FG"],["([12]\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3","10[1-9]|2[02-9]","$NP$FG"],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","3(?:1[02-9]|35|49|5|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|[35][2-9]|6[4789]|7\\\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[04-9]|4[3-6]|6[2368])|8(?:1[236-8]|2[5-7]|3|5[1-9]|7[02-9]|8[3678]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])","$NP$FG"],["(\\\\d{3})(\\\\d{4})(\\\\d{4})","$1 $2 $3","3(?:11|7[179])|4(?:[15]1|3[1-35])|5(?:1|2[37]|3[12]|51|7[13-79]|9[15])|7(?:31|5[457]|6[09]|91)|8(?:[57]1|98)","$NP$FG"],["(\\\\d{4})(\\\\d{3})(\\\\d{4})","$1 $2 $3","807","$NP$FG"],["(\\\\d{3})(\\\\d{4})(\\\\d{4})","$1 $2 $3","1[3-578]",null],["(10800)(\\\\d{3})(\\\\d{4})","$1 $2 $3","108",null],["(\\\\d{3})(\\\\d{7,8})","$1 $2","950",null]]]',
+ 257: '["BI","00",null,null,null,null,"\\\\d{8}","[267]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 683: '["NU","00",null,null,null,null,"\\\\d{4}","[1-5]\\\\d{3}"]',
+ 43: '["AT","00","0",null,null,"$NP$FG","\\\\d{3,13}","[1-9]\\\\d{3,12}",[["(116\\\\d{3})","$1","116","$FG"],["(1)(\\\\d{3,12})","$1 $2","1",null],["(5\\\\d)(\\\\d{3,5})","$1 $2","5[079]",null],["(5\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","5[079]",null],["(5\\\\d)(\\\\d{4})(\\\\d{4,7})","$1 $2 $3","5[079]",null],["(\\\\d{3})(\\\\d{3,10})","$1 $2","316|46|51|732|6(?:5[0-3579]|[6-9])|7(?:[28]0)|[89]",null],["(\\\\d{4})(\\\\d{3,9})","$1 $2","2|3(?:1[1-578]|[3-8])|4[2378]|5[2-6]|6(?:[12]|4[1-9]|5[468])|7(?:2[1-8]|35|4[1-8]|[5-79])",null]]]',
+ 247: '["AC","00",null,null,null,null,"\\\\d{5,6}","[46]\\\\d{4}|[01589]\\\\d{5}"]',
+ 675: '["PG","00",null,null,null,null,"\\\\d{7,8}","[1-9]\\\\d{6,7}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[13-689]|27",null],["(\\\\d{4})(\\\\d{4})","$1 $2","20|7",null]]]',
+ 376: '["AD","00",null,null,null,null,"\\\\d{6,9}","[16]\\\\d{5,8}|[37-9]\\\\d{5}",[["(\\\\d{3})(\\\\d{3})","$1 $2","[137-9]|6[0-8]",null],["(\\\\d{4})(\\\\d{4})","$1 $2","180",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","690",null]]]',
+ 63: '["PH","00","0",null,null,null,"\\\\d{5,13}","2\\\\d{5,7}|[3-9]\\\\d{7,9}|1800\\\\d{7,9}",[["(2)(\\\\d{3})(\\\\d{4})","$1 $2 $3","2","($NP$FG)"],["(2)(\\\\d{5})","$1 $2","2","($NP$FG)"],["(\\\\d{4})(\\\\d{4,6})","$1 $2","3(?:23|39|46)|4(?:2[3-6]|[35]9|4[26]|76)|5(?:22|44)|642|8(?:62|8[245])","($NP$FG)"],["(\\\\d{5})(\\\\d{4})","$1 $2","346|4(?:27|9[35])|883","($NP$FG)"],["([3-8]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","[3-8]","($NP$FG)"],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","81|9","$NP$FG"],["(1800)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1",null],["(1800)(\\\\d{1,2})(\\\\d{3})(\\\\d{4})","$1 $2 $3 $4","1",null]]]',
+ 236: '["CF","00",null,null,null,null,"\\\\d{8}","[278]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 590: [
+ '["GP","00","0",null,null,"$NP$FG","\\\\d{9}","[56]\\\\d{8}",[["([56]90)(\\\\d{2})(\\\\d{4})","$1 $2-$3",null,null]]]',
+ '["BL","00","0",null,null,null,"\\\\d{9}","[56]\\\\d{8}"]',
+ '["MF","00","0",null,null,null,"\\\\d{9}","[56]\\\\d{8}"]',
+ ],
+ 53: '["CU","119","0",null,null,"($NP$FG)","\\\\d{4,8}","[2-57]\\\\d{5,7}",[["(\\\\d)(\\\\d{6,7})","$1 $2","7",null],["(\\\\d{2})(\\\\d{4,6})","$1 $2","[2-4]",null],["(\\\\d)(\\\\d{7})","$1 $2","5","$NP$FG"]]]',
+ 64: '["NZ","0(?:0|161)","0",null,null,"$NP$FG","\\\\d{7,11}","6[235-9]\\\\d{6}|[2-57-9]\\\\d{7,10}",[["([34679])(\\\\d{3})(\\\\d{4})","$1-$2 $3","[346]|7[2-57-9]|9[1-9]",null],["(24099)(\\\\d{3})","$1 $2","240",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","21",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3,5})","$1 $2 $3","2(?:1[1-9]|[69]|7[0-35-9])|70|86",null],["(2\\\\d)(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","2[028]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","2(?:10|74)|5|[89]0",null]]]',
+ 965: '["KW","00",null,null,null,null,"\\\\d{7,8}","[12569]\\\\d{6,7}",[["(\\\\d{4})(\\\\d{3,4})","$1 $2","[16]|2(?:[0-35-9]|4[0-35-9])|9[024-9]|52[25]",null],["(\\\\d{3})(\\\\d{5})","$1 $2","244|5(?:[015]|66)",null]]]',
+ 224: '["GN","00",null,null,null,null,"\\\\d{8,9}","[367]\\\\d{7,8}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","3",null],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[67]",null]]]',
+ 973: '["BH","00",null,null,null,null,"\\\\d{8}","[136-9]\\\\d{7}",[["(\\\\d{4})(\\\\d{4})","$1 $2",null,null]]]',
+ 32: '["BE","00","0",null,null,"$NP$FG","\\\\d{8,9}","[1-9]\\\\d{7,8}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","4[6-9]",null],["(\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[23]|4[23]|9[2-4]",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[156]|7[018]|8(?:0[1-9]|[1-79])",null],["(\\\\d{3})(\\\\d{2})(\\\\d{3})","$1 $2 $3","(?:80|9)0",null]]]',
+ 249: '["SD","00","0",null,null,"$NP$FG","\\\\d{9}","[19]\\\\d{8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3",null,null]]]',
+ 678: '["VU","00",null,null,null,null,"\\\\d{5,7}","[2-57-9]\\\\d{4,6}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[579]",null]]]',
+ 52: '["MX","0[09]","01","0[12]|04[45](\\\\d{10})","1$1","$NP $FG","\\\\d{7,11}","[1-9]\\\\d{9,10}",[["([358]\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3","33|55|81",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[2467]|3[0-2457-9]|5[089]|8[02-9]|9[0-35-9]",null],["(1)([358]\\\\d)(\\\\d{4})(\\\\d{4})","044 $2 $3 $4","1(?:33|55|81)","$FG","$1 $2 $3 $4"],["(1)(\\\\d{3})(\\\\d{3})(\\\\d{4})","044 $2 $3 $4","1(?:[2467]|3[0-2457-9]|5[089]|8[2-9]|9[1-35-9])","$FG","$1 $2 $3 $4"]]]',
+ 968: '["OM","00",null,null,null,null,"\\\\d{7,9}","(?:5|[279]\\\\d)\\\\d{6}|800\\\\d{5,6}",[["(2\\\\d)(\\\\d{6})","$1 $2","2",null],["([79]\\\\d{3})(\\\\d{4})","$1 $2","[79]",null],["([58]00)(\\\\d{4,6})","$1 $2","[58]",null]]]',
+ 599: [
+ '["CW","00",null,null,null,null,"\\\\d{7,8}","[169]\\\\d{6,7}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[13-7]",null],["(9)(\\\\d{3})(\\\\d{4})","$1 $2 $3","9",null]]]',
+ '["BQ","00",null,null,null,null,"\\\\d{7}","[347]\\\\d{6}"]',
+ ],
+ 800: '["001",null,null,null,null,null,"\\\\d{8}","\\\\d{8}",[["(\\\\d{4})(\\\\d{4})","$1 $2",null,null]]]',
+ 386: '["SI","00","0",null,null,"$NP$FG","\\\\d{5,8}","[1-7]\\\\d{6,7}|[89]\\\\d{4,7}",[["(\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[12]|3[24-8]|4[24-8]|5[2-8]|7[3-8]","($NP$FG)"],["([3-7]\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","[37][01]|4[0139]|51|6",null],["([89][09])(\\\\d{3,6})","$1 $2","[89][09]",null],["([58]\\\\d{2})(\\\\d{5})","$1 $2","59|8[1-3]",null]]]',
+ 679: '["FJ","0(?:0|52)",null,null,null,null,"\\\\d{7}(?:\\\\d{4})?","[35-9]\\\\d{6}|0\\\\d{10}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[35-9]",null],["(\\\\d{4})(\\\\d{3})(\\\\d{4})","$1 $2 $3","0",null]]]',
+ 238: '["CV","0",null,null,null,null,"\\\\d{7}","[259]\\\\d{6}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3",null,null]]]',
+ 691: '["FM","00",null,null,null,null,"\\\\d{7}","[39]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 262: [
+ '["RE","00","0",null,null,"$NP$FG","\\\\d{9}","[268]\\\\d{8}",[["([268]\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ '["YT","00","0",null,null,"$NP$FG","\\\\d{9}","[268]\\\\d{8}"]',
+ ],
+ 241: '["GA","00",null,null,null,null,"\\\\d{7,8}","0?\\\\d{7}",[["(\\\\d)(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[2-7]","0$FG"],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","0",null]]]',
+ 370: '["LT","00","8","[08]",null,"($NP-$FG)","\\\\d{8}","[3-9]\\\\d{7}",[["([34]\\\\d)(\\\\d{6})","$1 $2","37|4(?:1|5[45]|6[2-4])",null],["([3-6]\\\\d{2})(\\\\d{5})","$1 $2","3[148]|4(?:[24]|6[09])|528|6",null],["([7-9]\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3","[7-9]","$NP $FG"],["(5)(2\\\\d{2})(\\\\d{4})","$1 $2 $3","52[0-79]",null]]]',
+ 256: '["UG","00[057]","0",null,null,"$NP$FG","\\\\d{5,9}","\\\\d{9}",[["(\\\\d{3})(\\\\d{6})","$1 $2","[7-9]|20(?:[013-8]|2[5-9])|4(?:6[45]|[7-9])",null],["(\\\\d{2})(\\\\d{7})","$1 $2","3|4(?:[1-5]|6[0-36-9])",null],["(2024)(\\\\d{5})","$1 $2","2024",null]]]',
+ 677: '["SB","0[01]",null,null,null,null,"\\\\d{5,7}","[1-9]\\\\d{4,6}",[["(\\\\d{2})(\\\\d{5})","$1 $2","[7-9]",null]]]',
+ 377: '["MC","00","0",null,null,"$NP$FG","\\\\d{8,9}","[34689]\\\\d{7,8}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[39]","$FG"],["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","4",null],["(6)(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4 $5","6",null],["(\\\\d{3})(\\\\d{3})(\\\\d{2})","$1 $2 $3","8","$FG"]]]',
+ 382: '["ME","00","0",null,null,"$NP$FG","\\\\d{6,9}","[2-9]\\\\d{7,8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[2-57-9]|6[036-9]",null]]]',
+ 231: '["LR","00","0",null,null,"$NP$FG","\\\\d{7,9}","2\\\\d{7,8}|[378]\\\\d{8}|4\\\\d{6}|5\\\\d{6,8}",[["(2\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","2",null],["([4-5])(\\\\d{3})(\\\\d{3})","$1 $2 $3","[45]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[23578]",null]]]',
+ 591: '["BO","00(1\\\\d)?","0","0(1\\\\d)?",null,null,"\\\\d{7,8}","[23467]\\\\d{7}",[["([234])(\\\\d{7})","$1 $2","[234]",null],["([67]\\\\d{7})","$1","[67]",null]]]',
+ 808: '["001",null,null,null,null,null,"\\\\d{8}","\\\\d{8}",[["(\\\\d{4})(\\\\d{4})","$1 $2",null,null]]]',
+ 964: '["IQ","00","0",null,null,"$NP$FG","\\\\d{6,10}","[1-7]\\\\d{7,9}",[["(1)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1",null],["([2-6]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[2-6]",null],["(7\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","7",null]]]',
+ 225: '["CI","00",null,null,null,null,"\\\\d{8}","[02-8]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 992: '["TJ","810","8",null,null,"$FG","\\\\d{3,9}","[3-57-9]\\\\d{8}",[["([349]\\\\d{2})(\\\\d{2})(\\\\d{4})","$1 $2 $3","[34]7|91[78]",null],["([457-9]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","4[148]|[578]|9(?:1[59]|[0235-9])",null],["(331700)(\\\\d)(\\\\d{2})","$1 $2 $3","331",null],["(\\\\d{4})(\\\\d)(\\\\d{4})","$1 $2 $3","3[1-5]",null]]]',
+ 55: '["BR","00(?:1[245]|2[1-35]|31|4[13]|[56]5|99)","0","(?:0|90)(?:(1[245]|2[135]|[34]1)(\\\\d{10,11}))?","$2",null,"\\\\d{8,11}","[1-46-9]\\\\d{7,10}|5(?:[0-4]\\\\d{7,9}|5(?:[2-8]\\\\d{7}|9\\\\d{7,8}))",[["(\\\\d{4})(\\\\d{4})","$1-$2","[2-9](?:[1-9]|0[1-9])","$FG","NA"],["(\\\\d{5})(\\\\d{4})","$1-$2","9(?:[1-9]|0[1-9])","$FG","NA"],["(\\\\d{3,5})","$1","1[125689]","$FG","NA"],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1 $2-$3","[1-9][1-9]","($FG)"],["(\\\\d{2})(\\\\d{5})(\\\\d{4})","$1 $2-$3","(?:[14689][1-9]|2[12478]|3[1-578]|5[1-5]|7[13-579])9","($FG)"],["(\\\\d{4})(\\\\d{4})","$1-$2","(?:300|40(?:0|20))",null],["([3589]00)(\\\\d{2,3})(\\\\d{4})","$1 $2 $3","[3589]00","$NP$FG"]]]',
+ 674: '["NR","00",null,null,null,null,"\\\\d{7}","[458]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 967: '["YE","00","0",null,null,"$NP$FG","\\\\d{6,9}","[1-7]\\\\d{6,8}",[["([1-7])(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[1-6]|7[24-68]",null],["(7\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","7[0137]",null]]]',
+ 49: '["DE","00","0",null,null,"$NP$FG","\\\\d{2,15}","[1-35-9]\\\\d{3,14}|4(?:[0-8]\\\\d{3,12}|9(?:[0-37]\\\\d|4(?:[1-35-8]|4\\\\d?)|5\\\\d{1,2}|6[1-8]\\\\d?)\\\\d{2,8})",[["(1\\\\d{2})(\\\\d{7,8})","$1 $2","1[67]",null],["(15\\\\d{3})(\\\\d{6})","$1 $2","15[0568]",null],["(1\\\\d{3})(\\\\d{7})","$1 $2","15",null],["(\\\\d{2})(\\\\d{3,11})","$1 $2","3[02]|40|[68]9",null],["(\\\\d{3})(\\\\d{3,11})","$1 $2","2(?:\\\\d1|0[2389]|1[24]|28|34)|3(?:[3-9][15]|40)|[4-8][1-9]1|9(?:06|[1-9]1)",null],["(\\\\d{4})(\\\\d{2,11})","$1 $2","[24-6]|[7-9](?:\\\\d[1-9]|[1-9]\\\\d)|3(?:[3569][02-46-9]|4[2-4679]|7[2-467]|8[2-46-8])",null],["(3\\\\d{4})(\\\\d{1,10})","$1 $2","3",null],["(800)(\\\\d{7,12})","$1 $2","800",null],["(\\\\d{3})(\\\\d)(\\\\d{4,10})","$1 $2 $3","(?:18|90)0|137",null],["(1\\\\d{2})(\\\\d{5,11})","$1 $2","181",null],["(18\\\\d{3})(\\\\d{6})","$1 $2","185",null],["(18\\\\d{2})(\\\\d{7})","$1 $2","18[68]",null],["(18\\\\d)(\\\\d{8})","$1 $2","18[2-579]",null],["(700)(\\\\d{4})(\\\\d{4})","$1 $2 $3","700",null],["(138)(\\\\d{4})","$1 $2","138",null],["(15[013-68])(\\\\d{2})(\\\\d{8})","$1 $2 $3","15[013-68]",null],["(15[279]\\\\d)(\\\\d{2})(\\\\d{7})","$1 $2 $3","15[279]",null],["(1[67]\\\\d)(\\\\d{2})(\\\\d{7,8})","$1 $2 $3","1(?:6[023]|7)",null]]]',
+ 31: '["NL","00","0",null,null,"$NP$FG","\\\\d{5,10}","1\\\\d{4,8}|[2-7]\\\\d{8}|[89]\\\\d{6,9}",[["([1-578]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1[035]|2[0346]|3[03568]|4[0356]|5[0358]|7|8[4578]",null],["([1-5]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","1[16-8]|2[259]|3[124]|4[17-9]|5[124679]",null],["(6)(\\\\d{8})","$1 $2","6[0-57-9]",null],["(66)(\\\\d{7})","$1 $2","66",null],["(14)(\\\\d{3,4})","$1 $2","14","$FG"],["([89]0\\\\d)(\\\\d{4,7})","$1 $2","80|9",null]]]',
+ 970: '["PS","00","0",null,null,"$NP$FG","\\\\d{4,10}","[24589]\\\\d{7,8}|1(?:[78]\\\\d{8}|[49]\\\\d{2,3})",[["([2489])(2\\\\d{2})(\\\\d{4})","$1 $2 $3","[2489]",null],["(5[69]\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","5",null],["(1[78]00)(\\\\d{3})(\\\\d{3})","$1 $2 $3","1[78]","$FG"]]]',
+ 58: '["VE","00","0",null,null,"$NP$FG","\\\\d{7,10}","[24589]\\\\d{9}",[["(\\\\d{3})(\\\\d{7})","$1-$2",null,null]]]',
+ 856: '["LA","00","0",null,null,"$NP$FG","\\\\d{6,10}","[2-8]\\\\d{7,9}",[["(20)(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","20",null],["([2-8]\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","2[13]|3[14]|[4-8]",null],["(30)(\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3 $4","30",null]]]',
+ 354: '["IS","1(?:0(?:01|10|20)|100)|00",null,null,null,null,"\\\\d{7,9}","[4-9]\\\\d{6}|38\\\\d{7}",[["(\\\\d{3})(\\\\d{4})","$1 $2","[4-9]",null],["(3\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","3",null]]]',
+ 242: '["CG","00",null,null,null,null,"\\\\d{9}","[028]\\\\d{8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[02]",null],["(\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3","8",null]]]',
+ 423: '["LI","00","0","0|10(?:01|20|66)",null,null,"\\\\d{7,9}","6\\\\d{8}|[23789]\\\\d{6}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3","[23789]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","6[56]",null],["(69)(7\\\\d{2})(\\\\d{4})","$1 $2 $3","697",null]]]',
+ 213: '["DZ","00","0",null,null,"$NP$FG","\\\\d{8,9}","(?:[1-4]|[5-9]\\\\d)\\\\d{7}",[["([1-4]\\\\d)(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[1-4]",null],["([5-8]\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[5-8]",null],["(9\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","9",null]]]',
+ 371: '["LV","00",null,null,null,null,"\\\\d{8}","[2689]\\\\d{7}",[["([2689]\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3",null,null]]]',
+ 503: '["SV","00",null,null,null,null,"\\\\d{7,8}|\\\\d{11}","[267]\\\\d{7}|[89]\\\\d{6}(?:\\\\d{4})?",[["(\\\\d{4})(\\\\d{4})","$1 $2","[267]",null],["(\\\\d{3})(\\\\d{4})","$1 $2","[89]",null],["(\\\\d{3})(\\\\d{4})(\\\\d{4})","$1 $2 $3","[89]",null]]]',
+ 685: '["WS","0",null,null,null,null,"\\\\d{5,7}","[2-8]\\\\d{4,6}",[["(8\\\\d{2})(\\\\d{3,4})","$1 $2","8",null],["(7\\\\d)(\\\\d{5})","$1 $2","7",null],["(\\\\d{5})","$1","[2-6]",null]]]',
+ 880: '["BD","00","0",null,null,"$NP$FG","\\\\d{6,10}","[2-79]\\\\d{5,9}|1\\\\d{9}|8[0-7]\\\\d{4,8}",[["(2)(\\\\d{7,8})","$1-$2","2",null],["(\\\\d{2})(\\\\d{4,6})","$1-$2","[3-79]1",null],["(\\\\d{4})(\\\\d{3,6})","$1-$2","1|3(?:0|[2-58]2)|4(?:0|[25]2|3[23]|[4689][25])|5(?:[02-578]2|6[25])|6(?:[0347-9]2|[26][25])|7[02-9]2|8(?:[023][23]|[4-7]2)|9(?:[02][23]|[458]2|6[016])",null],["(\\\\d{3})(\\\\d{3,7})","$1-$2","[3-79][2-9]|8",null]]]',
+ 265: '["MW","00","0",null,null,"$NP$FG","\\\\d{7,9}","(?:1(?:\\\\d{2})?|[2789]\\\\d{2})\\\\d{6}",[["(\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","1",null],["(2\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","2",null],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[1789]",null]]]',
+ 65: '["SG","0[0-3]\\\\d",null,null,null,null,"\\\\d{8,11}","[36]\\\\d{7}|[17-9]\\\\d{7,10}",[["([3689]\\\\d{3})(\\\\d{4})","$1 $2","[369]|8[1-9]",null],["(1[89]00)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1[89]",null],["(7000)(\\\\d{4})(\\\\d{3})","$1 $2 $3","70",null],["(800)(\\\\d{3})(\\\\d{4})","$1 $2 $3","80",null]]]',
+ 504: '["HN","00",null,null,null,null,"\\\\d{8}","[237-9]\\\\d{7}",[["(\\\\d{4})(\\\\d{4})","$1-$2",null,null]]]',
+ 688: '["TV","00",null,null,null,null,"\\\\d{5,7}","[279]\\\\d{4,6}"]',
+ 84: '["VN","00","0",null,null,"$NP$FG","\\\\d{7,10}","[167]\\\\d{6,9}|[2-59]\\\\d{7,9}|8\\\\d{6,8}",[["([17]99)(\\\\d{4})","$1 $2","[17]99",null],["([48])(\\\\d{4})(\\\\d{4})","$1 $2 $3","4|8(?:[1-57]|6[0-79]|9[0-7])",null],["([235-7]\\\\d)(\\\\d{4})(\\\\d{3})","$1 $2 $3","2[025-79]|3[0136-9]|5[2-9]|6[0-46-8]|7[02-79]",null],["(80)(\\\\d{5})","$1 $2","80",null],["(69\\\\d)(\\\\d{4,5})","$1 $2","69",null],["([235-7]\\\\d{2})(\\\\d{4})(\\\\d{3})","$1 $2 $3","2[0-489]|3[25]|5[01]|65|7[18]",null],["([89]\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","8(?:68|8|9[89])|9",null],["(1[2689]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1(?:[26]|8[68]|99)",null],["(1[89]00)(\\\\d{4,6})","$1 $2","1[89]0","$FG"]]]',
+ 255: '["TZ","00[056]","0",null,null,"$NP$FG","\\\\d{7,9}","\\\\d{9}",[["([24]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","[24]",null],["([67]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[67]",null],["([89]\\\\d{2})(\\\\d{2})(\\\\d{4})","$1 $2 $3","[89]",null]]]',
+ 222: '["MR","00",null,null,null,null,"\\\\d{8}","[2-48]\\\\d{7}",[["([2-48]\\\\d)(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 230: '["MU","0(?:0|[2-7]0|33)",null,null,null,null,"\\\\d{7,8}","[2-9]\\\\d{6,7}",[["([2-46-9]\\\\d{2})(\\\\d{4})","$1 $2","[2-46-9]",null],["(5\\\\d{3})(\\\\d{4})","$1 $2","5",null]]]',
+ 592: '["GY","001",null,null,null,null,"\\\\d{7}","[2-46-9]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 41: '["CH","00","0",null,null,"$NP$FG","\\\\d{9}(?:\\\\d{3})?","[2-9]\\\\d{8}|860\\\\d{9}",[["([2-9]\\\\d)(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[2-7]|[89]1",null],["([89]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","8[047]|90",null],["(\\\\d{3})(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4 $5","860",null]]]',
+ 39: [
+ '["IT","00",null,null,null,null,"\\\\d{6,11}","[01589]\\\\d{5,10}|3(?:[12457-9]\\\\d{8}|[36]\\\\d{7,9})",[["(\\\\d{2})(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","0[26]|55",null],["(0[26])(\\\\d{4})(\\\\d{5})","$1 $2 $3","0[26]",null],["(0[26])(\\\\d{4,6})","$1 $2","0[26]",null],["(0\\\\d{2})(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","0[13-57-9][0159]",null],["(\\\\d{3})(\\\\d{3,6})","$1 $2","0[13-57-9][0159]|8(?:03|4[17]|9[245])",null],["(0\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","0[13-57-9][2-46-8]",null],["(0\\\\d{3})(\\\\d{2,6})","$1 $2","0[13-57-9][2-46-8]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[13]|8(?:00|4[08]|9[59])",null],["(\\\\d{4})(\\\\d{4})","$1 $2","894",null],["(\\\\d{3})(\\\\d{4})(\\\\d{4})","$1 $2 $3","3",null]]]',
+ '["VA","00",null,null,null,null,"\\\\d{6,11}","(?:0(?:878\\\\d{5}|6698\\\\d{5})|[1589]\\\\d{5,10}|3(?:[12457-9]\\\\d{8}|[36]\\\\d{7,9}))"]',
+ ],
+ 993: '["TM","810","8",null,null,"($NP $FG)","\\\\d{8}","[1-6]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2-$3-$4","12",null],["(\\\\d{2})(\\\\d{6})","$1 $2","6","$NP $FG"],["(\\\\d{3})(\\\\d)(\\\\d{2})(\\\\d{2})","$1 $2-$3-$4","13|[2-5]",null]]]',
+ 888: '["001",null,null,null,null,null,"\\\\d{11}","\\\\d{11}",[["(\\\\d{3})(\\\\d{3})(\\\\d{5})","$1 $2 $3",null,null]]]',
+ 353: '["IE","00","0",null,null,"($NP$FG)","\\\\d{5,10}","[124-9]\\\\d{6,9}",[["(1)(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","1",null],["(\\\\d{2})(\\\\d{5})","$1 $2","2[24-9]|47|58|6[237-9]|9[35-9]",null],["(\\\\d{3})(\\\\d{5})","$1 $2","40[24]|50[45]",null],["(48)(\\\\d{4})(\\\\d{4})","$1 $2 $3","48",null],["(818)(\\\\d{3})(\\\\d{3})","$1 $2 $3","81",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[24-69]|7[14]",null],["([78]\\\\d)(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","76|8[35-9]","$NP$FG"],["(700)(\\\\d{3})(\\\\d{3})","$1 $2 $3","70","$NP$FG"],["(\\\\d{4})(\\\\d{3})(\\\\d{3})","$1 $2 $3","1(?:8[059]|5)","$FG"]]]',
+ 966: '["SA","00","0",null,null,"$NP$FG","\\\\d{7,10}","1\\\\d{7,8}|(?:[2-467]|92)\\\\d{7}|5\\\\d{8}|8\\\\d{9}",[["([1-467])(\\\\d{3})(\\\\d{4})","$1 $2 $3","[1-467]",null],["(1\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1[1-467]",null],["(5\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","5",null],["(92\\\\d{2})(\\\\d{5})","$1 $2","92","$FG"],["(800)(\\\\d{3})(\\\\d{4})","$1 $2 $3","80","$FG"],["(811)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","81",null]]]',
+ 380: '["UA","00","0",null,null,"$NP$FG","\\\\d{5,9}","[3-9]\\\\d{8}",[["([3-9]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","[38]9|4(?:[45][0-5]|87)|5(?:0|6[37]|7[37])|6[36-8]|7|9[1-9]",null],["([3-689]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","3[1-8]2|4[13678]2|5(?:[12457]2|6[24])|6(?:[49]2|[12][29]|5[24])|8[0-8]|90",null],["([3-6]\\\\d{3})(\\\\d{5})","$1 $2","3(?:5[013-9]|[1-46-8])|4(?:[137][013-9]|6|[45][6-9]|8[4-6])|5(?:[1245][013-9]|6[0135-9]|3|7[4-6])|6(?:[49][013-9]|5[0135-9]|[12][13-8])",null]]]',
+ 98: '["IR","00","0",null,null,"$NP$FG","\\\\d{4,10}","[1-8]\\\\d{9}|9(?:[0-4]\\\\d{8}|9\\\\d{2,8})",[["(21)(\\\\d{3,5})","$1 $2","21",null],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1 $2 $3","[1-8]",null],["(\\\\d{3})(\\\\d{3})","$1 $2","9",null],["(\\\\d{3})(\\\\d{2})(\\\\d{2,3})","$1 $2 $3","9",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","9",null]]]',
+ 971: '["AE","00","0",null,null,"$NP$FG","\\\\d{5,12}","[2-79]\\\\d{7,8}|800\\\\d{2,9}",[["([2-4679])(\\\\d{3})(\\\\d{4})","$1 $2 $3","[2-4679][2-8]",null],["(5\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","5",null],["([479]00)(\\\\d)(\\\\d{5})","$1 $2 $3","[479]0","$FG"],["([68]00)(\\\\d{2,9})","$1 $2","60|8","$FG"]]]',
+ 30: '["GR","00",null,null,null,null,"\\\\d{10}","[26-9]\\\\d{9}",[["([27]\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3","21|7",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","2[2-9]1|[689]",null],["(2\\\\d{3})(\\\\d{6})","$1 $2","2[2-9][02-9]",null]]]',
+ 228: '["TG","00",null,null,null,null,"\\\\d{8}","[29]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[29]",null]]]',
+ 48: '["PL","00",null,null,null,null,"\\\\d{6,9}","[12]\\\\d{6,8}|[3-57-9]\\\\d{8}|6\\\\d{5,8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[14]|2[0-57-9]|3[2-4]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145]",null],["(\\\\d{2})(\\\\d{1})(\\\\d{4})","$1 $2 $3","[12]2",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","26|39|5[0137]|6[0469]|7[02389]|8[08]",null],["(\\\\d{3})(\\\\d{2})(\\\\d{2,3})","$1 $2 $3","64",null],["(\\\\d{3})(\\\\d{3})","$1 $2","64",null]]]',
+ 886: '["TW","0(?:0[25679]|19)","0",null,null,"$NP$FG","\\\\d{7,10}","2\\\\d{6,8}|[3-689]\\\\d{7,8}|7\\\\d{7,9}",[["(20)(\\\\d)(\\\\d{4})","$1 $2 $3","202",null],["(20)(\\\\d{3})(\\\\d{4})","$1 $2 $3","20[013-9]",null],["([2-8])(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","2[23-8]|[3-6]|[78][1-9]",null],["([89]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","80|9",null],["(70)(\\\\d{4})(\\\\d{4})","$1 $2 $3","70",null]]]',
+ 212: [
+ '["MA","00","0",null,null,"$NP$FG","\\\\d{9}","[5-9]\\\\d{8}",[["([5-7]\\\\d{2})(\\\\d{6})","$1-$2","5(?:2[015-7]|3[0-4])|[67]",null],["([58]\\\\d{3})(\\\\d{5})","$1-$2","5(?:2[2-489]|3[5-9]|92)|892",null],["(5\\\\d{4})(\\\\d{4})","$1-$2","5(?:29|38)",null],["([5]\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","5(?:4[067]|5[03])",null],["(8[09])(\\\\d{7})","$1-$2","8(?:0|9[013-9])",null]]]',
+ '["EH","00","0",null,null,"$NP$FG","\\\\d{9}","[5-9]\\\\d{8}"]',
+ ],
+ 372: '["EE","00",null,null,null,null,"\\\\d{4,10}","1\\\\d{3,4}|[3-9]\\\\d{6,7}|800\\\\d{6,7}",[["([3-79]\\\\d{2})(\\\\d{4})","$1 $2","[369]|4[3-8]|5(?:[0-2]|5[0-478]|6[45])|7[1-9]",null],["(70)(\\\\d{2})(\\\\d{4})","$1 $2 $3","70",null],["(8000)(\\\\d{3})(\\\\d{3})","$1 $2 $3","800",null],["([458]\\\\d{3})(\\\\d{3,4})","$1 $2","40|5|8(?:00|[1-5])",null]]]',
+ 598: '["UY","0(?:1[3-9]\\\\d|0)","0",null,null,null,"\\\\d{7,8}","[2489]\\\\d{6,7}",[["(\\\\d{4})(\\\\d{4})","$1 $2","[24]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","9[1-9]","$NP$FG"],["(\\\\d{3})(\\\\d{4})","$1 $2","[89]0","$NP$FG"]]]',
+ 502: '["GT","00",null,null,null,null,"\\\\d{8}(?:\\\\d{3})?","[2-7]\\\\d{7}|1[89]\\\\d{9}",[["(\\\\d{4})(\\\\d{4})","$1 $2","[2-7]",null],["(\\\\d{4})(\\\\d{3})(\\\\d{4})","$1 $2 $3","1",null]]]',
+ 82: '["KR","00(?:[124-68]|3\\\\d{2}|7(?:[0-8]\\\\d|9[0-79]))","0","0(8[1-46-8]|85\\\\d{2})?",null,"$NP$FG","\\\\d{3,14}","007\\\\d{9,11}|[1-7]\\\\d{3,9}|8\\\\d{8}",[["(\\\\d{5})(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","00798","$FG","NA"],["(\\\\d{5})(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3 $4","00798","$FG","NA"],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1-$2-$3","1(?:0|1[19]|[69]9|5[458])|[57]0",null],["(\\\\d{2})(\\\\d{3,4})(\\\\d{4})","$1-$2-$3","1(?:[01]|5[1-4]|6[2-8]|[7-9])|[68]0|[3-6][1-9][1-9]",null],["(\\\\d{3})(\\\\d)(\\\\d{4})","$1-$2-$3","131",null],["(\\\\d{3})(\\\\d{2})(\\\\d{4})","$1-$2-$3","131",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1-$2-$3","13[2-9]",null],["(\\\\d{2})(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1-$2-$3-$4","30",null],["(\\\\d)(\\\\d{3,4})(\\\\d{4})","$1-$2-$3","2[1-9]",null],["(\\\\d)(\\\\d{3,4})","$1-$2","21[0-46-9]",null],["(\\\\d{2})(\\\\d{3,4})","$1-$2","[3-6][1-9]1",null],["(\\\\d{4})(\\\\d{4})","$1-$2","1(?:5[246-9]|6[04678]|8[03579])","$FG"]]]',
+ 253: '["DJ","00",null,null,null,null,"\\\\d{8}","[27]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 91: '["IN","00","0",null,null,"$NP$FG","\\\\d{6,13}","008\\\\d{9}|1\\\\d{7,12}|[2-9]\\\\d{9,10}",[["(\\\\d{5})(\\\\d{5})","$1 $2","600|7(?:[02-8]|19|9[037-9])|8(?:0[015-9]|[1-9]|20)|9",null],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1 $2 $3","11|2[02]|33|4[04]|79[1-9]|80[2-46]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","1(?:2[0-249]|3[0-25]|4[145]|[59][14]|7[1257]|[68][1-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|[36][25]|22|4[28]|5[12]|[78]1|9[15])|6(?:12|[2-4]1|5[17]|6[13]|7[14]|80)|7(?:12|2[14]|3[134]|4[47]|5[15]|[67]1|88)|8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91)",null],["(\\\\d{4})(\\\\d{3})(\\\\d{3})","$1 $2 $3","1(?:[23579]|[468][1-9])|[2-8]",null],["(\\\\d{2})(\\\\d{3})(\\\\d{4})(\\\\d{3})","$1 $2 $3 $4","008",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","140","$FG"],["(\\\\d{4})(\\\\d{2})(\\\\d{4})","$1 $2 $3","160","$FG"],["(\\\\d{4})(\\\\d{4,5})","$1 $2","180","$FG"],["(\\\\d{4})(\\\\d{2,4})(\\\\d{4})","$1 $2 $3","180","$FG"],["(\\\\d{4})(\\\\d{3,4})(\\\\d{4})","$1 $2 $3","186","$FG"],["(\\\\d{4})(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3 $4","18[06]","$FG"]]]',
+ 389: '["MK","00","0",null,null,"$NP$FG","\\\\d{6,8}","[2-578]\\\\d{7}",[["(2)(\\\\d{3})(\\\\d{4})","$1 $2 $3","2",null],["([347]\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","[347]",null],["([58]\\\\d{2})(\\\\d)(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[58]",null]]]',
+ 1: [
+ '["US","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2-9]\\\\d{9}",[["(\\\\d{3})(\\\\d{4})","$1-$2",null,null,"NA"],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","($1) $2-$3",null,null,"$1-$2-$3"]]]',
+ '["AI","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2589]\\\\d{9}"]',
+ '["AS","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5689]\\\\d{9}"]',
+ '["BB","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2589]\\\\d{9}"]',
+ '["BM","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[4589]\\\\d{9}"]',
+ '["BS","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2589]\\\\d{9}"]',
+ '["CA","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2-9]\\\\d{9}|3\\\\d{6}"]',
+ '["DM","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[57-9]\\\\d{9}"]',
+ '["DO","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[589]\\\\d{9}"]',
+ '["GD","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[4589]\\\\d{9}"]',
+ '["GU","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5689]\\\\d{9}"]',
+ '["JM","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[589]\\\\d{9}"]',
+ '["KN","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[589]\\\\d{9}"]',
+ '["KY","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[3589]\\\\d{9}"]',
+ '["LC","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5789]\\\\d{9}"]',
+ '["MP","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5689]\\\\d{9}"]',
+ '["MS","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5689]\\\\d{9}"]',
+ '["PR","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5789]\\\\d{9}"]',
+ '["SX","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5789]\\\\d{9}"]',
+ '["TC","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5689]\\\\d{9}"]',
+ '["TT","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[589]\\\\d{9}"]',
+ '["AG","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2589]\\\\d{9}"]',
+ '["VC","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[5789]\\\\d{9}"]',
+ '["VG","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[2589]\\\\d{9}"]',
+ '["VI","011","1",null,null,null,"\\\\d{7}(?:\\\\d{3})?","[3589]\\\\d{9}"]',
+ ],
+ 60: '["MY","00","0",null,null,null,"\\\\d{6,10}","[13-9]\\\\d{7,9}",[["([4-79])(\\\\d{3})(\\\\d{4})","$1-$2 $3","[4-79]","$NP$FG"],["(3)(\\\\d{4})(\\\\d{4})","$1-$2 $3","3","$NP$FG"],["([18]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1-$2 $3","1[02-46-9][1-9]|8","$NP$FG"],["(1)([36-8]00)(\\\\d{2})(\\\\d{4})","$1-$2-$3-$4","1[36-8]0",null],["(11)(\\\\d{4})(\\\\d{4})","$1-$2 $3","11","$NP$FG"],["(15[49])(\\\\d{3})(\\\\d{4})","$1-$2 $3","15","$NP$FG"]]]',
+ 355: '["AL","00","0",null,null,"$NP$FG","\\\\d{5,9}","[2-57]\\\\d{7}|6\\\\d{8}|8\\\\d{5,7}|9\\\\d{5}",[["(4)(\\\\d{3})(\\\\d{4})","$1 $2 $3","4[0-6]",null],["(6\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","6",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[2358][2-5]|4[7-9]",null],["(\\\\d{3})(\\\\d{3,5})","$1 $2","[235][16-9]|8[016-9]|[79]",null]]]',
+ 254: '["KE","000","0","005|0",null,"$NP$FG","\\\\d{7,10}","20\\\\d{6,7}|[4-9]\\\\d{6,9}",[["(\\\\d{2})(\\\\d{5,7})","$1 $2","[24-6]",null],["(\\\\d{3})(\\\\d{6})","$1 $2","7",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[89]",null]]]',
+ 223: '["ML","00",null,null,null,null,"\\\\d{8}","[246-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[246-9]",null],["(\\\\d{4})","$1","67|74",null,"NA"]]]',
+ 686: '["KI","00",null,"0",null,null,"\\\\d{5,8}","[2458]\\\\d{4}|3\\\\d{4,7}|7\\\\d{7}"]',
+ 994: '["AZ","00","0",null,null,"($NP$FG)","\\\\d{7,9}","[1-9]\\\\d{8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","(?:1[28]|2(?:[45]2|[0-36])|365)",null],["(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[4-8]","$NP$FG"],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","9","$NP$FG"]]]',
+ 979: '["001",null,null,null,null,null,"\\\\d{9}","\\\\d{9}",[["(\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3",null,null]]]',
+ 66: '["TH","00","0",null,null,"$NP$FG","\\\\d{4}|\\\\d{8,10}","[2-9]\\\\d{7,8}|1\\\\d{3}(?:\\\\d{5,6})?",[["(2)(\\\\d{3})(\\\\d{4})","$1 $2 $3","2",null],["([13-9]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","14|[3-9]",null],["(1[89]00)(\\\\d{3})(\\\\d{3})","$1 $2 $3","1","$FG"]]]',
+ 233: '["GH","00","0",null,null,"$NP$FG","\\\\d{7,9}","[235]\\\\d{8}|8\\\\d{7}",[["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[235]",null],["(\\\\d{3})(\\\\d{5})","$1 $2","8",null]]]',
+ 593: '["EC","00","0",null,null,"($NP$FG)","\\\\d{7,11}","1\\\\d{9,10}|[2-8]\\\\d{7}|9\\\\d{8}",[["(\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2-$3","[247]|[356][2-8]",null,"$1-$2-$3"],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","9","$NP$FG"],["(1800)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","1","$FG"]]]',
+ 509: '["HT","00",null,null,null,null,"\\\\d{8}","[2-489]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{4})","$1 $2 $3",null,null]]]',
+ 54: '["AR","00","0","0?(?:(11|2(?:2(?:02?|[13]|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:02?|1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[67])|4(?:7[3-578]|9)|6(?:[0136]|2[24-6]|4[6-8]?|5[15-8])|80|9(?:0[1-3]|[19]|2\\\\d|3[1-6]|4[02568]?|5[2-4]|6[2-46]|72?|8[23]?))|3(?:3(?:2[79]|6|8[2578])|4(?:0[0-24-9]|[12]|3[5-8]?|4[24-7]|5[4-68]?|6[02-9]|7[126]|8[2379]?|9[1-36-8])|5(?:1|2[1245]|3[237]?|4[1-46-9]|6[2-4]|7[1-6]|8[2-5]?)|6[24]|7(?:[069]|1[1568]|2[15]|3[145]|4[13]|5[14-8]|7[2-57]|8[126])|8(?:[01]|2[15-7]|3[2578]?|4[13-6]|5[4-8]?|6[1-357-9]|7[36-8]?|8[5-8]?|9[124])))?15)?","9$1","$NP$FG","\\\\d{6,11}","11\\\\d{8}|[2368]\\\\d{9}|9\\\\d{10}",[["([68]\\\\d{2})(\\\\d{3})(\\\\d{4})","$1-$2-$3","[68]",null],["(\\\\d{2})(\\\\d{4})","$1-$2","[2-9]","$FG","NA"],["(\\\\d{3})(\\\\d{4})","$1-$2","[2-9]","$FG","NA"],["(\\\\d{4})(\\\\d{4})","$1-$2","[2-9]","$FG","NA"],["(9)(11)(\\\\d{4})(\\\\d{4})","$2 15-$3-$4","911",null,"$1 $2 $3-$4"],["(9)(\\\\d{3})(\\\\d{3})(\\\\d{4})","$2 15-$3-$4","9(?:2[234689]|3[3-8])",null,"$1 $2 $3-$4"],["(9)(\\\\d{4})(\\\\d{2})(\\\\d{4})","$2 15-$3-$4","9[23]",null,"$1 $2 $3-$4"],["(11)(\\\\d{4})(\\\\d{4})","$1 $2-$3","1",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2-$3","2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[1-358]|5[138]|6[24]|7[069]|8[013578])",null],["(\\\\d{4})(\\\\d{2})(\\\\d{4})","$1 $2-$3","[23]",null],["(\\\\d{3})","$1","1[012]|911","$FG","NA"]]]',
+ 57: '["CO","00(?:4(?:[14]4|56)|[579])","0","0([3579]|4(?:44|56))?",null,null,"\\\\d{7,11}","(?:[13]\\\\d{0,3}|[24-8])\\\\d{7}",[["(\\\\d)(\\\\d{7})","$1 $2","1(?:8[2-9]|9[0-3]|[2-7])|[24-8]","($FG)"],["(\\\\d{3})(\\\\d{7})","$1 $2","3",null],["(1)(\\\\d{3})(\\\\d{7})","$1-$2-$3","1(?:80|9[04])","$NP$FG","$1 $2 $3"]]]',
+ 597: '["SR","00",null,null,null,null,"\\\\d{6,7}","[2-8]\\\\d{5,6}",[["(\\\\d{3})(\\\\d{3})","$1-$2","[2-4]|5[2-58]",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1-$2-$3","56",null],["(\\\\d{3})(\\\\d{4})","$1-$2","[6-8]",null]]]',
+ 676: '["TO","00",null,null,null,null,"\\\\d{5,7}","[02-8]\\\\d{4,6}",[["(\\\\d{2})(\\\\d{3})","$1-$2","[1-6]|7[0-4]|8[05]",null],["(\\\\d{3})(\\\\d{4})","$1 $2","7[5-9]|8[47-9]",null],["(\\\\d{4})(\\\\d{3})","$1 $2","0",null]]]',
+ 505: '["NI","00",null,null,null,null,"\\\\d{8}","[12578]\\\\d{7}",[["(\\\\d{4})(\\\\d{4})","$1 $2",null,null]]]',
+ 850: '["KP","00|99","0",null,null,"$NP$FG","\\\\d{6,8}|\\\\d{10}","1\\\\d{9}|[28]\\\\d{7}",[["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","1",null],["(\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","2",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","8",null]]]',
+ 7: [
+ '["RU","810","8",null,null,"$NP ($FG)","\\\\d{10}","[3489]\\\\d{9}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1-$2-$3","[1-79]","$FG","NA"],["([3489]\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2-$3-$4","[34689]",null],["(7\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","7",null]]]',
+ '["KZ","810","8",null,null,null,"\\\\d{10}","(?:33\\\\d|7\\\\d{2}|80[09])\\\\d{7}"]',
+ ],
+ 268: '["SZ","00",null,null,null,null,"\\\\d{8}","[027]\\\\d{7}",[["(\\\\d{4})(\\\\d{4})","$1 $2","[027]",null]]]',
+ 501: '["BZ","00",null,null,null,null,"\\\\d{7}(?:\\\\d{4})?","[2-8]\\\\d{6}|0\\\\d{10}",[["(\\\\d{3})(\\\\d{4})","$1-$2","[2-8]",null],["(0)(800)(\\\\d{4})(\\\\d{3})","$1-$2-$3-$4","0",null]]]',
+ 252: '["SO","00","0",null,null,null,"\\\\d{6,9}","[1-9]\\\\d{5,8}",[["(\\\\d{6})","$1","[134]",null],["(\\\\d)(\\\\d{6})","$1 $2","2[0-79]|[13-5]",null],["(\\\\d)(\\\\d{7})","$1 $2","24|[67]",null],["(\\\\d{2})(\\\\d{4})","$1 $2","8[125]",null],["(\\\\d{2})(\\\\d{5,7})","$1 $2","15|28|6[1-35-9]|799|9[2-9]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","3[59]|4[89]|6[24-6]|79|8[08]|90",null]]]',
+ 229: '["BJ","00",null,null,null,null,"\\\\d{4,8}","[2689]\\\\d{7}|7\\\\d{3}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 680: '["PW","01[12]",null,null,null,null,"\\\\d{7}","[2-8]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 263: '["ZW","00","0",null,null,"$NP$FG","\\\\d{3,10}","2(?:[012457-9]\\\\d{3,8}|6(?:[14]\\\\d{7}|\\\\d{4}))|[13-79]\\\\d{4,9}|8[06]\\\\d{8}",[["([49])(\\\\d{3})(\\\\d{2,4})","$1 $2 $3","4|9[2-9]",null],["(7\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","7",null],["(86\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","86[24]",null],["([2356]\\\\d{2})(\\\\d{3,5})","$1 $2","2(?:0[45]|2[278]|[49]8|[78])|3(?:08|17|3[78]|7[1569]|8[37]|98)|5[15][78]|6(?:[29]8|[38]7|6[78]|75|[89]8)",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","2(?:1[39]|2[0157]|6[14]|7[35]|84)|329",null],["([1-356]\\\\d)(\\\\d{3,5})","$1 $2","1[3-9]|2[0569]|3[0-69]|5[05689]|6[0-46-9]",null],["([235]\\\\d)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[23]9|54",null],["([25]\\\\d{3})(\\\\d{3,5})","$1 $2","(?:25|54)8",null],["(8\\\\d{3})(\\\\d{6})","$1 $2","86",null],["(80\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","80",null]]]',
+ 90: '["TR","00","0",null,null,null,"\\\\d{7,10}","[2-589]\\\\d{9}|444\\\\d{4}",[["(\\\\d{3})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[23]|4(?:[0-35-9]|4[0-35-9])","($NP$FG)"],["(\\\\d{3})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","5[02-69]","$NP$FG"],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","51|[89]","$NP$FG"],["(444)(\\\\d{1})(\\\\d{3})","$1 $2 $3","444",null]]]',
+ 352: '["LU","00",null,"(15(?:0[06]|1[12]|35|4[04]|55|6[26]|77|88|99)\\\\d)",null,null,"\\\\d{4,11}","[24-9]\\\\d{3,10}|3(?:[0-46-9]\\\\d{2,9}|5[013-9]\\\\d{1,8})",[["(\\\\d{2})(\\\\d{3})","$1 $2","[2-5]|7[1-9]|[89](?:[1-9]|0[2-9])",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3","[2-5]|7[1-9]|[89](?:[1-9]|0[2-9])",null],["(\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3","20",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{1,2})","$1 $2 $3 $4","2(?:[0367]|4[3-8])",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3 $4","20",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{1,2})","$1 $2 $3 $4 $5","2(?:[0367]|4[3-8])",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{1,4})","$1 $2 $3 $4","2(?:[12589]|4[12])|[3-5]|7[1-9]|8(?:[1-9]|0[2-9])|9(?:[1-9]|0[2-46-9])",null],["(\\\\d{3})(\\\\d{2})(\\\\d{3})","$1 $2 $3","70|80[01]|90[015]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","6",null]]]',
+ 47: [
+ '["NO","00",null,null,null,null,"\\\\d{5}(?:\\\\d{3})?","0\\\\d{4}|[2-9]\\\\d{7}",[["([489]\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3","[489]",null],["([235-7]\\\\d)(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[235-7]",null]]]',
+ '["SJ","00",null,null,null,null,"\\\\d{5}(?:\\\\d{3})?","0\\\\d{4}|[45789]\\\\d{7}"]',
+ ],
+ 243: '["CD","00","0",null,null,"$NP$FG","\\\\d{7,9}","[2-6]\\\\d{6}|[18]\\\\d{6,8}|9\\\\d{8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","12",null],["([89]\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","8[0-2459]|9",null],["(\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3","88",null],["(\\\\d{2})(\\\\d{5})","$1 $2","[1-6]",null]]]',
+ 220: '["GM","00",null,null,null,null,"\\\\d{7}","[2-9]\\\\d{6}",[["(\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 687: '["NC","00",null,null,null,null,"\\\\d{6}","[2-57-9]\\\\d{5}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1.$2.$3","[2-46-9]|5[0-4]",null]]]',
+ 995: '["GE","00","0",null,null,null,"\\\\d{6,9}","[34578]\\\\d{8}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[348]","$NP$FG"],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","7","$NP$FG"],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","5","$FG"]]]',
+ 961: '["LB","00","0",null,null,null,"\\\\d{7,8}","[13-9]\\\\d{6,7}",[["(\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","[13-6]|7(?:[2-57]|62|8[0-7]|9[04-9])|8[02-9]|9","$NP$FG"],["([7-9]\\\\d)(\\\\d{3})(\\\\d{3})","$1 $2 $3","[89][01]|7(?:[01]|6[013-9]|8[89]|9[1-3])",null]]]',
+ 40: '["RO","00","0",null,null,"$NP$FG","\\\\d{6,9}","[23]\\\\d{5,8}|[7-9]\\\\d{8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[23]1",null],["(\\\\d{2})(\\\\d{4})","$1 $2","[23]1",null],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[23][3-7]|[7-9]",null],["(2\\\\d{2})(\\\\d{3})","$1 $2","2[3-6]",null]]]',
+ 232: '["SL","00","0",null,null,"($NP$FG)","\\\\d{6,8}","[2-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{6})","$1 $2",null,null]]]',
+ 594: '["GF","00","0",null,null,"$NP$FG","\\\\d{9}","[56]\\\\d{8}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 976: '["MN","001","0",null,null,"$NP$FG","\\\\d{6,10}","[12]\\\\d{7,9}|[57-9]\\\\d{7}",[["([12]\\\\d)(\\\\d{2})(\\\\d{4})","$1 $2 $3","[12]1",null],["([12]2\\\\d)(\\\\d{5,6})","$1 $2","[12]2[1-3]",null],["([12]\\\\d{3})(\\\\d{5})","$1 $2","[12](?:27|[3-5])",null],["(\\\\d{4})(\\\\d{4})","$1 $2","[57-9]","$FG"],["([12]\\\\d{4})(\\\\d{4,5})","$1 $2","[12](?:27|[3-5])",null]]]',
+ 20: '["EG","00","0",null,null,"$NP$FG","\\\\d{5,10}","1\\\\d{4,9}|[2456]\\\\d{8}|3\\\\d{7}|[89]\\\\d{8,9}",[["(\\\\d)(\\\\d{7,8})","$1 $2","[23]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","1[012]|[89]00",null],["(\\\\d{2})(\\\\d{6,7})","$1 $2","1[35]|[4-6]|[89][2-9]",null]]]',
+ 689: '["PF","00",null,null,null,null,"\\\\d{6}(?:\\\\d{2})?","4\\\\d{5,7}|8\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","4[09]|8[79]",null],["(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3","44",null]]]',
+ 56: '["CL","(?:0|1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))0","0","0|(1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))",null,"$NP$FG","\\\\d{7,11}","(?:[2-9]|600|123)\\\\d{7,8}",[["(\\\\d)(\\\\d{4})(\\\\d{4})","$1 $2 $3","2[23]","($FG)"],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[357]|4[1-35]|6[13-57]","($FG)"],["(9)(\\\\d{4})(\\\\d{4})","$1 $2 $3","9",null],["(44)(\\\\d{3})(\\\\d{4})","$1 $2 $3","44",null],["([68]00)(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","60|8","$FG"],["(600)(\\\\d{3})(\\\\d{2})(\\\\d{3})","$1 $2 $3 $4","60","$FG"],["(1230)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1","$FG"],["(\\\\d{5})(\\\\d{4})","$1 $2","219","($FG)"],["(\\\\d{4,5})","$1","[1-9]","$FG","NA"]]]',
+ 596: '["MQ","00","0",null,null,"$NP$FG","\\\\d{9}","[56]\\\\d{8}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 508: '["PM","00","0",null,null,"$NP$FG","\\\\d{6}","[45]\\\\d{5}",[["([45]\\\\d)(\\\\d{2})(\\\\d{2})","$1 $2 $3",null,null]]]',
+ 269: '["KM","00",null,null,null,null,"\\\\d{7}","[3478]\\\\d{6}",[["(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3",null,null]]]',
+ 358: [
+ '["FI","00|99(?:[02469]|5(?:11|33|5[59]|88|9[09]))","0",null,null,"$NP$FG","\\\\d{5,12}","1\\\\d{4,11}|[2-9]\\\\d{4,10}",[["(\\\\d{3})(\\\\d{3,7})","$1 $2","(?:[1-3]00|[6-8]0)",null],["(116\\\\d{3})","$1","116","$FG"],["(\\\\d{2})(\\\\d{4,10})","$1 $2","[14]|2[09]|50|7[135]",null],["(\\\\d)(\\\\d{4,11})","$1 $2","[25689][1-8]|3",null]]]',
+ '["AX","00|99(?:[02469]|5(?:11|33|5[59]|88|9[09]))","0",null,null,"$NP$FG","\\\\d{5,12}","1\\\\d{5,11}|[35]\\\\d{5,9}|[27]\\\\d{4,9}|4\\\\d{5,10}|6\\\\d{7,9}|8\\\\d{6,9}"]',
+ ],
+ 251: '["ET","00","0",null,null,"$NP$FG","\\\\d{7,9}","[1-59]\\\\d{8}",[["([1-59]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3",null,null]]]',
+ 681: '["WF","00",null,null,null,null,"\\\\d{6}","[4-8]\\\\d{5}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3",null,null]]]',
+ 853: '["MO","00",null,null,null,null,"\\\\d{8}","[268]\\\\d{7}",[["([268]\\\\d{3})(\\\\d{4})","$1 $2",null,null]]]',
+ 44: [
+ '["GB","00","0",null,null,"$NP$FG","\\\\d{4,10}","\\\\d{7,10}",[["(7\\\\d{3})(\\\\d{6})","$1 $2","7(?:[1-5789]|62)",null],["(\\\\d{2})(\\\\d{4})(\\\\d{4})","$1 $2 $3","2|5[56]|7[06]",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","1(?:1|\\\\d1)|3|9[018]",null],["(\\\\d{5})(\\\\d{4,5})","$1 $2","1(?:38|5[23]|69|76|94)",null],["(1\\\\d{3})(\\\\d{5,6})","$1 $2","1",null],["(800)(\\\\d{4})","$1 $2","800",null],["(845)(46)(4\\\\d)","$1 $2 $3","845",null],["(8\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","8(?:4[2-5]|7[0-3])",null],["(80\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","80",null],["([58]00)(\\\\d{6})","$1 $2","[58]00",null]]]',
+ '["GG","00","0",null,null,"$NP$FG","\\\\d{6,10}","[135789]\\\\d{6,9}"]',
+ '["IM","00","0",null,null,"$NP$FG","\\\\d{6,10}","[135789]\\\\d{6,9}"]',
+ '["JE","00","0",null,null,"$NP$FG","\\\\d{6,10}","[135789]\\\\d{6,9}"]',
+ ],
+ 244: '["AO","00",null,null,null,null,"\\\\d{9}","[29]\\\\d{8}",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3",null,null]]]',
+ 211: '["SS","00","0",null,null,null,"\\\\d{9}","[19]\\\\d{8}",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3",null,"$NP$FG"]]]',
+ 373: '["MD","00","0",null,null,"$NP$FG","\\\\d{8}","[235-9]\\\\d{7}",[["(\\\\d{2})(\\\\d{3})(\\\\d{3})","$1 $2 $3","22|3",null],["([25-7]\\\\d{2})(\\\\d{2})(\\\\d{3})","$1 $2 $3","2[13-9]|[5-7]",null],["([89]\\\\d{2})(\\\\d{5})","$1 $2","[89]",null]]]',
+ 996: '["KG","00","0",null,null,"$NP$FG","\\\\d{5,10}","[235-8]\\\\d{8,9}",[["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[25-7]|31[25]",null],["(\\\\d{4})(\\\\d{5})","$1 $2","3(?:1[36]|[2-9])",null],["(\\\\d{3})(\\\\d{3})(\\\\d)(\\\\d{3})","$1 $2 $3 $4","8",null]]]',
+ 93: '["AF","00","0",null,null,"$NP$FG","\\\\d{7,9}","[2-7]\\\\d{8}",[["([2-7]\\\\d)(\\\\d{3})(\\\\d{4})","$1 $2 $3","[2-7]",null]]]',
+ 260: '["ZM","00","0",null,null,"$NP$FG","\\\\d{9}","[289]\\\\d{8}",[["([29]\\\\d)(\\\\d{7})","$1 $2","[29]",null],["(800)(\\\\d{3})(\\\\d{3})","$1 $2 $3","8",null]]]',
+ 378: '["SM","00",null,"(?:0549)?([89]\\\\d{5})","0549$1",null,"\\\\d{6,10}","[05-7]\\\\d{7,9}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[5-7]",null],["(0549)(\\\\d{6})","$1 $2","0",null,"($1) $2"],["(\\\\d{6})","0549 $1","[89]",null,"(0549) $1"]]]',
+ 235: '["TD","00|16",null,null,null,null,"\\\\d{8}","[2679]\\\\d{7}",[["(\\\\d{2})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4",null,null]]]',
+ 960: '["MV","0(?:0|19)",null,null,null,null,"\\\\d{7,10}","[346-8]\\\\d{6,9}|9(?:00\\\\d{7}|\\\\d{6})",[["(\\\\d{3})(\\\\d{4})","$1-$2","[3467]|9(?:[1-9]|0[1-9])",null],["(\\\\d{3})(\\\\d{3})(\\\\d{4})","$1 $2 $3","[89]00",null]]]',
+ 221: '["SN","00",null,null,null,null,"\\\\d{9}","[3789]\\\\d{8}",[["(\\\\d{2})(\\\\d{3})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","[379]",null],["(\\\\d{3})(\\\\d{2})(\\\\d{2})(\\\\d{2})","$1 $2 $3 $4","8",null]]]',
+ 595: '["PY","00","0",null,null,null,"\\\\d{5,9}","5[0-5]\\\\d{4,7}|[2-46-9]\\\\d{5,8}",[["(\\\\d{2})(\\\\d{5})","$1 $2","(?:[26]1|3[289]|4[124678]|7[123]|8[1236])","($NP$FG)"],["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","(?:[26]1|3[289]|4[124678]|7[123]|8[1236])","($NP$FG)"],["(\\\\d{3})(\\\\d{3,6})","$1 $2","[2-9]0","$NP$FG"],["(\\\\d{3})(\\\\d{6})","$1 $2","9[1-9]","$NP$FG"],["(\\\\d{2})(\\\\d{3})(\\\\d{4})","$1 $2 $3","8700",null],["(\\\\d{3})(\\\\d{4,5})","$1 $2","[2-8][1-9]","($NP$FG)"],["(\\\\d{3})(\\\\d{3})(\\\\d{3})","$1 $2 $3","[2-8][1-9]","$NP$FG"]]]',
+ 977: '["NP","00","0",null,null,"$NP$FG","\\\\d{6,10}","[1-8]\\\\d{7}|9(?:[1-69]\\\\d{6,8}|7[2-6]\\\\d{5,7}|8\\\\d{8})",[["(1)(\\\\d{7})","$1-$2","1[2-6]",null],["(\\\\d{2})(\\\\d{6})","$1-$2","1[01]|[2-8]|9(?:[1-69]|7[15-9])",null],["(9\\\\d{2})(\\\\d{7})","$1-$2","9(?:6[013]|7[245]|8)","$FG"]]]',
+ 36: '["HU","00","06",null,null,"($FG)","\\\\d{6,9}","[1-9]\\\\d{7,8}",[["(1)(\\\\d{3})(\\\\d{4})","$1 $2 $3","1",null],["(\\\\d{2})(\\\\d{3})(\\\\d{3,4})","$1 $2 $3","[2-9]",null]]]',
+};
diff --git a/toolkit/components/formautofill/shared/PhoneNumberNormalizer.sys.mjs b/toolkit/components/formautofill/shared/PhoneNumberNormalizer.sys.mjs
new file mode 100644
index 0000000000..604eefe314
--- /dev/null
+++ b/toolkit/components/formautofill/shared/PhoneNumberNormalizer.sys.mjs
@@ -0,0 +1,67 @@
+/* This Source Code Form is subject to the terms of the Apache License, Version
+ * 2.0. If a copy of the Apache License was not distributed with this file, You
+ * can obtain one at https://www.apache.org/licenses/LICENSE-2.0 */
+
+// This library came from https://github.com/andreasgal/PhoneNumber.js but will
+// be further maintained by our own in Form Autofill codebase.
+
+export var PhoneNumberNormalizer = (function () {
+ const UNICODE_DIGITS = /[\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9]/g;
+ const VALID_ALPHA_PATTERN = /[a-zA-Z]/g;
+ const LEADING_PLUS_CHARS_PATTERN = /^[+\uFF0B]+/g;
+ const NON_DIALABLE_CHARS = /[^,#+\*\d]/g;
+
+ // Map letters to numbers according to the ITU E.161 standard
+ let E161 = {
+ a: 2,
+ b: 2,
+ c: 2,
+ d: 3,
+ e: 3,
+ f: 3,
+ g: 4,
+ h: 4,
+ i: 4,
+ j: 5,
+ k: 5,
+ l: 5,
+ m: 6,
+ n: 6,
+ o: 6,
+ p: 7,
+ q: 7,
+ r: 7,
+ s: 7,
+ t: 8,
+ u: 8,
+ v: 8,
+ w: 9,
+ x: 9,
+ y: 9,
+ z: 9,
+ };
+
+ // Normalize a number by converting unicode numbers and symbols to their
+ // ASCII equivalents and removing all non-dialable characters.
+ function NormalizeNumber(number, numbersOnly) {
+ if (typeof number !== "string") {
+ return "";
+ }
+
+ number = number.replace(UNICODE_DIGITS, function (ch) {
+ return String.fromCharCode(48 + (ch.charCodeAt(0) & 0xf));
+ });
+ if (!numbersOnly) {
+ number = number.replace(VALID_ALPHA_PATTERN, function (ch) {
+ return String(E161[ch.toLowerCase()] || 0);
+ });
+ }
+ number = number.replace(LEADING_PLUS_CHARS_PATTERN, "+");
+ number = number.replace(NON_DIALABLE_CHARS, "");
+ return number;
+ }
+
+ return {
+ Normalize: NormalizeNumber,
+ };
+})();