diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
commit | 40a355a42d4a9444dc753c04c6608dade2f06a23 (patch) | |
tree | 871fc667d2de662f171103ce5ec067014ef85e61 /toolkit/components/formautofill/shared | |
parent | Adding upstream version 124.0.1. (diff) | |
download | firefox-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')
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, + }; +})(); |