text: /**
   * @license
   * Copyright (C) 2010 The Libphonenumber Authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  /**
   * @fileoverview  Utility for international phone numbers.
   * Functionality includes formatting, parsing and validation.
   * (based on the java implementation).
   *
   * NOTE: A lot of methods in this class require Region Code strings. These must
   * be provided using ISO 3166-1 two-letter country-code format. These should be
   * in upper-case (but for compatibility lower-case is also allowed). The list of
   * the codes can be found here:
   * http://www.iso.org/iso/english_country_names_and_code_elements
   *
   * Credits to Nikolaos Trogkanis for original implementation.
   */
  
  goog.provide('i18n.phonenumbers.Error');
  goog.provide('i18n.phonenumbers.PhoneNumberFormat');
  goog.provide('i18n.phonenumbers.PhoneNumberType');
  goog.provide('i18n.phonenumbers.PhoneNumberUtil');
  goog.provide('i18n.phonenumbers.PhoneNumberUtil.MatchType');
  goog.provide('i18n.phonenumbers.PhoneNumberUtil.ValidationResult');
  
  goog.require('goog.array');
  goog.require('goog.proto2.PbLiteSerializer');
  goog.require('goog.string');
  goog.require('goog.string.StringBuffer');
  goog.require('i18n.phonenumbers.NumberFormat');
  goog.require('i18n.phonenumbers.PhoneMetadata');
  goog.require('i18n.phonenumbers.PhoneNumber');
  goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource');
  goog.require('i18n.phonenumbers.PhoneNumberDesc');
  goog.require('i18n.phonenumbers.metadata');
  
  
  
  /**
   * @constructor
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil = function() {
    /**
     * A mapping from a region code to the PhoneMetadata for that region.
     * @type {Object.<string, i18n.phonenumbers.PhoneMetadata>}
     */
    this.regionToMetadataMap = {};
  };
  goog.addSingletonGetter(i18n.phonenumbers.PhoneNumberUtil);
  
  
  /**
   * Errors encountered when parsing phone numbers.
   *
   * @enum {string}
   */
  i18n.phonenumbers.Error = {
    INVALID_COUNTRY_CODE: 'Invalid country calling code',
    // This generally indicates the string passed in had less than 3 digits in it.
    // More specifically, the number failed to match the regular expression
    // VALID_PHONE_NUMBER.
    NOT_A_NUMBER: 'The string supplied did not seem to be a phone number',
    // This indicates the string started with an international dialing prefix, but
    // after this was stripped from the number, had less digits than any valid
    // phone number (including country calling code) could have.
    TOO_SHORT_AFTER_IDD: 'Phone number too short after IDD',
    // This indicates the string, after any country calling code has been
    // stripped, had less digits than any valid phone number could have.
    TOO_SHORT_NSN: 'The string supplied is too short to be a phone number',
    // This indicates the string had more digits than any valid phone number could
    // have.
    TOO_LONG: 'The string supplied is too long to be a phone number'
  };
  
  
  /**
   * @const
   * @type {number}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_ = 1;
  
  
  /**
   * The minimum length of the national significant number.
   *
   * @const
   * @type {number}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ = 2;
  
  
  /**
   * The ITU says the maximum length should be 15, but we have found longer
   * numbers in Germany.
   *
   * @const
   * @type {number}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ = 17;
  
  
  /**
   * The maximum length of the country calling code.
   *
   * @const
   * @type {number}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ = 3;
  
  
  /**
   * We don't allow input strings for parsing to be longer than 250 chars. This
   * prevents malicious input from consuming CPU.
   *
   * @const
   * @type {number}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_ = 250;
  
  
  /**
   * Region-code for the unknown region.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ = 'ZZ';
  
  
  /**
   * The prefix that needs to be inserted in front of a Colombian landline number
   * when dialed from a mobile phone in Colombia.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_ = '3';
  
  
  /**
   * Map of country calling codes that use a mobile token before the area code.
   * One example of when this is relevant is when determining the length of the
   * national destination code, which should be the length of the area code plus
   * the length of the mobile token.
   *
   * @const
   * @type {!Object.<number, string>}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_ = {
    52: '1',
    54: '9'
  };
  
  
  /**
   * Set of country calling codes that have geographically assigned mobile
   * numbers. This may not be complete; we add calling codes case by case, as we
   * find geographical mobile numbers or hear from user reports.
   *
   * @const
   * @type {!Array.<number>}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_ = [
    52,  // Mexico
    54,  // Argentina
    55  // Brazil
  ];
  
  
  /**
   * The PLUS_SIGN signifies the international prefix.
   *
   * @const
   * @type {string}
   */
  i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN = '+';
  
  
  /**
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ = '*';
  
  
  /**
   * The RFC 3966 format for extensions.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ = ';ext=';
  
  
  /**
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ = 'tel:';
  
  
  /**
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_ = ';phone-context=';
  
  
  /**
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_ = ';isub=';
  
  
  /**
   * These mappings map a character (key) to a specific digit that should replace
   * it for normalization purposes. Non-European digits that may be used in phone
   * numbers are mapped to a European equivalent.
   *
   * @const
   * @type {!Object.<string, string>}
   */
  i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS = {
    '0': '0',
    '1': '1',
    '2': '2',
    '3': '3',
    '4': '4',
    '5': '5',
    '6': '6',
    '7': '7',
    '8': '8',
    '9': '9',
    '\uFF10': '0', // Fullwidth digit 0
    '\uFF11': '1', // Fullwidth digit 1
    '\uFF12': '2', // Fullwidth digit 2
    '\uFF13': '3', // Fullwidth digit 3
    '\uFF14': '4', // Fullwidth digit 4
    '\uFF15': '5', // Fullwidth digit 5
    '\uFF16': '6', // Fullwidth digit 6
    '\uFF17': '7', // Fullwidth digit 7
    '\uFF18': '8', // Fullwidth digit 8
    '\uFF19': '9', // Fullwidth digit 9
    '\u0660': '0', // Arabic-indic digit 0
    '\u0661': '1', // Arabic-indic digit 1
    '\u0662': '2', // Arabic-indic digit 2
    '\u0663': '3', // Arabic-indic digit 3
    '\u0664': '4', // Arabic-indic digit 4
    '\u0665': '5', // Arabic-indic digit 5
    '\u0666': '6', // Arabic-indic digit 6
    '\u0667': '7', // Arabic-indic digit 7
    '\u0668': '8', // Arabic-indic digit 8
    '\u0669': '9', // Arabic-indic digit 9
    '\u06F0': '0', // Eastern-Arabic digit 0
    '\u06F1': '1', // Eastern-Arabic digit 1
    '\u06F2': '2', // Eastern-Arabic digit 2
    '\u06F3': '3', // Eastern-Arabic digit 3
    '\u06F4': '4', // Eastern-Arabic digit 4
    '\u06F5': '5', // Eastern-Arabic digit 5
    '\u06F6': '6', // Eastern-Arabic digit 6
    '\u06F7': '7', // Eastern-Arabic digit 7
    '\u06F8': '8', // Eastern-Arabic digit 8
    '\u06F9': '9'  // Eastern-Arabic digit 9
  };
  
  
  /**
   * A map that contains characters that are essential when dialling. That means
   * any of the characters in this map must not be removed from a number when
   * dialling, otherwise the call will not reach the intended destination.
   *
   * @const
   * @type {!Object.<string, string>}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_ = {
    '0': '0',
    '1': '1',
    '2': '2',
    '3': '3',
    '4': '4',
    '5': '5',
    '6': '6',
    '7': '7',
    '8': '8',
    '9': '9',
    '+': i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN,
    '*': '*'
  };
  
  
  /**
   * Only upper-case variants of alpha characters are stored.
   *
   * @const
   * @type {!Object.<string, string>}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.ALPHA_MAPPINGS_ = {
    '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'
  };
  
  
  /**
   * For performance reasons, amalgamate both into one map.
   *
   * @const
   * @type {!Object.<string, string>}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_ = {
    '0': '0',
    '1': '1',
    '2': '2',
    '3': '3',
    '4': '4',
    '5': '5',
    '6': '6',
    '7': '7',
    '8': '8',
    '9': '9',
    '\uFF10': '0', // Fullwidth digit 0
    '\uFF11': '1', // Fullwidth digit 1
    '\uFF12': '2', // Fullwidth digit 2
    '\uFF13': '3', // Fullwidth digit 3
    '\uFF14': '4', // Fullwidth digit 4
    '\uFF15': '5', // Fullwidth digit 5
    '\uFF16': '6', // Fullwidth digit 6
    '\uFF17': '7', // Fullwidth digit 7
    '\uFF18': '8', // Fullwidth digit 8
    '\uFF19': '9', // Fullwidth digit 9
    '\u0660': '0', // Arabic-indic digit 0
    '\u0661': '1', // Arabic-indic digit 1
    '\u0662': '2', // Arabic-indic digit 2
    '\u0663': '3', // Arabic-indic digit 3
    '\u0664': '4', // Arabic-indic digit 4
    '\u0665': '5', // Arabic-indic digit 5
    '\u0666': '6', // Arabic-indic digit 6
    '\u0667': '7', // Arabic-indic digit 7
    '\u0668': '8', // Arabic-indic digit 8
    '\u0669': '9', // Arabic-indic digit 9
    '\u06F0': '0', // Eastern-Arabic digit 0
    '\u06F1': '1', // Eastern-Arabic digit 1
    '\u06F2': '2', // Eastern-Arabic digit 2
    '\u06F3': '3', // Eastern-Arabic digit 3
    '\u06F4': '4', // Eastern-Arabic digit 4
    '\u06F5': '5', // Eastern-Arabic digit 5
    '\u06F6': '6', // Eastern-Arabic digit 6
    '\u06F7': '7', // Eastern-Arabic digit 7
    '\u06F8': '8', // Eastern-Arabic digit 8
    '\u06F9': '9', // Eastern-Arabic digit 9
    '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'
  };
  
  
  /**
   * Separate map of all symbols that we wish to retain when formatting alpha
   * numbers. This includes digits, ASCII letters and number grouping symbols such
   * as '-' and ' '.
   *
   * @const
   * @type {!Object.<string, string>}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_ = {
    '0': '0',
    '1': '1',
    '2': '2',
    '3': '3',
    '4': '4',
    '5': '5',
    '6': '6',
    '7': '7',
    '8': '8',
    '9': '9',
    'A': 'A',
    'B': 'B',
    'C': 'C',
    'D': 'D',
    'E': 'E',
    'F': 'F',
    'G': 'G',
    'H': 'H',
    'I': 'I',
    'J': 'J',
    'K': 'K',
    'L': 'L',
    'M': 'M',
    'N': 'N',
    'O': 'O',
    'P': 'P',
    'Q': 'Q',
    'R': 'R',
    'S': 'S',
    'T': 'T',
    'U': 'U',
    'V': 'V',
    'W': 'W',
    'X': 'X',
    'Y': 'Y',
    'Z': 'Z',
    'a': 'A',
    'b': 'B',
    'c': 'C',
    'd': 'D',
    'e': 'E',
    'f': 'F',
    'g': 'G',
    'h': 'H',
    'i': 'I',
    'j': 'J',
    'k': 'K',
    'l': 'L',
    'm': 'M',
    'n': 'N',
    'o': 'O',
    'p': 'P',
    'q': 'Q',
    'r': 'R',
    's': 'S',
    't': 'T',
    'u': 'U',
    'v': 'V',
    'w': 'W',
    'x': 'X',
    'y': 'Y',
    'z': 'Z',
    '-': '-',
    '\uFF0D': '-',
    '\u2010': '-',
    '\u2011': '-',
    '\u2012': '-',
    '\u2013': '-',
    '\u2014': '-',
    '\u2015': '-',
    '\u2212': '-',
    '/': '/',
    '\uFF0F': '/',
    ' ': ' ',
    '\u3000': ' ',
    '\u2060': ' ',
    '.': '.',
    '\uFF0E': '.'
  };
  
  
  /**
   * Pattern that makes it easy to distinguish whether a region has a unique
   * international dialing prefix or not. If a region has a unique international
   * prefix (e.g. 011 in USA), it will be represented as a string that contains a
   * sequence of ASCII digits. If there are multiple available international
   * prefixes in a region, they will be represented as a regex string that always
   * contains character(s) other than ASCII digits. Note this regex also includes
   * tilde, which signals waiting for the tone.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_ =
      /[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?/;
  
  
  /**
   * Regular expression of acceptable punctuation found in phone numbers. This
   * excludes punctuation found as a leading character only. This consists of dash
   * characters, white space characters, full stops, slashes, square brackets,
   * parentheses and tildes. It also includes the letter 'x' as that is found as a
   * placeholder for carrier information in some phone numbers. Full-width
   * variants are also present.
   *
   * @const
   * @type {string}
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION =
      '-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0\u00AD\u200B\u2060\u3000' +
      '()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E';
  
  
  /**
   * Digits accepted in phone numbers (ascii, fullwidth, arabic-indic, and eastern
   * arabic digits).
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ =
      '0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9';
  
  
  /**
   * We accept alpha characters in phone numbers, ASCII only, upper and lower
   * case.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ = 'A-Za-z';
  
  
  /**
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ = '+\uFF0B';
  
  
  /**
   * @const
   * @type {!RegExp}
   */
  i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN =
      new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
  
  
  /**
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_ =
      new RegExp('^[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
  
  
  /**
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_ =
      '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + ']+';
  
  
  /**
   * @const
   * @type {!RegExp}
   */
  i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN =
      new RegExp('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + '])');
  
  
  /**
   * Regular expression of acceptable characters that may start a phone number for
   * the purposes of parsing. This allows us to strip away meaningless prefixes to
   * phone numbers that may be mistakenly given to us. This consists of digits,
   * the plus symbol and arabic-indic digits. This does not contain alpha
   * characters, although they may be used later in the number. It also does not
   * include other punctuation, as this will be stripped later during parsing and
   * is of no information value when parsing a number.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_ =
      new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ +
                 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']');
  
  
  /**
   * Regular expression of characters typically used to start a second phone
   * number for the purposes of parsing. This allows us to strip off parts of the
   * number that are actually the start of another number, such as for:
   * (530) 583-6985 x302/x2303 -> the second extension here makes this actually
   * two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove
   * the second extension so that the first number is parsed correctly.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_ = /[\\\/] *x/;
  
  
  /**
   * Regular expression of trailing characters that we want to remove. We remove
   * all characters that are not alpha or numerical characters. The hash character
   * is retained here, as it may signify the previous block was an extension.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_ =
      new RegExp('[^' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ +
                 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + '#]+$');
  
  
  /**
   * We use this pattern to check if the phone number has at least three letters
   * in it - if so, then we treat it as a number where some phone-number digits
   * are represented by letters.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ =
      /(?:.*?[A-Za-z]){3}.*/;
  
  
  /**
   * Regular expression of viable phone numbers. This is location independent.
   * Checks we have at least three leading digits, and only valid punctuation,
   * alpha characters and digits in the phone number. Does not include extension
   * data. The symbol 'x' is allowed here as valid punctuation since it is often
   * used as a placeholder for carrier codes, for example in Brazilian phone
   * numbers. We also allow multiple '+' characters at the start.
   * Corresponds to the following:
   * [digits]{minLengthNsn}|
   * plus_sign*
   * (([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
   *
   * The first reg-ex is to allow short numbers (two digits long) to be parsed if
   * they are entered as "15" etc, but only if there is no punctuation in them.
   * The second expression restricts the number of digits to three or more, but
   * then allows them to be in international form, and to have alpha-characters
   * and punctuation. We split up the two reg-exes here and combine them when
   * creating the reg-ex VALID_PHONE_NUMBER_PATTERN_ itself so we can prefix it
   * with ^ and append $ to each branch.
   *
   * Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ =
      '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{' +
      i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ + '}';
  
  
  /**
   * See MIN_LENGTH_PHONE_NUMBER_PATTERN_ for a full description of this reg-exp.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ =
      '[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' +
      i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION +
      i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ + ']*[' +
      i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']){3,}[' +
      i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION +
      i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ +
      i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ +
      i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']*';
  
  
  /**
   * Default extension prefix to use when formatting. This will be put in front of
   * any extension component of the number, after the main national number is
   * formatted. For example, if you wish the default extension formatting to be
   * ' extn: 3456', then you should specify ' extn: ' here as the default
   * extension prefix. This can be overridden by region-specific preferences.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ = ' ext. ';
  
  
  /**
   * Pattern to capture digits used in an extension.
   * Places a maximum length of '7' for an extension.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ =
      '([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})';
  
  
  /**
   * Regexp of all possible ways to write extensions, for use when parsing. This
   * will be run as a case-insensitive regexp match. Wide character versions are
   * also provided after each ASCII version. There are three regular expressions
   * here. The first covers RFC 3966 format, where the extension is added using
   * ';ext='. The second more generic one starts with optional white space and
   * ends with an optional full stop (.), followed by zero or more spaces/tabs and
   * then the numbers themselves. The other one covers the special case of
   * American numbers where the extension is written with a hash at the end, such
   * as '- 503#'. Note that the only capturing groups should be around the digits
   * that you want to capture as part of the extension, or else parsing will fail!
   * We allow two options for representing the accented o - the character itself,
   * and one in the unicode decomposed form with the combining acute accent.
   *
   * @const
   * @type {string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ =
      i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ +
      i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ + '|' +
      '[ \u00A0\\t,]*' +
      '(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|' +
      '[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)' +
      '[:\\.\uFF0E]?[ \u00A0\\t,-]*' +
      i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ + '#?|' +
      '[- ]+([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,5})#';
  
  
  /**
   * Regexp of all known extension prefixes used by different regions followed by
   * 1 or more valid digits, for use when parsing.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ =
      new RegExp('(?:' +
                 i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ +
                 ')$', 'i');
  
  
  /**
   * We append optionally the extension pattern to the end here, as a valid phone
   * number may have an extension prefix appended, followed by 1 or more digits.
   *
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ =
      new RegExp(
          '^' +
          i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ +
          '$|' +
          '^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ +
          '(?:' + i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ +
          ')?' + '$', 'i');
  
  
  /**
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_ = /\D+/;
  
  
  /**
   * This was originally set to $1 but there are some countries for which the
   * first group is not used in the national pattern (e.g. Argentina) so the $1
   * group does not match correctly.  Therefore, we use \d, so that the first
   * group actually used in the pattern will be matched.
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_ = /(\$\d)/;
  
  
  /**
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_ = /\$NP/;
  
  
  /**
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/;
  
  
  /**
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/;
  
  
  /**
   * A pattern that is used to determine if the national prefix formatting rule
   * has the first group only, i.e., does not start with the national prefix.
   * Note that the pattern explicitly allows for unbalanced parentheses.
   * @const
   * @type {!RegExp}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_ =
      /^\(?\$1\)?$/;
  
  
  /**
   * @const
   * @type {string}
   */
  i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY = '001';
  
  
  /**
   * INTERNATIONAL and NATIONAL formats are consistent with the definition in
   * ITU-T Recommendation E123. For example, the number of the Google Switzerland
   * office will be written as '+41 44 668 1800' in INTERNATIONAL format, and as
   * '044 668 1800' in NATIONAL format. E164 format is as per INTERNATIONAL format
   * but with no formatting applied, e.g. '+41446681800'. RFC3966 is as per
   * INTERNATIONAL format, but with all spaces and other separating symbols
   * replaced with a hyphen, and with any phone number extension appended with
   * ';ext='. It also will have a prefix of 'tel:' added, e.g.
   * 'tel:+41-44-668-1800'.
   *
   * Note: If you are considering storing the number in a neutral format, you are
   * highly advised to use the PhoneNumber class.
   * @enum {number}
   */
  i18n.phonenumbers.PhoneNumberFormat = {
    E164: 0,
    INTERNATIONAL: 1,
    NATIONAL: 2,
    RFC3966: 3
  };
  
  
  /**
   * Type of phone numbers.
   *
   * @enum {number}
   */
  i18n.phonenumbers.PhoneNumberType = {
    FIXED_LINE: 0,
    MOBILE: 1,
    // In some regions (e.g. the USA), it is impossible to distinguish between
    // fixed-line and mobile numbers by looking at the phone number itself.
    FIXED_LINE_OR_MOBILE: 2,
    // Freephone lines
    TOLL_FREE: 3,
    PREMIUM_RATE: 4,
    // The cost of this call is shared between the caller and the recipient, and
    // is hence typically less than PREMIUM_RATE calls. See
    // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
    SHARED_COST: 5,
    // Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
    VOIP: 6,
    // A personal number is associated with a particular person, and may be routed
    // to either a MOBILE or FIXED_LINE number. Some more information can be found
    // here: http://en.wikipedia.org/wiki/Personal_Numbers
    PERSONAL_NUMBER: 7,
    PAGER: 8,
    // Used for 'Universal Access Numbers' or 'Company Numbers'. They may be
    // further routed to specific offices, but allow one number to be used for a
    // company.
    UAN: 9,
    // Used for 'Voice Mail Access Numbers'.
    VOICEMAIL: 10,
    // A phone number is of type UNKNOWN when it does not fit any of the known
    // patterns for a specific region.
    UNKNOWN: -1
  };
  
  
  /**
   * Types of phone number matches. See detailed description beside the
   * isNumberMatch() method.
   *
   * @enum {number}
   */
  i18n.phonenumbers.PhoneNumberUtil.MatchType = {
    NOT_A_NUMBER: 0,
    NO_MATCH: 1,
    SHORT_NSN_MATCH: 2,
    NSN_MATCH: 3,
    EXACT_MATCH: 4
  };
  
  
  /**
   * Possible outcomes when testing if a PhoneNumber is possible.
   *
   * @enum {number}
   */
  i18n.phonenumbers.PhoneNumberUtil.ValidationResult = {
    IS_POSSIBLE: 0,
    INVALID_COUNTRY_CODE: 1,
    TOO_SHORT: 2,
    TOO_LONG: 3
  };
  
  
  /**
   * Attempts to extract a possible number from the string passed in. This
   * currently strips all leading characters that cannot be used to start a phone
   * number. Characters that can be used to start a phone number are defined in
   * the VALID_START_CHAR_PATTERN. If none of these characters are found in the
   * number passed in, an empty string is returned. This function also attempts to
   * strip off any alternative extensions or endings if two or more are present,
   * such as in the case of: (530) 583-6985 x302/x2303. The second extension here
   * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985
   * x2303. We remove the second extension so that the first number is parsed
   * correctly.
   *
   * @param {string} number the string that might contain a phone number.
   * @return {string} the number, stripped of any non-phone-number prefix (such as
   *     'Tel:') or an empty string if no character used to start phone numbers
   *     (such as + or any digit) is found in the number.
   */
  i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber = function(number) {
    /** @type {string} */
    var possibleNumber;
  
    /** @type {number} */
    var start = number
        .search(i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_);
    if (start >= 0) {
      possibleNumber = number.substring(start);
      // Remove trailing non-alpha non-numerical characters.
      possibleNumber = possibleNumber.replace(
          i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, '');
  
      // Check for extra numbers at the end.
      /** @type {number} */
      var secondNumberStart = possibleNumber
          .search(i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_);
      if (secondNumberStart >= 0) {
        possibleNumber = possibleNumber.substring(0, secondNumberStart);
      }
    } else {
      possibleNumber = '';
    }
    return possibleNumber;
  };
  
  
  /**
   * Checks to see if the string of characters could possibly be a phone number at
   * all. At the moment, checks to see that the string begins with at least 2
   * digits, ignoring any punctuation commonly found in phone numbers. This method
   * does not require the number to be normalized in advance - but does assume
   * that leading non-number symbols have been removed, such as by the method
   * extractPossibleNumber.
   *
   * @param {string} number string to be checked for viability as a phone number.
   * @return {boolean} true if the number could be a phone number of some sort,
   *     otherwise false.
   */
  i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber = function(number) {
    if (number.length < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
      return false;
    }
    return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
        i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_, number);
  };
  
  
  /**
   * Normalizes a string of characters representing a phone number. This performs
   * the following conversions:
   *   Punctuation is stripped.
   *   For ALPHA/VANITY numbers:
   *   Letters are converted to their numeric representation on a telephone
   *       keypad. The keypad used here is the one defined in ITU Recommendation
   *       E.161. This is only done if there are 3 or more letters in the number,
   *       to lessen the risk that such letters are typos.
   *   For other numbers:
   *   Wide-ascii digits are converted to normal ASCII (European) digits.
   *   Arabic-Indic numerals are converted to European numerals.
   *   Spurious alpha characters are stripped.
   *
   * @param {string} number a string of characters representing a phone number.
   * @return {string} the normalized string version of the phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.normalize = function(number) {
    if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
        i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, number)) {
      return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
          i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, true);
    } else {
      return i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(number);
    }
  };
  
  
  /**
   * Normalizes a string of characters representing a phone number. This is a
   * wrapper for normalize(String number) but does in-place normalization of the
   * StringBuffer provided.
   *
   * @param {!goog.string.StringBuffer} number a StringBuffer of characters
   *     representing a phone number that will be normalized in place.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.normalizeSB_ = function(number) {
    /** @type {string} */
    var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil.normalize(number
        .toString());
    number.clear();
    number.append(normalizedNumber);
  };
  
  
  /**
   * Normalizes a string of characters representing a phone number. This converts
   * wide-ascii and arabic-indic numerals to European numerals, and strips
   * punctuation and alpha characters.
   *
   * @param {string} number a string of characters representing a phone number.
   * @return {string} the normalized string version of the phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly = function(number) {
    return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
        i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
  };
  
  
  /**
   * Converts all alpha characters in a number to their respective digits on a
   * keypad, but retains existing formatting. Also converts wide-ascii digits to
   * normal ascii digits, and converts Arabic-Indic numerals to European numerals.
   *
   * @param {string} number a string of characters representing a phone number.
   * @return {string} the normalized string version of the phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.convertAlphaCharactersInNumber =
      function(number) {
  
    return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
        i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, false);
  };
  
  
  /**
   * Gets the length of the geographical area code from the
   * {@code national_number} field of the PhoneNumber object passed in, so that
   * clients could use it to split a national significant number into geographical
   * area code and subscriber number. It works in such a way that the resultant
   * subscriber number should be diallable, at least on some devices. An example
   * of how this could be used:
   *
   * <pre>
   * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
   * var number = phoneUtil.parse('16502530000', 'US');
   * var nationalSignificantNumber =
   *     phoneUtil.getNationalSignificantNumber(number);
   * var areaCode;
   * var subscriberNumber;
   *
   * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
   * if (areaCodeLength > 0) {
   *   areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
   *   subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
   * } else {
   *   areaCode = '';
   *   subscriberNumber = nationalSignificantNumber;
   * }
   * </pre>
   *
   * N.B.: area code is a very ambiguous concept, so the I18N team generally
   * recommends against using it for most purposes, but recommends using the more
   * general {@code national_number} instead. Read the following carefully before
   * deciding to use this method:
   * <ul>
   *  <li> geographical area codes change over time, and this method honors those
   *    changes; therefore, it doesn't guarantee the stability of the result it
   *    produces.
   *  <li> subscriber numbers may not be diallable from all devices (notably
   *    mobile devices, which typically requires the full national_number to be
   *    dialled in most regions).
   *  <li> most non-geographical numbers have no area codes, including numbers
   *    from non-geographical entities.
   *  <li> some geographical numbers have no area codes.
   * </ul>
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
   *     which clients want to know the length of the area code.
   * @return {number} the length of area code of the PhoneNumber object passed in.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
      function(number) {
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number));
    if (metadata == null) {
      return 0;
    }
    // If a country doesn't use a national prefix, and this number doesn't have
    // an Italian leading zero, we assume it is a closed dialling plan with no
    // area codes.
    if (!metadata.hasNationalPrefix() && !number.hasItalianLeadingZero()) {
      return 0;
    }
  
    if (!this.isNumberGeographical(number)) {
      return 0;
    }
  
    return this.getLengthOfNationalDestinationCode(number);
  };
  
  
  /**
   * Gets the length of the national destination code (NDC) from the PhoneNumber
   * object passed in, so that clients could use it to split a national
   * significant number into NDC and subscriber number. The NDC of a phone number
   * is normally the first group of digit(s) right after the country calling code
   * when the number is formatted in the international format, if there is a
   * subscriber number part that follows. An example of how this could be used:
   *
   * <pre>
   * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
   * var number = phoneUtil.parse('18002530000', 'US');
   * var nationalSignificantNumber =
   *     phoneUtil.getNationalSignificantNumber(number);
   * var nationalDestinationCode;
   * var subscriberNumber;
   *
   * var nationalDestinationCodeLength =
   *     phoneUtil.getLengthOfNationalDestinationCode(number);
   * if (nationalDestinationCodeLength > 0) {
   *   nationalDestinationCode =
   *       nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
   *   subscriberNumber =
   *       nationalSignificantNumber.substring(nationalDestinationCodeLength);
   * } else {
   *   nationalDestinationCode = '';
   *   subscriberNumber = nationalSignificantNumber;
   * }
   * </pre>
   *
   * Refer to the unittests to see the difference between this function and
   * {@link #getLengthOfGeographicalAreaCode}.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
   *     which clients want to know the length of the NDC.
   * @return {number} the length of NDC of the PhoneNumber object passed in.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode =
      function(number) {
  
    /** @type {i18n.phonenumbers.PhoneNumber} */
    var copiedProto;
    if (number.hasExtension()) {
      // We don't want to alter the proto given to us, but we don't want to
      // include the extension when we format it, so we copy it and clear the
      // extension here.
      copiedProto = number.clone();
      copiedProto.clearExtension();
    } else {
      copiedProto = number;
    }
  
    /** @type {string} */
    var nationalSignificantNumber = this.format(copiedProto,
        i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
    /** @type {!Array.<string>} */
    var numberGroups = nationalSignificantNumber.split(
        i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_);
    // The pattern will start with '+COUNTRY_CODE ' so the first group will always
    // be the empty string (before the + symbol) and the second group will be the
    // country calling code. The third group will be area code if it is not the
    // last group.
    // NOTE: On IE the first group that is supposed to be the empty string does
    // not appear in the array of number groups... so make the result on non-IE
    // browsers to be that of IE.
    if (numberGroups[0].length == 0) {
      numberGroups.shift();
    }
    if (numberGroups.length <= 2) {
      return 0;
    }
  
    if (this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) {
      // For example Argentinian mobile numbers, when formatted in the
      // international format, are in the form of +54 9 NDC XXXX.... As a result,
      // we take the length of the third group (NDC) and add the length of the
      // mobile token, which also forms part of the national significant number.
      // This assumes that the mobile token is always formatted separately from
      // the rest of the phone number.
      /** @type {string} */
      var mobileToken = i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken(
          number.getCountryCodeOrDefault());
      if (mobileToken != '') {
        return numberGroups[2].length + mobileToken.length;
      }
    }
    return numberGroups[1].length;
  };
  
  
  /**
   * Returns the mobile token for the provided country calling code if it has
   * one, otherwise returns an empty string. A mobile token is a number inserted
   * before the area code when dialing a mobile number from that country from
   * abroad.
   *
   * @param {number} countryCallingCode the country calling code for which we
   *     want the mobile token.
   * @return {string} the mobile token for the given country calling code.
   */
  i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken =
      function(countryCallingCode) {
    return i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_[
        countryCallingCode] || '';
  };
  
  
  /**
   * Convenience method to get a list of what regions the library has metadata
   * for.
   * @return {!Array.<string>} region codes supported by the library.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedRegions = function() {
    return goog.array.filter(
        Object.keys(i18n.phonenumbers.metadata.countryToMetadata),
        function(regionCode) {
          return isNaN(regionCode);
        });
  };
  
  
  /**
   * Convenience method to get a list of what global network calling codes the
   * library has metadata for.
   * @return {!Array.<number>} global network calling codes supported by the
   *     library.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      getSupportedGlobalNetworkCallingCodes = function() {
    var callingCodesAsStrings = goog.array.filter(
        Object.keys(i18n.phonenumbers.metadata.countryToMetadata),
        function(regionCode) {
          return !isNaN(regionCode);
        });
    return goog.array.map(callingCodesAsStrings,
        function(callingCode) {
          return parseInt(callingCode, 10);
        });
  };
  
  
  /**
   * Normalizes a string of characters representing a phone number by replacing
   * all characters found in the accompanying map with the values therein, and
   * stripping all other characters if removeNonMatches is true.
   *
   * @param {string} number a string of characters representing a phone number.
   * @param {!Object.<string, string>} normalizationReplacements a mapping of
   *     characters to what they should be replaced by in the normalized version
   *     of the phone number.
   * @param {boolean} removeNonMatches indicates whether characters that are not
   *     able to be replaced should be stripped from the number. If this is false,
   *     they will be left unchanged in the number.
   * @return {string} the normalized string version of the phone number.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_ =
      function(number, normalizationReplacements, removeNonMatches) {
  
    /** @type {!goog.string.StringBuffer} */
    var normalizedNumber = new goog.string.StringBuffer();
    /** @type {string} */
    var character;
    /** @type {string} */
    var newDigit;
    /** @type {number} */
    var numberLength = number.length;
    for (var i = 0; i < numberLength; ++i) {
      character = number.charAt(i);
      newDigit = normalizationReplacements[character.toUpperCase()];
      if (newDigit != null) {
        normalizedNumber.append(newDigit);
      } else if (!removeNonMatches) {
        normalizedNumber.append(character);
      }
      // If neither of the above are true, we remove this character.
    }
    return normalizedNumber.toString();
  };
  
  
  /**
   * Helper function to check if the national prefix formatting rule has the first
   * group only, i.e., does not start with the national prefix.
   *
   * @param {string} nationalPrefixFormattingRule The formatting rule for the
   *     national prefix.
   * @return {boolean} true if the national prefix formatting rule has the first
   *     group only.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formattingRuleHasFirstGroupOnly =
      function(nationalPrefixFormattingRule) {
    return nationalPrefixFormattingRule.length == 0 ||
        i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_.
            test(nationalPrefixFormattingRule);
  };
  
  
  /**
   * Tests whether a phone number has a geographical association. It checks if
   * the number is associated to a certain region in the country where it belongs
   * to. Note that this doesn't verify if the number is actually in use.
   *
   * @param {i18n.phonenumbers.PhoneNumber} phoneNumber The phone number to test.
   * @return {boolean} true if the phone number has a geographical association.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberGeographical =
      function(phoneNumber) {
    /** @type {i18n.phonenumbers.PhoneNumberType} */
    var numberType = this.getNumberType(phoneNumber);
  
    return numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE ||
        numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE ||
        (goog.array.contains(
            i18n.phonenumbers.PhoneNumberUtil.GEO_MOBILE_COUNTRIES_,
            phoneNumber.getCountryCodeOrDefault()) &&
         numberType == i18n.phonenumbers.PhoneNumberType.MOBILE);
  };
  
  
  /**
   * Helper function to check region code is not unknown or null.
   *
   * @param {?string} regionCode the ISO 3166-1 two-letter region code.
   * @return {boolean} true if region code is valid.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ =
      function(regionCode) {
  
    // In Java we check whether the regionCode is contained in supportedRegions
    // that is built out of all the values of countryCallingCodeToRegionCodeMap
    // (countryCodeToRegionCodeMap in JS) minus REGION_CODE_FOR_NON_GEO_ENTITY.
    // In JS we check whether the regionCode is contained in the keys of
    // countryToMetadata but since for non-geographical country calling codes
    // (e.g. +800) we use the country calling codes instead of the region code as
    // key in the map we have to make sure regionCode is not a number to prevent
    // returning true for non-geographical country calling codes.
    return regionCode != null &&
        isNaN(regionCode) &&
        regionCode.toUpperCase() in i18n.phonenumbers.metadata.countryToMetadata;
  };
  
  
  /**
   * Helper function to check the country calling code is valid.
   *
   * @param {number} countryCallingCode the country calling code.
   * @return {boolean} true if country calling code code is valid.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.hasValidCountryCallingCode_ =
      function(countryCallingCode) {
  
    return countryCallingCode in
        i18n.phonenumbers.metadata.countryCodeToRegionCodeMap;
  };
  
  
  /**
   * Formats a phone number in the specified format using default rules. Note that
   * this does not promise to produce a phone number that the user can dial from
   * where they are - although we do format in either 'national' or
   * 'international' format depending on what the client asks for, we do not
   * currently support a more abbreviated format, such as for users in the same
   * 'area' who could potentially dial the number without area code. Note that if
   * the phone number has a country calling code of 0 or an otherwise invalid
   * country calling code, we cannot work out which formatting rules to apply so
   * we return the national significant number with no formatting applied.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
   *     formatted.
   * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
   *     phone number should be formatted into.
   * @return {string} the formatted phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.format =
      function(number, numberFormat) {
  
    if (number.getNationalNumber() == 0 && number.hasRawInput()) {
      // Unparseable numbers that kept their raw input just use that.
      // This is the only case where a number can be formatted as E164 without a
      // leading '+' symbol (but the original number wasn't parseable anyway).
      // TODO: Consider removing the 'if' above so that unparseable strings
      // without raw input format to the empty string instead of "+00"
      /** @type {string} */
      var rawInput = number.getRawInputOrDefault();
      if (rawInput.length > 0) {
        return rawInput;
      }
    }
    /** @type {number} */
    var countryCallingCode = number.getCountryCodeOrDefault();
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
    if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) {
      // Early exit for E164 case (even if the country calling code is invalid)
      // since no formatting of the national number needs to be applied.
      // Extensions are not formatted.
      return this.prefixNumberWithCountryCallingCode_(
          countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.E164,
          nationalSignificantNumber, '');
    }
    if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
      return nationalSignificantNumber;
    }
    // Note getRegionCodeForCountryCode() is used because formatting information
    // for regions which share a country calling code is contained by only one
    // region for performance reasons. For example, for NANPA regions it will be
    // contained in the metadata for US.
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
  
    // Metadata cannot be null because the country calling code is valid (which
    // means that the region code cannot be ZZ and must be one of our supported
    // region codes).
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata =
        this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
    /** @type {string} */
    var formattedExtension =
        this.maybeGetFormattedExtension_(number, metadata, numberFormat);
    /** @type {string} */
    var formattedNationalNumber =
        this.formatNsn_(nationalSignificantNumber, metadata, numberFormat);
    return this.prefixNumberWithCountryCallingCode_(countryCallingCode,
                                                    numberFormat,
                                                    formattedNationalNumber,
                                                    formattedExtension);
  };
  
  
  /**
   * Formats a phone number in the specified format using client-defined
   * formatting rules. Note that if the phone number has a country calling code of
   * zero or an otherwise invalid country calling code, we cannot work out things
   * like whether there should be a national prefix applied, or how to format
   * extensions, so we return the national significant number with no formatting
   * applied.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone  number to be
   *     formatted.
   * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
   *     phone number should be formatted into.
   * @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting
   *     rules specified by clients.
   * @return {string} the formatted phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
      function(number, numberFormat, userDefinedFormats) {
  
    /** @type {number} */
    var countryCallingCode = number.getCountryCodeOrDefault();
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
    if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
      return nationalSignificantNumber;
    }
    // Note getRegionCodeForCountryCode() is used because formatting information
    // for regions which share a country calling code is contained by only one
    // region for performance reasons. For example, for NANPA regions it will be
    // contained in the metadata for US.
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
    // Metadata cannot be null because the country calling code is valid
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata =
        this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
  
    /** @type {string} */
    var formattedNumber = '';
  
    /** @type {i18n.phonenumbers.NumberFormat} */
    var formattingPattern = this.chooseFormattingPatternForNumber_(
        userDefinedFormats, nationalSignificantNumber);
    if (formattingPattern == null) {
      // If no pattern above is matched, we format the number as a whole.
      formattedNumber = nationalSignificantNumber;
    } else {
      // Before we do a replacement of the national prefix pattern $NP with the
      // national prefix, we need to copy the rule so that subsequent replacements
      // for different numbers have the appropriate national prefix.
      /** @type {i18n.phonenumbers.NumberFormat} */
      var numFormatCopy = formattingPattern.clone();
      /** @type {string} */
      var nationalPrefixFormattingRule =
          formattingPattern.getNationalPrefixFormattingRuleOrDefault();
      if (nationalPrefixFormattingRule.length > 0) {
        /** @type {string} */
        var nationalPrefix = metadata.getNationalPrefixOrDefault();
        if (nationalPrefix.length > 0) {
          // Replace $NP with national prefix and $FG with the first group ($1).
          nationalPrefixFormattingRule = nationalPrefixFormattingRule
              .replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_,
                       nationalPrefix)
              .replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1');
          numFormatCopy.setNationalPrefixFormattingRule(
              nationalPrefixFormattingRule);
        } else {
          // We don't want to have a rule for how to format the national prefix if
          // there isn't one.
          numFormatCopy.clearNationalPrefixFormattingRule();
        }
      }
      formattedNumber = this.formatNsnUsingPattern_(
          nationalSignificantNumber, numFormatCopy, numberFormat);
    }
  
    /** @type {string} */
    var formattedExtension =
        this.maybeGetFormattedExtension_(number, metadata, numberFormat);
    return this.prefixNumberWithCountryCallingCode_(countryCallingCode,
                                                    numberFormat,
                                                    formattedNumber,
                                                    formattedExtension);
  };
  
  
  /**
   * Formats a phone number in national format for dialing using the carrier as
   * specified in the {@code carrierCode}. The {@code carrierCode} will always be
   * used regardless of whether the phone number already has a preferred domestic
   * carrier code stored. If {@code carrierCode} contains an empty string, returns
   * the number in national format without any carrier code.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
   *     formatted.
   * @param {string} carrierCode the carrier selection code to be used.
   * @return {string} the formatted phone number in national format for dialing
   *     using the carrier as specified in the {@code carrierCode}.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      formatNationalNumberWithCarrierCode = function(number, carrierCode) {
  
    /** @type {number} */
    var countryCallingCode = number.getCountryCodeOrDefault();
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
    if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
      return nationalSignificantNumber;
    }
  
    // Note getRegionCodeForCountryCode() is used because formatting information
    // for regions which share a country calling code is contained by only one
    // region for performance reasons. For example, for NANPA regions it will be
    // contained in the metadata for US.
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
    // Metadata cannot be null because the country calling code is valid.
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata =
        this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
    /** @type {string} */
    var formattedExtension = this.maybeGetFormattedExtension_(
        number, metadata, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
    /** @type {string} */
    var formattedNationalNumber = this.formatNsn_(
        nationalSignificantNumber, metadata,
        i18n.phonenumbers.PhoneNumberFormat.NATIONAL, carrierCode);
    return this.prefixNumberWithCountryCallingCode_(
        countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
        formattedNationalNumber, formattedExtension);
  };
  
  
  /**
   * @param {number} countryCallingCode
   * @param {?string} regionCode
   * @return {i18n.phonenumbers.PhoneMetadata}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegionOrCallingCode_ =
      function(countryCallingCode, regionCode) {
    return i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY ==
        regionCode ?
        this.getMetadataForNonGeographicalRegion(countryCallingCode) :
        this.getMetadataForRegion(regionCode);
  };
  
  
  /**
   * Formats a phone number in national format for dialing using the carrier as
   * specified in the preferred_domestic_carrier_code field of the PhoneNumber
   * object passed in. If that is missing, use the {@code fallbackCarrierCode}
   * passed in instead. If there is no {@code preferred_domestic_carrier_code},
   * and the {@code fallbackCarrierCode} contains an empty string, return the
   * number in national format without any carrier code.
   *
   * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier
   * code passed in should take precedence over the number's
   * {@code preferred_domestic_carrier_code} when formatting.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
   *     formatted.
   * @param {string} fallbackCarrierCode the carrier selection code to be used, if
   *     none is found in the phone number itself.
   * @return {string} the formatted phone number in national format for dialing
   *     using the number's preferred_domestic_carrier_code, or the
   *     {@code fallbackCarrierCode} passed in if none is found.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      formatNationalNumberWithPreferredCarrierCode = function(
          number, fallbackCarrierCode) {
    return this.formatNationalNumberWithCarrierCode(
        number,
        // Historically, we set this to an empty string when parsing with raw
        // input if none was found in the input string. However, this doesn't
        // result in a number we can dial. For this reason, we treat the empty
        // string the same as if it isn't set at all.
        number.getPreferredDomesticCarrierCodeOrDefault().length > 0 ?
            number.getPreferredDomesticCarrierCodeOrDefault() :
            fallbackCarrierCode);
  };
  
  
  /**
   * Returns a number formatted in such a way that it can be dialed from a mobile
   * phone in a specific region. If the number cannot be reached from the region
   * (e.g. some countries block toll-free numbers from being called outside of the
   * country), the method returns an empty string.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
   *     formatted.
   * @param {string} regionCallingFrom the region where the call is being placed.
   * @param {boolean} withFormatting whether the number should be returned with
   *     formatting symbols, such as spaces and dashes.
   * @return {string} the formatted phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formatNumberForMobileDialing =
      function(number, regionCallingFrom, withFormatting) {
  
    /** @type {number} */
    var countryCallingCode = number.getCountryCodeOrDefault();
    if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
      return number.hasRawInput() ? number.getRawInputOrDefault() : '';
    }
  
    /** @type {string} */
    var formattedNumber = '';
    // Clear the extension, as that part cannot normally be dialed together with
    // the main number.
    /** @type {i18n.phonenumbers.PhoneNumber} */
    var numberNoExt = number.clone();
    numberNoExt.clearExtension();
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
    /** @type {i18n.phonenumbers.PhoneNumberType} */
    var numberType = this.getNumberType(numberNoExt);
    /** @type {boolean} */
    var isValidNumber = (numberType != i18n.phonenumbers.PhoneNumberType.UNKNOWN);
    if (regionCallingFrom == regionCode) {
      /** @type {boolean} */
      var isFixedLineOrMobile =
          (numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE) ||
          (numberType == i18n.phonenumbers.PhoneNumberType.MOBILE) ||
          (numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE);
      // Carrier codes may be needed in some countries. We handle this here.
      if (regionCode == 'CO' &&
          numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE) {
        formattedNumber = this.formatNationalNumberWithCarrierCode(
            numberNoExt,
            i18n.phonenumbers.PhoneNumberUtil
                .COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_);
      } else if (regionCode == 'BR' && isFixedLineOrMobile) {
        formattedNumber =
            // Historically, we set this to an empty string when parsing with raw
            // input if none was found in the input string. However, this doesn't
            // result in a number we can dial. For this reason, we treat the empty
            // string the same as if it isn't set at all.
            numberNoExt.getPreferredDomesticCarrierCodeOrDefault().length > 0 ?
            this.formatNationalNumberWithPreferredCarrierCode(numberNoExt, '') :
            // Brazilian fixed line and mobile numbers need to be dialed with a
            // carrier code when called within Brazil. Without that, most of the
            // carriers won't connect the call. Because of that, we return an
            // empty string here.
            '';
      } else if (isValidNumber && regionCode == 'HU') {
        // The national format for HU numbers doesn't contain the national prefix,
        // because that is how numbers are normally written down. However, the
        // national prefix is obligatory when dialing from a mobile phone. As a
        // result, we add it back here if it is a valid regular length phone
        // number.
        formattedNumber =
            this.getNddPrefixForRegion(regionCode, true /* strip non-digits */) +
            ' ' + this.format(numberNoExt,
                i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
      } else if (countryCallingCode ==
                 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
        // For NANPA countries, we output international format for numbers that
        // can be dialed internationally, since that always works, except for
        // numbers which might potentially be short numbers, which are always
        // dialled in national format.
        /** @type {i18n.phonenumbers.PhoneMetadata} */
        var regionMetadata = this.getMetadataForRegion(regionCallingFrom);
        if (this.canBeInternationallyDialled(numberNoExt) &&
            this.testNumberLength_(this.getNationalSignificantNumber(numberNoExt),
                regionMetadata.getGeneralDesc()) !=
            i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
          formattedNumber = this.format(
              numberNoExt, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
        } else {
          formattedNumber = this.format(
              numberNoExt, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
        }
      } else {
        // For non-geographical countries, Mexican and Chilean fixed line and
        // mobile numbers, we output international format for numbers that can be
        // dialed internationally, as that always works.
        if ((regionCode ==
             i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY ||
            // MX fixed line and mobile numbers should always be formatted in
            // international format, even when dialed within MX. For national
            // format to work, a carrier code needs to be used, and the correct
            // carrier code depends on if the caller and callee are from the
            // same local area. It is trickier to get that to work correctly than
            // using international format, which is tested to work fine on all
            // carriers.
            // CL fixed line numbers need the national prefix when dialing in the
            // national format, but don't have it when used for display. The
            // reverse is true for mobile numbers. As a result, we output them in
            // the international format to make it work.
            ((regionCode == 'MX' || regionCode == 'CL') &&
                isFixedLineOrMobile)) &&
            this.canBeInternationallyDialled(numberNoExt)) {
          formattedNumber = this.format(
              numberNoExt, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
        } else {
          formattedNumber = this.format(
              numberNoExt, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
        }
      }
    } else if (isValidNumber && this.canBeInternationallyDialled(numberNoExt)) {
      // We assume that short numbers are not diallable from outside their region,
      // so if a number is not a valid regular length phone number, we treat it as
      // if it cannot be internationally dialled.
      return withFormatting ?
          this.format(numberNoExt,
                      i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL) :
          this.format(numberNoExt, i18n.phonenumbers.PhoneNumberFormat.E164);
    }
    return withFormatting ?
        formattedNumber :
        i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(formattedNumber,
            i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_, true);
  };
  
  
  /**
   * Formats a phone number for out-of-country dialing purposes. If no
   * regionCallingFrom is supplied, we format the number in its INTERNATIONAL
   * format. If the country calling code is the same as that of the region where
   * the number is from, then NATIONAL formatting will be applied.
   *
   * <p>If the number itself has a country calling code of zero or an otherwise
   * invalid country calling code, then we return the number with no formatting
   * applied.
   *
   * <p>Note this function takes care of the case for calling inside of NANPA and
   * between Russia and Kazakhstan (who share the same country calling code). In
   * those cases, no international prefix is used. For regions which have multiple
   * international prefixes, the number in its INTERNATIONAL format will be
   * returned instead.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
   *     formatted.
   * @param {string} regionCallingFrom the region where the call is being placed.
   * @return {string} the formatted phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber =
      function(number, regionCallingFrom) {
  
    if (!this.isValidRegionCode_(regionCallingFrom)) {
      return this.format(number,
                         i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
    }
    /** @type {number} */
    var countryCallingCode = number.getCountryCodeOrDefault();
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
    if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
      return nationalSignificantNumber;
    }
    if (countryCallingCode ==
            i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
      if (this.isNANPACountry(regionCallingFrom)) {
        // For NANPA regions, return the national format for these regions but
        // prefix it with the country calling code.
        return countryCallingCode + ' ' +
            this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
      }
    } else if (countryCallingCode ==
                   this.getCountryCodeForValidRegion_(regionCallingFrom)) {
      // If regions share a country calling code, the country calling code need
      // not be dialled. This also applies when dialling within a region, so this
      // if clause covers both these cases. Technically this is the case for
      // dialling from La Reunion to other overseas departments of France (French
      // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover
      // this edge case for now and for those cases return the version including
      // country calling code. Details here:
      // http://www.petitfute.com/voyage/225-info-pratiques-reunion
      return this.format(number,
                         i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
    }
    // Metadata cannot be null because we checked 'isValidRegionCode()' above.
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadataForRegionCallingFrom =
        this.getMetadataForRegion(regionCallingFrom);
    /** @type {string} */
    var internationalPrefix =
        metadataForRegionCallingFrom.getInternationalPrefixOrDefault();
  
    // For regions that have multiple international prefixes, the international
    // format of the number is returned, unless there is a preferred international
    // prefix.
    /** @type {string} */
    var internationalPrefixForFormatting = '';
    if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
        i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_,
        internationalPrefix)) {
      internationalPrefixForFormatting = internationalPrefix;
    } else if (metadataForRegionCallingFrom.hasPreferredInternationalPrefix()) {
      internationalPrefixForFormatting =
          metadataForRegionCallingFrom.getPreferredInternationalPrefixOrDefault();
    }
  
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
    // Metadata cannot be null because the country calling code is valid.
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadataForRegion =
        this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
    /** @type {string} */
    var formattedNationalNumber = this.formatNsn_(
        nationalSignificantNumber, metadataForRegion,
        i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
    /** @type {string} */
    var formattedExtension = this.maybeGetFormattedExtension_(number,
        metadataForRegion, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
    return internationalPrefixForFormatting.length > 0 ?
        internationalPrefixForFormatting + ' ' + countryCallingCode + ' ' +
            formattedNationalNumber + formattedExtension :
        this.prefixNumberWithCountryCallingCode_(
            countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
            formattedNationalNumber, formattedExtension);
  };
  
  
  /**
   * Formats a phone number using the original phone number format that the number
   * is parsed from. The original format is embedded in the country_code_source
   * field of the PhoneNumber object passed in. If such information is missing,
   * the number will be formatted into the NATIONAL format by default. When the
   * number contains a leading zero and this is unexpected for this country, or we
   * don't have a formatting pattern for the number, the method returns the raw
   * input when it is available.
   *
   * Note this method guarantees no digit will be inserted, removed or modified as
   * a result of formatting.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to
   *     be formatted in its original number format.
   * @param {string} regionCallingFrom the region whose IDD needs to be prefixed
   *     if the original number has one.
   * @return {string} the formatted phone number in its original number format.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formatInOriginalFormat =
      function(number, regionCallingFrom) {
  
    if (number.hasRawInput() &&
        (this.hasUnexpectedItalianLeadingZero_(number) ||
         !this.hasFormattingPatternForNumber_(number))) {
      // We check if we have the formatting pattern because without that, we might
      // format the number as a group without national prefix.
      return number.getRawInputOrDefault();
    }
    if (!number.hasCountryCodeSource()) {
      return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
    }
    /** @type {string} */
    var formattedNumber;
    switch (number.getCountryCodeSource()) {
      case i18n.phonenumbers.PhoneNumber.CountryCodeSource
          .FROM_NUMBER_WITH_PLUS_SIGN:
        formattedNumber = this.format(number,
            i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
        break;
      case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD:
        formattedNumber =
            this.formatOutOfCountryCallingNumber(number, regionCallingFrom);
        break;
      case i18n.phonenumbers.PhoneNumber.CountryCodeSource
          .FROM_NUMBER_WITHOUT_PLUS_SIGN:
        formattedNumber = this.format(number,
            i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL).substring(1);
        break;
      case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY:
        // Fall-through to default case.
      default:
        /** @type {string} */
        var regionCode =
            this.getRegionCodeForCountryCode(number.getCountryCodeOrDefault());
        // We strip non-digits from the NDD here, and from the raw input later,
        // so that we can compare them easily.
        /** @type {?string} */
        var nationalPrefix = this.getNddPrefixForRegion(regionCode, true);
        /** @type {string} */
        var nationalFormat =
            this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
        if (nationalPrefix == null || nationalPrefix.length == 0) {
          // If the region doesn't have a national prefix at all, we can safely
          // return the national format without worrying about a national prefix
          // being added.
          formattedNumber = nationalFormat;
          break;
        }
        // Otherwise, we check if the original number was entered with a national
        // prefix.
        if (this.rawInputContainsNationalPrefix_(
            number.getRawInputOrDefault(), nationalPrefix, regionCode)) {
          // If so, we can safely return the national format.
          formattedNumber = nationalFormat;
          break;
        }
        // Metadata cannot be null here because getNddPrefixForRegion() (above)
        // returns null if there is no metadata for the region.
        /** @type {i18n.phonenumbers.PhoneMetadata} */
        var metadata = this.getMetadataForRegion(regionCode);
        /** @type {string} */
        var nationalNumber = this.getNationalSignificantNumber(number);
        /** @type {i18n.phonenumbers.NumberFormat} */
        var formatRule = this.chooseFormattingPatternForNumber_(
            metadata.numberFormatArray(), nationalNumber);
        // The format rule could still be null here if the national number was 0
        // and there was no raw input (this should not be possible for numbers
        // generated by the phonenumber library as they would also not have a
        // country calling code and we would have exited earlier).
        if (formatRule == null) {
          formattedNumber = nationalFormat;
          break;
        }
        // When the format we apply to this number doesn't contain national
        // prefix, we can just return the national format.
        // TODO: Refactor the code below with the code in
        // isNationalPrefixPresentIfRequired.
        /** @type {string} */
        var candidateNationalPrefixRule =
            formatRule.getNationalPrefixFormattingRuleOrDefault();
        // We assume that the first-group symbol will never be _before_ the
        // national prefix.
        /** @type {number} */
        var indexOfFirstGroup = candidateNationalPrefixRule.indexOf('$1');
        if (indexOfFirstGroup <= 0) {
          formattedNumber = nationalFormat;
          break;
        }
        candidateNationalPrefixRule =
            candidateNationalPrefixRule.substring(0, indexOfFirstGroup);
        candidateNationalPrefixRule = i18n.phonenumbers.PhoneNumberUtil
            .normalizeDigitsOnly(candidateNationalPrefixRule);
        if (candidateNationalPrefixRule.length == 0) {
          // National prefix not used when formatting this number.
          formattedNumber = nationalFormat;
          break;
        }
        // Otherwise, we need to remove the national prefix from our output.
        /** @type {i18n.phonenumbers.NumberFormat} */
        var numFormatCopy = formatRule.clone();
        numFormatCopy.clearNationalPrefixFormattingRule();
        formattedNumber = this.formatByPattern(number,
            i18n.phonenumbers.PhoneNumberFormat.NATIONAL, [numFormatCopy]);
        break;
    }
    /** @type {string} */
    var rawInput = number.getRawInputOrDefault();
    // If no digit is inserted/removed/modified as a result of our formatting, we
    // return the formatted phone number; otherwise we return the raw input the
    // user entered.
    if (formattedNumber != null && rawInput.length > 0) {
      /** @type {string} */
      var normalizedFormattedNumber =
          i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(formattedNumber,
              i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_,
              true /* remove non matches */);
      /** @type {string} */
      var normalizedRawInput =
          i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(rawInput,
              i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_,
              true /* remove non matches */);
      if (normalizedFormattedNumber != normalizedRawInput) {
        formattedNumber = rawInput;
      }
    }
    return formattedNumber;
  };
  
  
  /**
   * Check if rawInput, which is assumed to be in the national format, has a
   * national prefix. The national prefix is assumed to be in digits-only form.
   * @param {string} rawInput
   * @param {string} nationalPrefix
   * @param {string} regionCode
   * @return {boolean}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.rawInputContainsNationalPrefix_ =
      function(rawInput, nationalPrefix, regionCode) {
  
    /** @type {string} */
    var normalizedNationalNumber =
        i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(rawInput);
    if (goog.string.startsWith(normalizedNationalNumber, nationalPrefix)) {
      try {
        // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the
        // national prefix when written without it (e.g. 0777123) if we just do
        // prefix matching. To tackle that, we check the validity of the number if
        // the assumed national prefix is removed (777123 won't be valid in
        // Japan).
        return this.isValidNumber(
            this.parse(normalizedNationalNumber.substring(nationalPrefix.length),
                       regionCode));
      } catch (e) {
        return false;
      }
    }
    return false;
  };
  
  
  /**
   * Returns true if a number is from a region whose national significant number
   * couldn't contain a leading zero, but has the italian_leading_zero field set
   * to true.
   * @param {i18n.phonenumbers.PhoneNumber} number
   * @return {boolean}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.hasUnexpectedItalianLeadingZero_ =
      function(number) {
  
    return number.hasItalianLeadingZero() &&
        !this.isLeadingZeroPossible(number.getCountryCodeOrDefault());
  };
  
  
  /**
   * @param {i18n.phonenumbers.PhoneNumber} number
   * @return {boolean}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.hasFormattingPatternForNumber_ =
      function(number) {
  
    /** @type {number} */
    var countryCallingCode = number.getCountryCodeOrDefault();
    /** @type {string} */
    var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCallingCode);
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.getMetadataForRegionOrCallingCode_(
        countryCallingCode, phoneNumberRegion);
    if (metadata == null) {
      return false;
    }
    /** @type {string} */
    var nationalNumber = this.getNationalSignificantNumber(number);
    /** @type {i18n.phonenumbers.NumberFormat} */
    var formatRule = this.chooseFormattingPatternForNumber_(
        metadata.numberFormatArray(), nationalNumber);
    return formatRule != null;
  };
  
  
  /**
   * Formats a phone number for out-of-country dialing purposes.
   *
   * Note that in this version, if the number was entered originally using alpha
   * characters and this version of the number is stored in raw_input, this
   * representation of the number will be used rather than the digit
   * representation. Grouping information, as specified by characters such as '-'
   * and ' ', will be retained.
   *
   * <p><b>Caveats:</b></p>
   * <ul>
   * <li>This will not produce good results if the country calling code is both
   * present in the raw input _and_ is the start of the national number. This is
   * not a problem in the regions which typically use alpha numbers.
   * <li>This will also not produce good results if the raw input has any grouping
   * information within the first three digits of the national number, and if the
   * function needs to strip preceding digits/words in the raw input before these
   * digits. Normally people group the first three digits together so this is not
   * a huge problem - and will be fixed if it proves to be so.
   * </ul>
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to
   *     be formatted.
   * @param {string} regionCallingFrom the region where the call is being placed.
   * @return {string} the formatted phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      formatOutOfCountryKeepingAlphaChars = function(number, regionCallingFrom) {
    /** @type {string} */
    var rawInput = number.getRawInputOrDefault();
    // If there is no raw input, then we can't keep alpha characters because there
    // aren't any. In this case, we return formatOutOfCountryCallingNumber.
    if (rawInput.length == 0) {
      return this.formatOutOfCountryCallingNumber(number, regionCallingFrom);
    }
    /** @type {number} */
    var countryCode = number.getCountryCodeOrDefault();
    if (!this.hasValidCountryCallingCode_(countryCode)) {
      return rawInput;
    }
    // Strip any prefix such as country calling code, IDD, that was present. We do
    // this by comparing the number in raw_input with the parsed number. To do
    // this, first we normalize punctuation. We retain number grouping symbols
    // such as ' ' only.
    rawInput = i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(
        rawInput,
        i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_,
        true);
    // Now we trim everything before the first three digits in the parsed number.
    // We choose three because all valid alpha numbers have 3 digits at the start
    // - if it does not, then we don't trim anything at all. Similarly, if the
    // national number was less than three digits, we don't trim anything at all.
    /** @type {string} */
    var nationalNumber = this.getNationalSignificantNumber(number);
    if (nationalNumber.length > 3) {
      /** @type {number} */
      var firstNationalNumberDigit =
          rawInput.indexOf(nationalNumber.substring(0, 3));
      if (firstNationalNumberDigit != -1) {
        rawInput = rawInput.substring(firstNationalNumberDigit);
      }
    }
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadataForRegionCallingFrom =
        this.getMetadataForRegion(regionCallingFrom);
    if (countryCode == i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
      if (this.isNANPACountry(regionCallingFrom)) {
        return countryCode + ' ' + rawInput;
      }
    } else if (metadataForRegionCallingFrom != null &&
        countryCode == this.getCountryCodeForValidRegion_(regionCallingFrom)) {
      /** @type {i18n.phonenumbers.NumberFormat} */
      var formattingPattern = this.chooseFormattingPatternForNumber_(
          metadataForRegionCallingFrom.numberFormatArray(), nationalNumber);
      if (formattingPattern == null) {
        // If no pattern above is matched, we format the original input.
        return rawInput;
      }
      /** @type {i18n.phonenumbers.NumberFormat} */
      var newFormat = formattingPattern.clone();
      // The first group is the first group of digits that the user wrote
      // together.
      newFormat.setPattern('(\\d+)(.*)');
      // Here we just concatenate them back together after the national prefix
      // has been fixed.
      newFormat.setFormat('$1$2');
      // Now we format using this pattern instead of the default pattern, but
      // with the national prefix prefixed if necessary.
      // This will not work in the cases where the pattern (and not the leading
      // digits) decide whether a national prefix needs to be used, since we have
      // overridden the pattern to match anything, but that is not the case in the
      // metadata to date.
      return this.formatNsnUsingPattern_(rawInput, newFormat,
          i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
    }
    /** @type {string} */
    var internationalPrefixForFormatting = '';
    // If an unsupported region-calling-from is entered, or a country with
    // multiple international prefixes, the international format of the number is
    // returned, unless there is a preferred international prefix.
    if (metadataForRegionCallingFrom != null) {
      /** @type {string} */
      var internationalPrefix =
          metadataForRegionCallingFrom.getInternationalPrefixOrDefault();
      internationalPrefixForFormatting =
          i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
              i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_,
              internationalPrefix) ?
          internationalPrefix :
          metadataForRegionCallingFrom.getPreferredInternationalPrefixOrDefault();
    }
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCode);
    // Metadata cannot be null because the country calling code is valid.
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadataForRegion =
        this.getMetadataForRegionOrCallingCode_(countryCode, regionCode);
    /** @type {string} */
    var formattedExtension = this.maybeGetFormattedExtension_(
        number, metadataForRegion,
        i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
    if (internationalPrefixForFormatting.length > 0) {
      return internationalPrefixForFormatting + ' ' + countryCode + ' ' +
          rawInput + formattedExtension;
    } else {
      // Invalid region entered as country-calling-from (so no metadata was found
      // for it) or the region chosen has multiple international dialling
      // prefixes.
      return this.prefixNumberWithCountryCallingCode_(
          countryCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
          rawInput, formattedExtension);
    }
  };
  
  
  /**
   * Gets the national significant number of the a phone number. Note a national
   * significant number doesn't contain a national prefix or any formatting.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number for which the
   *     national significant number is needed.
   * @return {string} the national significant number of the PhoneNumber object
   *     passed in.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getNationalSignificantNumber =
      function(number) {
  
    // If leading zero(s) have been set, we prefix this now. Note this is not a
    // national prefix.
    /** @type {string} */
    var nationalNumber = '' + number.getNationalNumber();
    if (number.hasItalianLeadingZero() && number.getItalianLeadingZero()) {
      return Array(number.getNumberOfLeadingZerosOrDefault() + 1).join('0') +
          nationalNumber;
    }
    return nationalNumber;
  };
  
  
  /**
   * A helper function that is used by format and formatByPattern.
   *
   * @param {number} countryCallingCode the country calling code.
   * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
   *     phone number should be formatted into.
   * @param {string} formattedNationalNumber
   * @param {string} formattedExtension
   * @return {string} the formatted phone number.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      prefixNumberWithCountryCallingCode_ = function(countryCallingCode,
                                                     numberFormat,
                                                     formattedNationalNumber,
                                                     formattedExtension) {
  
    switch (numberFormat) {
      case i18n.phonenumbers.PhoneNumberFormat.E164:
        return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode +
            formattedNationalNumber + formattedExtension;
      case i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL:
        return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode +
            ' ' + formattedNationalNumber + formattedExtension;
      case i18n.phonenumbers.PhoneNumberFormat.RFC3966:
        return i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ +
            i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode +
            '-' + formattedNationalNumber + formattedExtension;
      case i18n.phonenumbers.PhoneNumberFormat.NATIONAL:
      default:
        return formattedNationalNumber + formattedExtension;
    }
  };
  
  
  /**
   * Note in some regions, the national number can be written in two completely
   * different ways depending on whether it forms part of the NATIONAL format or
   * INTERNATIONAL format. The numberFormat parameter here is used to specify
   * which format to use for those cases. If a carrierCode is specified, this will
   * be inserted into the formatted string to replace $CC.
   *
   * @param {string} number a string of characters representing a phone number.
   * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
   *     region that we think this number is from.
   * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
   *     phone number should be formatted into.
   * @param {string=} opt_carrierCode
   * @return {string} the formatted phone number.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formatNsn_ =
      function(number, metadata, numberFormat, opt_carrierCode) {
  
    /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
    var intlNumberFormats = metadata.intlNumberFormatArray();
    // When the intlNumberFormats exists, we use that to format national number
    // for the INTERNATIONAL format instead of using the numberDesc.numberFormats.
    /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
    var availableFormats =
        (intlNumberFormats.length == 0 ||
            numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL) ?
        metadata.numberFormatArray() : metadata.intlNumberFormatArray();
    /** @type {i18n.phonenumbers.NumberFormat} */
    var formattingPattern = this.chooseFormattingPatternForNumber_(
        availableFormats, number);
    return (formattingPattern == null) ?
        number :
        this.formatNsnUsingPattern_(number, formattingPattern,
                                    numberFormat, opt_carrierCode);
  };
  
  
  /**
   * @param {Array.<i18n.phonenumbers.NumberFormat>} availableFormats the
   *     available formats the phone number could be formatted into.
   * @param {string} nationalNumber a string of characters representing a phone
   *     number.
   * @return {i18n.phonenumbers.NumberFormat}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.chooseFormattingPatternForNumber_ =
      function(availableFormats, nationalNumber) {
  
    /** @type {i18n.phonenumbers.NumberFormat} */
    var numFormat;
    /** @type {number} */
    var l = availableFormats.length;
    for (var i = 0; i < l; ++i) {
      numFormat = availableFormats[i];
      /** @type {number} */
      var size = numFormat.leadingDigitsPatternCount();
      if (size == 0 ||
          // We always use the last leading_digits_pattern, as it is the most
          // detailed.
          nationalNumber
              .search(numFormat.getLeadingDigitsPattern(size - 1)) == 0) {
        /** @type {!RegExp} */
        var patternToMatch = new RegExp(numFormat.getPattern());
        if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(patternToMatch,
                                                               nationalNumber)) {
          return numFormat;
        }
      }
    }
    return null;
  };
  
  
  /**
   * Note that carrierCode is optional - if null or an empty string, no carrier
   * code replacement will take place.
   *
   * @param {string} nationalNumber a string of characters representing a phone
   *     number.
   * @param {i18n.phonenumbers.NumberFormat} formattingPattern the formatting rule
   *     the phone number should be formatted into.
   * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
   *     phone number should be formatted into.
   * @param {string=} opt_carrierCode
   * @return {string} the formatted phone number.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.formatNsnUsingPattern_ =
      function(nationalNumber, formattingPattern, numberFormat, opt_carrierCode) {
  
    /** @type {string} */
    var numberFormatRule = formattingPattern.getFormatOrDefault();
    /** @type {!RegExp} */
    var patternToMatch = new RegExp(formattingPattern.getPattern());
    /** @type {string} */
    var domesticCarrierCodeFormattingRule =
        formattingPattern.getDomesticCarrierCodeFormattingRuleOrDefault();
    /** @type {string} */
    var formattedNationalNumber = '';
    if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL &&
        opt_carrierCode != null && opt_carrierCode.length > 0 &&
        domesticCarrierCodeFormattingRule.length > 0) {
      // Replace the $CC in the formatting rule with the desired carrier code.
      /** @type {string} */
      var carrierCodeFormattingRule = domesticCarrierCodeFormattingRule
          .replace(i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_,
                   opt_carrierCode);
      // Now replace the $FG in the formatting rule with the first group and
      // the carrier code combined in the appropriate way.
      numberFormatRule = numberFormatRule.replace(
          i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
          carrierCodeFormattingRule);
      formattedNationalNumber =
          nationalNumber.replace(patternToMatch, numberFormatRule);
    } else {
      // Use the national prefix formatting rule instead.
      /** @type {string} */
      var nationalPrefixFormattingRule =
          formattingPattern.getNationalPrefixFormattingRuleOrDefault();
      if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL &&
          nationalPrefixFormattingRule != null &&
          nationalPrefixFormattingRule.length > 0) {
        formattedNationalNumber = nationalNumber.replace(patternToMatch,
            numberFormatRule.replace(
                i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
                nationalPrefixFormattingRule));
      } else {
        formattedNationalNumber =
            nationalNumber.replace(patternToMatch, numberFormatRule);
      }
    }
    if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.RFC3966) {
      // Strip any leading punctuation.
      formattedNationalNumber = formattedNationalNumber.replace(
          new RegExp('^' + i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_),
          '');
      // Replace the rest with a dash between each number group.
      formattedNationalNumber = formattedNationalNumber.replace(
          new RegExp(i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_, 'g'),
          '-');
    }
    return formattedNationalNumber;
  };
  
  
  /**
   * Gets a valid number for the specified region.
   *
   * @param {string} regionCode the region for which an example number is needed.
   * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the
   *     specified region. Returns null when the metadata does not contain such
   *     information, or the region 001 is passed in. For 001 (representing non-
   *     geographical numbers), call {@link #getExampleNumberForNonGeoEntity}
   *     instead.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumber =
      function(regionCode) {
  
    return this.getExampleNumberForType(regionCode,
        i18n.phonenumbers.PhoneNumberType.FIXED_LINE);
  };
  
  
  /**
   * Gets a valid number for the specified region and number type.
   *
   * @param {string} regionCode the region for which an example number is needed.
   * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is
   *     needed.
   * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified
   *     region and type. Returns null when the metadata does not contain such
   *     information or if an invalid region or region 001 was entered.
   *     For 001 (representing non-geographical numbers), call
   *     {@link #getExampleNumberForNonGeoEntity} instead.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForType =
      function(regionCode, type) {
  
    // Check the region code is valid.
    if (!this.isValidRegionCode_(regionCode)) {
      return null;
    }
    /** @type {i18n.phonenumbers.PhoneNumberDesc} */
    var desc = this.getNumberDescByType_(
        this.getMetadataForRegion(regionCode), type);
    try {
      if (desc.hasExampleNumber()) {
        return this.parse(desc.getExampleNumberOrDefault(), regionCode);
      }
    } catch (e) {
    }
    return null;
  };
  
  
  /**
   * Gets a valid number for the specified country calling code for a
   * non-geographical entity.
   *
   * @param {number} countryCallingCode the country calling code for a
   *     non-geographical entity.
   * @return {i18n.phonenumbers.PhoneNumber} a valid number for the
   *     non-geographical entity. Returns null when the metadata does not contain
   *     such information, or the country calling code passed in does not belong
   *     to a non-geographical entity.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForNonGeoEntity =
      function(countryCallingCode) {
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata =
        this.getMetadataForNonGeographicalRegion(countryCallingCode);
    if (metadata != null) {
      /** @type {i18n.phonenumbers.PhoneNumberDesc} */
      var desc = metadata.getGeneralDesc();
      try {
        if (desc.hasExampleNumber()) {
          return this.parse('+' + countryCallingCode + desc.getExampleNumber(),
                            'ZZ');
        }
      } catch (e) {
      }
    }
    return null;
  };
  
  
  /**
   * Gets the formatted extension of a phone number, if the phone number had an
   * extension specified. If not, it returns an empty string.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have
   *     an extension.
   * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
   *     region that we think this number is from.
   * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
   *     phone number should be formatted into.
   * @return {string} the formatted extension if any.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.maybeGetFormattedExtension_ =
      function(number, metadata, numberFormat) {
  
    if (!number.hasExtension() || number.getExtension().length == 0) {
      return '';
    } else {
      if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.RFC3966) {
        return i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ +
            number.getExtension();
      } else {
        if (metadata.hasPreferredExtnPrefix()) {
          return metadata.getPreferredExtnPrefix() +
              number.getExtensionOrDefault();
        } else {
          return i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ +
              number.getExtensionOrDefault();
        }
      }
    }
  };
  
  
  /**
   * @param {i18n.phonenumbers.PhoneMetadata} metadata
   * @param {i18n.phonenumbers.PhoneNumberType} type
   * @return {i18n.phonenumbers.PhoneNumberDesc}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberDescByType_ =
      function(metadata, type) {
  
    switch (type) {
      case i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE:
        return metadata.getPremiumRate();
      case i18n.phonenumbers.PhoneNumberType.TOLL_FREE:
        return metadata.getTollFree();
      case i18n.phonenumbers.PhoneNumberType.MOBILE:
        return metadata.getMobile();
      case i18n.phonenumbers.PhoneNumberType.FIXED_LINE:
      case i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE:
        return metadata.getFixedLine();
      case i18n.phonenumbers.PhoneNumberType.SHARED_COST:
        return metadata.getSharedCost();
      case i18n.phonenumbers.PhoneNumberType.VOIP:
        return metadata.getVoip();
      case i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER:
        return metadata.getPersonalNumber();
      case i18n.phonenumbers.PhoneNumberType.PAGER:
        return metadata.getPager();
      case i18n.phonenumbers.PhoneNumberType.UAN:
        return metadata.getUan();
      case i18n.phonenumbers.PhoneNumberType.VOICEMAIL:
        return metadata.getVoicemail();
      default:
        return metadata.getGeneralDesc();
    }
  };
  
  
  /**
   * Gets the type of a phone number.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
   *     to know the type.
   * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberType =
      function(number) {
  
    /** @type {?string} */
    var regionCode = this.getRegionCodeForNumber(number);
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.getMetadataForRegionOrCallingCode_(
        number.getCountryCodeOrDefault(), regionCode);
    if (metadata == null) {
      return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
    }
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
    return this.getNumberTypeHelper_(nationalSignificantNumber, metadata);
  };
  
  
  /**
   * @param {string} nationalNumber
   * @param {i18n.phonenumbers.PhoneMetadata} metadata
   * @return {i18n.phonenumbers.PhoneNumberType}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberTypeHelper_ =
      function(nationalNumber, metadata) {
  
    if (!this.isNumberMatchingDesc_(nationalNumber, metadata.getGeneralDesc())) {
      return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
    }
  
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPremiumRate())) {
      return i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE;
    }
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getTollFree())) {
      return i18n.phonenumbers.PhoneNumberType.TOLL_FREE;
    }
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getSharedCost())) {
      return i18n.phonenumbers.PhoneNumberType.SHARED_COST;
    }
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoip())) {
      return i18n.phonenumbers.PhoneNumberType.VOIP;
    }
    if (this.isNumberMatchingDesc_(nationalNumber,
                                   metadata.getPersonalNumber())) {
      return i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER;
    }
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPager())) {
      return i18n.phonenumbers.PhoneNumberType.PAGER;
    }
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getUan())) {
      return i18n.phonenumbers.PhoneNumberType.UAN;
    }
    if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoicemail())) {
      return i18n.phonenumbers.PhoneNumberType.VOICEMAIL;
    }
  
    /** @type {boolean} */
    var isFixedLine = this.isNumberMatchingDesc_(nationalNumber, metadata
        .getFixedLine());
    if (isFixedLine) {
      if (metadata.getSameMobileAndFixedLinePattern()) {
        return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
      } else if (this.isNumberMatchingDesc_(nationalNumber,
                                            metadata.getMobile())) {
        return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
      }
      return i18n.phonenumbers.PhoneNumberType.FIXED_LINE;
    }
    // Otherwise, test to see if the number is mobile. Only do this if certain
    // that the patterns for mobile and fixed line aren't the same.
    if (!metadata.getSameMobileAndFixedLinePattern() &&
        this.isNumberMatchingDesc_(nationalNumber, metadata.getMobile())) {
      return i18n.phonenumbers.PhoneNumberType.MOBILE;
    }
    return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
  };
  
  
  /**
   * Returns the metadata for the given region code or {@code null} if the region
   * code is invalid or unknown.
   *
   * @param {?string} regionCode
   * @return {i18n.phonenumbers.PhoneMetadata}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegion =
      function(regionCode) {
  
    if (regionCode == null) {
      return null;
    }
    regionCode = regionCode.toUpperCase();
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.regionToMetadataMap[regionCode];
    if (metadata == null) {
      /** @type {goog.proto2.PbLiteSerializer} */
      var serializer = new goog.proto2.PbLiteSerializer();
      /** @type {Array} */
      var metadataSerialized =
          i18n.phonenumbers.metadata.countryToMetadata[regionCode];
      if (metadataSerialized == null) {
        return null;
      }
      metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ (
          serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(),
              metadataSerialized));
      this.regionToMetadataMap[regionCode] = metadata;
    }
    return metadata;
  };
  
  
  /**
   * @param {number} countryCallingCode
   * @return {i18n.phonenumbers.PhoneMetadata}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      getMetadataForNonGeographicalRegion = function(countryCallingCode) {
  
    return this.getMetadataForRegion('' + countryCallingCode);
  };
  
  
  /**
   * @param {string} nationalNumber
   * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc
   * @return {boolean}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatchingDesc_ =
      function(nationalNumber, numberDesc) {
    // Check if any possible number lengths are present; if so, we use them to
    // avoid checking the validation pattern if they don't match. If they are
    // absent, this means they match the general description, which we have
    // already checked before a specific number type.
    var actualLength = nationalNumber.length;
    if (numberDesc.possibleLengthCount() > 0 &&
        goog.array.indexOf(numberDesc.possibleLengthArray(),
            actualLength) == -1) {
      return false;
    }
    return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
        numberDesc.getNationalNumberPatternOrDefault(), nationalNumber);
  };
  
  
  /**
   * Tests whether a phone number matches a valid pattern. Note this doesn't
   * verify the number is actually in use, which is impossible to tell by just
   * looking at a number itself.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
   *     to validate.
   * @return {boolean} a boolean that indicates whether the number is of a valid
   *     pattern.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumber = function(number) {
    /** @type {?string} */
    var regionCode = this.getRegionCodeForNumber(number);
    return this.isValidNumberForRegion(number, regionCode);
  };
  
  
  /**
   * Tests whether a phone number is valid for a certain region. Note this doesn't
   * verify the number is actually in use, which is impossible to tell by just
   * looking at a number itself. If the country calling code is not the same as
   * the country calling code for the region, this immediately exits with false.
   * After this, the specific number pattern rules for the region are examined.
   * This is useful for determining for example whether a particular number is
   * valid for Canada, rather than just a valid NANPA number.
   * Warning: In most cases, you want to use {@link #isValidNumber} instead. For
   * example, this method will mark numbers from British Crown dependencies such
   * as the Isle of Man as invalid for the region "GB" (United Kingdom), since it
   * has its own region code, "IM", which may be undesirable.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
   *     to validate.
   * @param {?string} regionCode the region that we want to validate the phone
   *     number for.
   * @return {boolean} a boolean that indicates whether the number is of a valid
   *     pattern.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumberForRegion =
      function(number, regionCode) {
  
    /** @type {number} */
    var countryCode = number.getCountryCodeOrDefault();
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata =
        this.getMetadataForRegionOrCallingCode_(countryCode, regionCode);
    if (metadata == null ||
        (i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY !=
         regionCode &&
         countryCode != this.getCountryCodeForValidRegion_(regionCode))) {
      // Either the region code was invalid, or the country calling code for this
      // number does not match that of the region code.
      return false;
    }
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
  
    return this.getNumberTypeHelper_(nationalSignificantNumber, metadata) !=
        i18n.phonenumbers.PhoneNumberType.UNKNOWN;
  };
  
  
  /**
   * Returns the region where a phone number is from. This could be used for
   * geocoding at the region level.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone number whose origin
   *     we want to know.
   * @return {?string} the region where the phone number is from, or null
   *     if no region matches this calling code.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForNumber =
      function(number) {
  
    if (number == null) {
      return null;
    }
    /** @type {number} */
    var countryCode = number.getCountryCodeOrDefault();
    /** @type {Array.<string>} */
    var regions =
        i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode];
    if (regions == null) {
      return null;
    }
    if (regions.length == 1) {
      return regions[0];
    } else {
      return this.getRegionCodeForNumberFromRegionList_(number, regions);
    }
  };
  
  
  /**
   * @param {i18n.phonenumbers.PhoneNumber} number
   * @param {Array.<string>} regionCodes
   * @return {?string}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      getRegionCodeForNumberFromRegionList_ = function(number, regionCodes) {
  
    /** @type {string} */
    var nationalNumber = this.getNationalSignificantNumber(number);
    /** @type {string} */
    var regionCode;
    /** @type {number} */
    var regionCodesLength = regionCodes.length;
    for (var i = 0; i < regionCodesLength; i++) {
      regionCode = regionCodes[i];
      // If leadingDigits is present, use this. Otherwise, do full validation.
      // Metadata cannot be null because the region codes come from the country
      // calling code map.
      /** @type {i18n.phonenumbers.PhoneMetadata} */
      var metadata = this.getMetadataForRegion(regionCode);
      if (metadata.hasLeadingDigits()) {
        if (nationalNumber.search(metadata.getLeadingDigits()) == 0) {
          return regionCode;
        }
      } else if (this.getNumberTypeHelper_(nationalNumber, metadata) !=
          i18n.phonenumbers.PhoneNumberType.UNKNOWN) {
        return regionCode;
      }
    }
    return null;
  };
  
  
  /**
   * Returns the region code that matches the specific country calling code. In
   * the case of no region code being found, ZZ will be returned. In the case of
   * multiple regions, the one designated in the metadata as the 'main' region for
   * this calling code will be returned.
   *
   * @param {number} countryCallingCode the country calling code.
   * @return {string}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForCountryCode =
      function(countryCallingCode) {
  
    /** @type {Array.<string>} */
    var regionCodes =
        i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCallingCode];
    return regionCodes == null ?
        i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ : regionCodes[0];
  };
  
  
  /**
   * Returns a list with the region codes that match the specific country calling
   * code. For non-geographical country calling codes, the region code 001 is
   * returned. Also, in the case of no region code being found, an empty list is
   * returned.
   *
   * @param {number} countryCallingCode the country calling code.
   * @return {Array.<string>}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodesForCountryCode =
      function(countryCallingCode) {
  
    /** @type {Array.<string>} */
    var regionCodes =
        i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCallingCode];
    return regionCodes == null ? [] : regionCodes;
  };
  
  
  /**
   * Returns the country calling code for a specific region. For example, this
   * would be 1 for the United States, and 64 for New Zealand.
   *
   * @param {?string} regionCode the region that we want to get the country
   *     calling code for.
   * @return {number} the country calling code for the region denoted by
   *     regionCode.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForRegion =
      function(regionCode) {
  
    if (!this.isValidRegionCode_(regionCode)) {
      return 0;
    }
    return this.getCountryCodeForValidRegion_(regionCode);
  };
  
  
  /**
   * Returns the country calling code for a specific region. For example, this
   * would be 1 for the United States, and 64 for New Zealand. Assumes the region
   * is already valid.
   *
   * @param {?string} regionCode the region that we want to get the country
   *     calling code for.
   * @return {number} the country calling code for the region denoted by
   *     regionCode.
   * @throws {string} if the region is invalid
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForValidRegion_ =
      function(regionCode) {
  
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.getMetadataForRegion(regionCode);
    if (metadata == null) {
      throw 'Invalid region code: ' + regionCode;
    }
    return metadata.getCountryCodeOrDefault();
  };
  
  
  /**
   * Returns the national dialling prefix for a specific region. For example, this
   * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits
   * to true to strip symbols like '~' (which indicates a wait for a dialling
   * tone) from the prefix returned. If no national prefix is present, we return
   * null.
   *
   * <p>Warning: Do not use this method for do-your-own formatting - for some
   * regions, the national dialling prefix is used only for certain types of
   * numbers. Use the library's formatting functions to prefix the national prefix
   * when required.
   *
   * @param {?string} regionCode the region that we want to get the dialling
   *     prefix for.
   * @param {boolean} stripNonDigits true to strip non-digits from the national
   *     dialling prefix.
   * @return {?string} the dialling prefix for the region denoted by
   *     regionCode.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.getNddPrefixForRegion = function(
      regionCode, stripNonDigits) {
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.getMetadataForRegion(regionCode);
    if (metadata == null) {
      return null;
    }
    /** @type {string} */
    var nationalPrefix = metadata.getNationalPrefixOrDefault();
    // If no national prefix was found, we return null.
    if (nationalPrefix.length == 0) {
      return null;
    }
    if (stripNonDigits) {
      // Note: if any other non-numeric symbols are ever used in national
      // prefixes, these would have to be removed here as well.
      nationalPrefix = nationalPrefix.replace('~', '');
    }
    return nationalPrefix;
  };
  
  
  /**
   * Checks if this is a region under the North American Numbering Plan
   * Administration (NANPA).
   *
   * @param {?string} regionCode the ISO 3166-1 two-letter region code.
   * @return {boolean} true if regionCode is one of the regions under NANPA.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isNANPACountry =
      function(regionCode) {
  
    return regionCode != null && goog.array.contains(
        i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[
            i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_],
        regionCode.toUpperCase());
  };
  
  
  /**
   * Checks whether countryCode represents the country calling code from a region
   * whose national significant number could contain a leading zero. An example of
   * such a region is Italy. Returns false if no metadata for the country is
   * found.
   *
   * @param {number} countryCallingCode the country calling code.
   * @return {boolean}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isLeadingZeroPossible =
      function(countryCallingCode) {
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var mainMetadataForCallingCode = this.getMetadataForRegionOrCallingCode_(
        countryCallingCode,
        this.getRegionCodeForCountryCode(countryCallingCode));
    return mainMetadataForCallingCode != null &&
        mainMetadataForCallingCode.getLeadingZeroPossibleOrDefault();
  };
  
  
  /**
   * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT.
   * A valid vanity number will start with at least 3 digits and will have three
   * or more alpha characters. This does not do region-specific checks - to work
   * out if this number is actually valid for a region, it should be parsed and
   * methods such as {@link #isPossibleNumberWithReason} and
   * {@link #isValidNumber} should be used.
   *
   * @param {string} number the number that needs to be checked.
   * @return {boolean} true if the number is a valid vanity number.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isAlphaNumber = function(number) {
    if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(number)) {
      // Number is too short, or doesn't match the basic phone number pattern.
      return false;
    }
    /** @type {!goog.string.StringBuffer} */
    var strippedNumber = new goog.string.StringBuffer(number);
    this.maybeStripExtension(strippedNumber);
    return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
        i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_,
        strippedNumber.toString());
  };
  
  
  /**
   * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of
   * returning the reason for failure, this method returns a boolean value.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
   *     checked.
   * @return {boolean} true if the number is possible.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumber =
      function(number) {
  
    return this.isPossibleNumberWithReason(number) ==
        i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
  };
  
  
  /**
   * Helper method to check a number against a particular pattern and determine
   * whether it matches, or is too short or too long. Currently, if a number
   * pattern suggests that numbers of length 7 and 10 are possible, and a number
   * in between these possible lengths is entered, such as of length 8, this will
   * return TOO_LONG.
   *
   * @param {string} number
   * @param {i18n.phonenumbers.PhoneNumberDesc} phoneNumberDesc
   * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.testNumberLength_ =
      function(number, phoneNumberDesc) {
    var possibleLengths = phoneNumberDesc.possibleLengthArray();
    var localLengths = phoneNumberDesc.possibleLengthLocalOnlyArray();
    var actualLength = number.length;
    if (goog.array.indexOf(localLengths, actualLength) > -1) {
      return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
    }
    // There should always be "possibleLengths" set for every element. This will
    // be a build-time check once ShortNumberMetadata.xml is migrated to contain
    // this information as well.
    var minimumLength = possibleLengths[0];
    if (minimumLength == actualLength) {
      return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
    } else if (minimumLength > actualLength) {
      return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
    } else if (possibleLengths[possibleLengths.length - 1] < actualLength) {
      return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
    }
    // Note that actually the number is not too long if possible_lengths does not
    // contain the length: we know it is less than the highest possible number
    // length, and higher than the lowest possible number length. However, we
    // don't currently have an enum to express this, so we return TOO_LONG in the
    // short-term.
    // We skip the first element since we've already checked it.
    return (goog.array.indexOf(possibleLengths, actualLength, 1) > -1) ?
        i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE :
        i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
  };
  
  
  /**
   * Check whether a phone number is a possible number. It provides a more lenient
   * check than {@link #isValidNumber} in the following sense:
   * <ol>
   * <li>It only checks the length of phone numbers. In particular, it doesn't
   * check starting digits of the number.
   * <li>It doesn't attempt to figure out the type of the number, but uses general
   * rules which applies to all types of phone numbers in a region. Therefore, it
   * is much faster than isValidNumber.
   * <li>For fixed line numbers, many regions have the concept of area code, which
   * together with subscriber number constitute the national significant number.
   * It is sometimes okay to dial the subscriber number only when dialing in the
   * same area. This function will return true if the subscriber-number-only
   * version is passed in. On the other hand, because isValidNumber validates
   * using information on both starting digits (for fixed line numbers, that would
   * most likely be area codes) and length (obviously includes the length of area
   * codes for fixed line numbers), it will return false for the
   * subscriber-number-only version.
   * </ol>
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
   *     checked.
   * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} a
   *     ValidationResult object which indicates whether the number is possible.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason =
      function(number) {
  
    /** @type {string} */
    var nationalNumber = this.getNationalSignificantNumber(number);
    /** @type {number} */
    var countryCode = number.getCountryCodeOrDefault();
    // Note: For Russian Fed and NANPA numbers, we just use the rules from the
    // default region (US or Russia) since the getRegionCodeForNumber will not
    // work if the number is possible but not valid. This would need to be
    // revisited if the possible number pattern ever differed between various
    // regions within those plans.
    if (!this.hasValidCountryCallingCode_(countryCode)) {
      return i18n.phonenumbers.PhoneNumberUtil.ValidationResult
          .INVALID_COUNTRY_CODE;
    }
    /** @type {string} */
    var regionCode = this.getRegionCodeForCountryCode(countryCode);
    // Metadata cannot be null because the country calling code is valid.
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata =
        this.getMetadataForRegionOrCallingCode_(countryCode, regionCode);
    return this.testNumberLength_(nationalNumber, metadata.getGeneralDesc());
  };
  
  
  /**
   * Check whether a phone number is a possible number given a number in the form
   * of a string, and the region where the number could be dialed from. It
   * provides a more lenient check than {@link #isValidNumber}. See
   * {@link #isPossibleNumber} for details.
   *
   * <p>This method first parses the number, then invokes
   * {@link #isPossibleNumber} with the resultant PhoneNumber object.
   *
   * @param {string} number the number that needs to be checked, in the form of a
   *     string.
   * @param {string} regionDialingFrom the region that we are expecting the number
   *     to be dialed from.
   *     Note this is different from the region where the number belongs.
   *     For example, the number +1 650 253 0000 is a number that belongs to US.
   *     When written in this form, it can be dialed from any region. When it is
   *     written as 00 1 650 253 0000, it can be dialed from any region which uses
   *     an international dialling prefix of 00. When it is written as
   *     650 253 0000, it can only be dialed from within the US, and when written
   *     as 253 0000, it can only be dialed from within a smaller area in the US
   *     (Mountain View, CA, to be more specific).
   * @return {boolean} true if the number is possible.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberString =
      function(number, regionDialingFrom) {
  
    try {
      return this.isPossibleNumber(this.parse(number, regionDialingFrom));
    } catch (e) {
      return false;
    }
  };
  
  
  /**
   * Attempts to extract a valid number from a phone number that is too long to be
   * valid, and resets the PhoneNumber object passed in to that valid version. If
   * no valid number could be extracted, the PhoneNumber object passed in will not
   * be modified.
   * @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which
   *     contains a number that is too long to be valid.
   * @return {boolean} true if a valid phone number can be successfully extracted.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.truncateTooLongNumber =
      function(number) {
  
    if (this.isValidNumber(number)) {
      return true;
    }
    /** @type {i18n.phonenumbers.PhoneNumber} */
    var numberCopy = number.clone();
    /** @type {number} */
    var nationalNumber = number.getNationalNumberOrDefault();
    do {
      nationalNumber = Math.floor(nationalNumber / 10);
      numberCopy.setNationalNumber(nationalNumber);
      if (nationalNumber == 0 ||
          this.isPossibleNumberWithReason(numberCopy) ==
              i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
        return false;
      }
    } while (!this.isValidNumber(numberCopy));
    number.setNationalNumber(nationalNumber);
    return true;
  };
  
  
  /**
   * Extracts country calling code from fullNumber, returns it and places the
   * remaining number in nationalNumber. It assumes that the leading plus sign or
   * IDD has already been removed. Returns 0 if fullNumber doesn't start with a
   * valid country calling code, and leaves nationalNumber unmodified.
   *
   * @param {!goog.string.StringBuffer} fullNumber
   * @param {!goog.string.StringBuffer} nationalNumber
   * @return {number}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.extractCountryCode =
      function(fullNumber, nationalNumber) {
  
    /** @type {string} */
    var fullNumberStr = fullNumber.toString();
    if ((fullNumberStr.length == 0) || (fullNumberStr.charAt(0) == '0')) {
      // Country codes do not begin with a '0'.
      return 0;
    }
    /** @type {number} */
    var potentialCountryCode;
    /** @type {number} */
    var numberLength = fullNumberStr.length;
    for (var i = 1;
        i <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ &&
        i <= numberLength; ++i) {
      potentialCountryCode = parseInt(fullNumberStr.substring(0, i), 10);
      if (potentialCountryCode in
          i18n.phonenumbers.metadata.countryCodeToRegionCodeMap) {
        nationalNumber.append(fullNumberStr.substring(i));
        return potentialCountryCode;
      }
    }
    return 0;
  };
  
  
  /**
   * Tries to extract a country calling code from a number. This method will
   * return zero if no country calling code is considered to be present. Country
   * calling codes are extracted in the following ways:
   * <ul>
   * <li>by stripping the international dialing prefix of the region the person is
   * dialing from, if this is present in the number, and looking at the next
   * digits
   * <li>by stripping the '+' sign if present and then looking at the next digits
   * <li>by comparing the start of the number and the country calling code of the
   * default region. If the number is not considered possible for the numbering
   * plan of the default region initially, but starts with the country calling
   * code of this region, validation will be reattempted after stripping this
   * country calling code. If this number is considered a possible number, then
   * the first digits will be considered the country calling code and removed as
   * such.
   * </ul>
   *
   * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but
   * the country calling code supplied after this does not match that of any known
   * region.
   *
   * @param {string} number non-normalized telephone number that we wish to
   *     extract a country calling code from - may begin with '+'.
   * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata
   *     about the region this number may be from.
   * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store
   *     the national significant number in, in the case that a country calling
   *     code was extracted. The number is appended to any existing contents. If
   *     no country calling code was extracted, this will be left unchanged.
   * @param {boolean} keepRawInput true if the country_code_source and
   *     preferred_carrier_code fields of phoneNumber should be populated.
   * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object
   *     where the country_code and country_code_source need to be populated.
   *     Note the country_code is always populated, whereas country_code_source is
   *     only populated when keepCountryCodeSource is true.
   * @return {number} the country calling code extracted or 0 if none could be
   *     extracted.
   * @throws {i18n.phonenumbers.Error}
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode =
      function(number, defaultRegionMetadata, nationalNumber,
               keepRawInput, phoneNumber) {
  
    if (number.length == 0) {
      return 0;
    }
    /** @type {!goog.string.StringBuffer} */
    var fullNumber = new goog.string.StringBuffer(number);
    // Set the default prefix to be something that will never match.
    /** @type {?string} */
    var possibleCountryIddPrefix;
    if (defaultRegionMetadata != null) {
      possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix();
    }
    if (possibleCountryIddPrefix == null) {
      possibleCountryIddPrefix = 'NonMatch';
    }
  
    /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */
    var countryCodeSource = this.maybeStripInternationalPrefixAndNormalize(
        fullNumber, possibleCountryIddPrefix);
    if (keepRawInput) {
      phoneNumber.setCountryCodeSource(countryCodeSource);
    }
    if (countryCodeSource !=
        i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY) {
      if (fullNumber.getLength() <=
          i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
        throw i18n.phonenumbers.Error.TOO_SHORT_AFTER_IDD;
      }
      /** @type {number} */
      var potentialCountryCode = this.extractCountryCode(fullNumber,
                                                         nationalNumber);
      if (potentialCountryCode != 0) {
        phoneNumber.setCountryCode(potentialCountryCode);
        return potentialCountryCode;
      }
  
      // If this fails, they must be using a strange country calling code that we
      // don't recognize, or that doesn't exist.
      throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
    } else if (defaultRegionMetadata != null) {
      // Check to see if the number starts with the country calling code for the
      // default region. If so, we remove the country calling code, and do some
      // checks on the validity of the number before and after.
      /** @type {number} */
      var defaultCountryCode = defaultRegionMetadata.getCountryCodeOrDefault();
      /** @type {string} */
      var defaultCountryCodeString = '' + defaultCountryCode;
      /** @type {string} */
      var normalizedNumber = fullNumber.toString();
      if (goog.string.startsWith(normalizedNumber, defaultCountryCodeString)) {
        /** @type {!goog.string.StringBuffer} */
        var potentialNationalNumber = new goog.string.StringBuffer(
            normalizedNumber.substring(defaultCountryCodeString.length));
        /** @type {i18n.phonenumbers.PhoneNumberDesc} */
        var generalDesc = defaultRegionMetadata.getGeneralDesc();
        /** @type {!RegExp} */
        var validNumberPattern =
            new RegExp(generalDesc.getNationalNumberPatternOrDefault());
        // Passing null since we don't need the carrier code.
        this.maybeStripNationalPrefixAndCarrierCode(
            potentialNationalNumber, defaultRegionMetadata, null);
        /** @type {string} */
        var potentialNationalNumberStr = potentialNationalNumber.toString();
        // If the number was not valid before but is valid now, or if it was too
        // long before, we consider the number with the country calling code
        // stripped to be a better result and keep that instead.
        if ((!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
                validNumberPattern, fullNumber.toString()) &&
            i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
                validNumberPattern, potentialNationalNumberStr)) ||
            this.testNumberLength_(fullNumber.toString(), generalDesc) ==
                i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG) {
          nationalNumber.append(potentialNationalNumberStr);
          if (keepRawInput) {
            phoneNumber.setCountryCodeSource(
                i18n.phonenumbers.PhoneNumber.CountryCodeSource
                    .FROM_NUMBER_WITHOUT_PLUS_SIGN);
          }
          phoneNumber.setCountryCode(defaultCountryCode);
          return defaultCountryCode;
        }
      }
    }
    // No country calling code present.
    phoneNumber.setCountryCode(0);
    return 0;
  };
  
  
  /**
   * Strips the IDD from the start of the number if present. Helper function used
   * by maybeStripInternationalPrefixAndNormalize.
   *
   * @param {!RegExp} iddPattern the regular expression for the international
   *     prefix.
   * @param {!goog.string.StringBuffer} number the phone number that we wish to
   *     strip any international dialing prefix from.
   * @return {boolean} true if an international prefix was present.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.parsePrefixAsIdd_ =
      function(iddPattern, number) {
  
    /** @type {string} */
    var numberStr = number.toString();
    if (numberStr.search(iddPattern) == 0) {
      /** @type {number} */
      var matchEnd = numberStr.match(iddPattern)[0].length;
      /** @type {Array.<string>} */
      var matchedGroups = numberStr.substring(matchEnd).match(
          i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN);
      if (matchedGroups && matchedGroups[1] != null &&
          matchedGroups[1].length > 0) {
        /** @type {string} */
        var normalizedGroup =
            i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(
                matchedGroups[1]);
        if (normalizedGroup == '0') {
          return false;
        }
      }
      number.clear();
      number.append(numberStr.substring(matchEnd));
      return true;
    }
    return false;
  };
  
  
  /**
   * Strips any international prefix (such as +, 00, 011) present in the number
   * provided, normalizes the resulting number, and indicates if an international
   * prefix was present.
   *
   * @param {!goog.string.StringBuffer} number the non-normalized telephone number
   *     that we wish to strip any international dialing prefix from.
   * @param {string} possibleIddPrefix the international direct dialing prefix
   *     from the region we think this number may be dialed in.
   * @return {i18n.phonenumbers.PhoneNumber.CountryCodeSource} the corresponding
   *     CountryCodeSource if an international dialing prefix could be removed
   *     from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if
   *     the number did not seem to be in international format.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      maybeStripInternationalPrefixAndNormalize = function(number,
                                                           possibleIddPrefix) {
    /** @type {string} */
    var numberStr = number.toString();
    if (numberStr.length == 0) {
      return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
    }
    // Check to see if the number begins with one or more plus signs.
    if (i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_
        .test(numberStr)) {
      numberStr = numberStr.replace(
          i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_, '');
      // Can now normalize the rest of the number since we've consumed the '+'
      // sign at the start.
      number.clear();
      number.append(i18n.phonenumbers.PhoneNumberUtil.normalize(numberStr));
      return i18n.phonenumbers.PhoneNumber.CountryCodeSource
          .FROM_NUMBER_WITH_PLUS_SIGN;
    }
    // Attempt to parse the first digits as an international prefix.
    /** @type {!RegExp} */
    var iddPattern = new RegExp(possibleIddPrefix);
    i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number);
    return this.parsePrefixAsIdd_(iddPattern, number) ?
        i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD :
        i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
  };
  
  
  /**
   * Strips any national prefix (such as 0, 1) present in the number provided.
   *
   * @param {!goog.string.StringBuffer} number the normalized telephone number
   *     that we wish to strip any national dialing prefix from.
   * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
   *     region that we think this number is from.
   * @param {goog.string.StringBuffer} carrierCode a place to insert the carrier
   *     code if one is extracted.
   * @return {boolean} true if a national prefix or carrier code (or both) could
   *     be extracted.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.
      maybeStripNationalPrefixAndCarrierCode = function(number, metadata,
                                                        carrierCode) {
    /** @type {string} */
    var numberStr = number.toString();
    /** @type {number} */
    var numberLength = numberStr.length;
    /** @type {?string} */
    var possibleNationalPrefix = metadata.getNationalPrefixForParsing();
    if (numberLength == 0 || possibleNationalPrefix == null ||
        possibleNationalPrefix.length == 0) {
      // Early return for numbers of zero length.
      return false;
    }
    // Attempt to parse the first digits as a national prefix.
    /** @type {!RegExp} */
    var prefixPattern = new RegExp('^(?:' + possibleNationalPrefix + ')');
    /** @type {Array.<string>} */
    var prefixMatcher = prefixPattern.exec(numberStr);
    if (prefixMatcher) {
      /** @type {!RegExp} */
      var nationalNumberRule = new RegExp(
          metadata.getGeneralDesc().getNationalNumberPatternOrDefault());
      // Check if the original number is viable.
      /** @type {boolean} */
      var isViableOriginalNumber =
          i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
              nationalNumberRule, numberStr);
      // prefixMatcher[numOfGroups] == null implies nothing was captured by the
      // capturing groups in possibleNationalPrefix; therefore, no transformation
      // is necessary, and we just remove the national prefix.
      /** @type {number} */
      var numOfGroups = prefixMatcher.length - 1;
      /** @type {?string} */
      var transformRule = metadata.getNationalPrefixTransformRule();
      /** @type {boolean} */
      var noTransform = transformRule == null || transformRule.length == 0 ||
                        prefixMatcher[numOfGroups] == null ||
                        prefixMatcher[numOfGroups].length == 0;
      if (noTransform) {
        // If the original number was viable, and the resultant number is not,
        // we return.
        if (isViableOriginalNumber &&
            !i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
                nationalNumberRule,
                numberStr.substring(prefixMatcher[0].length))) {
          return false;
        }
        if (carrierCode != null &&
            numOfGroups > 0 && prefixMatcher[numOfGroups] != null) {
          carrierCode.append(prefixMatcher[1]);
        }
        number.set(numberStr.substring(prefixMatcher[0].length));
        return true;
      } else {
        // Check that the resultant number is still viable. If not, return. Check
        // this by copying the string buffer and making the transformation on the
        // copy first.
        /** @type {string} */
        var transformedNumber;
        transformedNumber = numberStr.replace(prefixPattern, transformRule);
        if (isViableOriginalNumber &&
            !i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
                nationalNumberRule, transformedNumber)) {
          return false;
        }
        if (carrierCode != null && numOfGroups > 0) {
          carrierCode.append(prefixMatcher[1]);
        }
        number.set(transformedNumber);
        return true;
      }
    }
    return false;
  };
  
  
  /**
   * Strips any extension (as in, the part of the number dialled after the call is
   * connected, usually indicated with extn, ext, x or similar) from the end of
   * the number, and returns it.
   *
   * @param {!goog.string.StringBuffer} number the non-normalized telephone number
   *     that we wish to strip the extension from.
   * @return {string} the phone extension.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension =
      function(number) {
  
    /** @type {string} */
    var numberStr = number.toString();
    /** @type {number} */
    var mStart =
        numberStr.search(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
    // If we find a potential extension, and the number preceding this is a viable
    // number, we assume it is an extension.
    if (mStart >= 0 && i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(
        numberStr.substring(0, mStart))) {
      // The numbers are captured into groups in the regular expression.
      /** @type {Array.<string>} */
      var matchedGroups =
          numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
      /** @type {number} */
      var matchedGroupsLength = matchedGroups.length;
      for (var i = 1; i < matchedGroupsLength; ++i) {
        if (matchedGroups[i] != null && matchedGroups[i].length > 0) {
          // We go through the capturing groups until we find one that captured
          // some digits. If none did, then we will return the empty string.
          number.clear();
          number.append(numberStr.substring(0, mStart));
          return matchedGroups[i];
        }
      }
    }
    return '';
  };
  
  
  /**
   * Checks to see that the region code used is valid, or if it is not valid, that
   * the number to parse starts with a + symbol so that we can attempt to infer
   * the region from the number.
   * @param {string} numberToParse number that we are attempting to parse.
   * @param {?string} defaultRegion region that we are expecting the number to be
   *     from.
   * @return {boolean} false if it cannot use the region provided and the region
   *     cannot be inferred.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.checkRegionForParsing_ = function(
      numberToParse, defaultRegion) {
    // If the number is null or empty, we can't infer the region.
    return this.isValidRegionCode_(defaultRegion) ||
        (numberToParse != null && numberToParse.length > 0 &&
            i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_.test(
                numberToParse));
  };
  
  
  /**
   * Parses a string and returns it as a phone number in proto buffer format. The
   * method is quite lenient and looks for a number in the input text (raw input)
   * and does not check whether the string is definitely only a phone number. To
   * do this, it ignores punctuation and white-space, as well as any text before
   * the number (e.g. a leading “Tel: ”) and trims the non-number bits.  It will
   * accept a number in any format (E164, national, international etc), assuming
   * it can be interpreted with the defaultRegion supplied. It also attempts to
   * convert any alpha characters into digits if it thinks this is a vanity number
   * of the type "1800 MICROSOFT".
   *
   * This method will throw a {@link i18n.phonenumbers.Error} if the number is not
   * considered to be a possible number. Note that validation of whether the
   * number is actually a valid number for a particular region is not performed.
   * This can be done separately with {@link #isValidNumber}.
   *
   * @param {?string} numberToParse number that we are attempting to parse. This
   *     can contain formatting such as +, ( and -, as well as a phone number
   *     extension. It can also be provided in RFC3966 format.
   * @param {?string} defaultRegion region that we are expecting the number to be
   *     from. This is only used if the number being parsed is not written in
   *     international format. The country_code for the number in this case would
   *     be stored as that of the default region supplied. If the number is
   *     guaranteed to start with a '+' followed by the country calling code, then
   *     'ZZ' or null can be supplied.
   * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
   *     with the parsed number.
   * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
   *     viable phone number (e.g. too few or too many digits) or if no default
   *     region was supplied and the number is not in international format (does
   *     not start with +).
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse,
                                                               defaultRegion) {
    return this.parseHelper_(numberToParse, defaultRegion, false, true);
  };
  
  
  /**
   * Parses a string and returns it in proto buffer format. This method differs
   * from {@link #parse} in that it always populates the raw_input field of the
   * protocol buffer with numberToParse as well as the country_code_source field.
   *
   * @param {string} numberToParse number that we are attempting to parse. This
   *     can contain formatting such as +, ( and -, as well as a phone number
   *     extension.
   * @param {?string} defaultRegion region that we are expecting the number to be
   *     from. This is only used if the number being parsed is not written in
   *     international format. The country calling code for the number in this
   *     case would be stored as that of the default region supplied.
   * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
   *     with the parsed number.
   * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
   *     viable phone number or if no default region was supplied.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput =
      function(numberToParse, defaultRegion) {
  
    if (!this.isValidRegionCode_(defaultRegion)) {
      if (numberToParse.length > 0 && numberToParse.charAt(0) !=
          i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
        throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
      }
    }
    return this.parseHelper_(numberToParse, defaultRegion, true, true);
  };
  
  
  /**
   * A helper function to set the values related to leading zeros in a
   * PhoneNumber.
   *
   * @param {string} nationalNumber the number we are parsing.
   * @param {i18n.phonenumbers.PhoneNumber} phoneNumber a phone number proto
   *     buffer to fill in.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.setItalianLeadingZerosForPhoneNumber_ =
      function(nationalNumber, phoneNumber) {
    if (nationalNumber.length > 1 && nationalNumber.charAt(0) == '0') {
      phoneNumber.setItalianLeadingZero(true);
      var numberOfLeadingZeros = 1;
      // Note that if the national number is all "0"s, the last "0" is not counted
      // as a leading zero.
      while (numberOfLeadingZeros < nationalNumber.length - 1 &&
             nationalNumber.charAt(numberOfLeadingZeros) == '0') {
        numberOfLeadingZeros++;
      }
      if (numberOfLeadingZeros != 1) {
        phoneNumber.setNumberOfLeadingZeros(numberOfLeadingZeros);
      }
    }
  };
  
  
  /**
   * Parses a string and returns it in proto buffer format. This method is the
   * same as the public {@link #parse} method, with the exception that it allows
   * the default region to be null, for use by {@link #isNumberMatch}.
   *
   * @param {?string} numberToParse number that we are attempting to parse. This
   *     can contain formatting such as +, ( and -, as well as a phone number
   *     extension.
   * @param {?string} defaultRegion region that we are expecting the number to be
   *     from. This is only used if the number being parsed is not written in
   *     international format. The country calling code for the number in this
   *     case would be stored as that of the default region supplied.
   * @param {boolean} keepRawInput whether to populate the raw_input field of the
   *     phoneNumber with numberToParse.
   * @param {boolean} checkRegion should be set to false if it is permitted for
   *     the default coregion to be null or unknown ('ZZ').
   * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
   *     with the parsed number.
   * @throws {i18n.phonenumbers.Error}
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
      function(numberToParse, defaultRegion, keepRawInput, checkRegion) {
  
    if (numberToParse == null) {
      throw i18n.phonenumbers.Error.NOT_A_NUMBER;
    } else if (numberToParse.length >
        i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_) {
      throw i18n.phonenumbers.Error.TOO_LONG;
    }
  
    /** @type {!goog.string.StringBuffer} */
    var nationalNumber = new goog.string.StringBuffer();
    this.buildNationalNumberForParsing_(numberToParse, nationalNumber);
  
    if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(
        nationalNumber.toString())) {
      throw i18n.phonenumbers.Error.NOT_A_NUMBER;
    }
  
    // Check the region supplied is valid, or that the extracted number starts
    // with some sort of + sign so the number's region can be determined.
    if (checkRegion &&
        !this.checkRegionForParsing_(nationalNumber.toString(), defaultRegion)) {
      throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
    }
  
    /** @type {i18n.phonenumbers.PhoneNumber} */
    var phoneNumber = new i18n.phonenumbers.PhoneNumber();
    if (keepRawInput) {
      phoneNumber.setRawInput(numberToParse);
    }
    // Attempt to parse extension first, since it doesn't require region-specific
    // data and we want to have the non-normalised number here.
    /** @type {string} */
    var extension = this.maybeStripExtension(nationalNumber);
    if (extension.length > 0) {
      phoneNumber.setExtension(extension);
    }
  
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var regionMetadata = this.getMetadataForRegion(defaultRegion);
    // Check to see if the number is given in international format so we know
    // whether this number is from the default region or not.
    /** @type {!goog.string.StringBuffer} */
    var normalizedNationalNumber = new goog.string.StringBuffer();
    /** @type {number} */
    var countryCode = 0;
    /** @type {string} */
    var nationalNumberStr = nationalNumber.toString();
    try {
      countryCode = this.maybeExtractCountryCode(nationalNumberStr,
          regionMetadata, normalizedNationalNumber, keepRawInput, phoneNumber);
    } catch (e) {
      if (e == i18n.phonenumbers.Error.INVALID_COUNTRY_CODE &&
          i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_
              .test(nationalNumberStr)) {
        // Strip the plus-char, and try again.
        nationalNumberStr = nationalNumberStr.replace(
            i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_, '');
        countryCode = this.maybeExtractCountryCode(nationalNumberStr,
            regionMetadata, normalizedNationalNumber, keepRawInput, phoneNumber);
        if (countryCode == 0) {
          throw e;
        }
      } else {
        throw e;
      }
    }
    if (countryCode != 0) {
      /** @type {string} */
      var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCode);
      if (phoneNumberRegion != defaultRegion) {
        // Metadata cannot be null because the country calling code is valid.
        regionMetadata = this.getMetadataForRegionOrCallingCode_(
            countryCode, phoneNumberRegion);
      }
    } else {
      // If no extracted country calling code, use the region supplied instead.
      // The national number is just the normalized version of the number we were
      // given to parse.
      i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(nationalNumber);
      normalizedNationalNumber.append(nationalNumber.toString());
      if (defaultRegion != null) {
        countryCode = regionMetadata.getCountryCodeOrDefault();
        phoneNumber.setCountryCode(countryCode);
      } else if (keepRawInput) {
        phoneNumber.clearCountryCodeSource();
      }
    }
    if (normalizedNationalNumber.getLength() <
        i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
      throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
    }
  
    if (regionMetadata != null) {
      /** @type {!goog.string.StringBuffer} */
      var carrierCode = new goog.string.StringBuffer();
      /** @type {!goog.string.StringBuffer} */
      var potentialNationalNumber =
          new goog.string.StringBuffer(normalizedNationalNumber.toString());
      this.maybeStripNationalPrefixAndCarrierCode(
          potentialNationalNumber, regionMetadata, carrierCode);
      // We require that the NSN remaining after stripping the national prefix and
      // carrier code be long enough to be a possible length for the region.
      // Otherwise, we don't do the stripping, since the original number could be
      // a valid short number.
      if (this.testNumberLength_(potentialNationalNumber.toString(),
              regionMetadata.getGeneralDesc()) !=
          i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
        normalizedNationalNumber = potentialNationalNumber;
        if (keepRawInput && carrierCode.toString().length > 0) {
          phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString());
        }
      }
    }
    /** @type {string} */
    var normalizedNationalNumberStr = normalizedNationalNumber.toString();
    /** @type {number} */
    var lengthOfNationalNumber = normalizedNationalNumberStr.length;
    if (lengthOfNationalNumber <
        i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
      throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
    }
    if (lengthOfNationalNumber >
        i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
      throw i18n.phonenumbers.Error.TOO_LONG;
    }
    this.setItalianLeadingZerosForPhoneNumber_(
        normalizedNationalNumberStr, phoneNumber);
    phoneNumber.setNationalNumber(parseInt(normalizedNationalNumberStr, 10));
    return phoneNumber;
  };
  
  
  /**
   * Converts numberToParse to a form that we can parse and write it to
   * nationalNumber if it is written in RFC3966; otherwise extract a possible
   * number out of it and write to nationalNumber.
   *
   * @param {?string} numberToParse number that we are attempting to parse. This
   *     can contain formatting such as +, ( and -, as well as a phone number
   *     extension.
   * @param {!goog.string.StringBuffer} nationalNumber a string buffer for storing
   *     the national significant number.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.buildNationalNumberForParsing_ =
      function(numberToParse, nationalNumber) {
  
    /** @type {number} */
    var indexOfPhoneContext = numberToParse.indexOf(
        i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_);
    if (indexOfPhoneContext > 0) {
      var phoneContextStart = indexOfPhoneContext +
          i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_.length;
      // If the phone context contains a phone number prefix, we need to capture
      // it, whereas domains will be ignored.
      if (numberToParse.charAt(phoneContextStart) ==
          i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
        // Additional parameters might follow the phone context. If so, we will
        // remove them here because the parameters after phone context are not
        // important for parsing the phone number.
        var phoneContextEnd = numberToParse.indexOf(';', phoneContextStart);
        if (phoneContextEnd > 0) {
          nationalNumber.append(numberToParse.substring(phoneContextStart,
              phoneContextEnd));
        } else {
          nationalNumber.append(numberToParse.substring(phoneContextStart));
        }
      }
  
      // Now append everything between the "tel:" prefix and the phone-context.
      // This should include the national number, an optional extension or
      // isdn-subaddress component. Note we also handle the case when "tel:" is
      // missing, as we have seen in some of the phone number inputs.
      // In that case, we append everything from the beginning.
      var indexOfRfc3966Prefix = numberToParse.indexOf(
          i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_);
      var indexOfNationalNumber = (indexOfRfc3966Prefix >= 0) ?
          indexOfRfc3966Prefix +
          i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_.length : 0;
      nationalNumber.append(numberToParse.substring(indexOfNationalNumber,
          indexOfPhoneContext));
    } else {
      // Extract a possible number from the string passed in (this strips leading
      // characters that could not be the start of a phone number.)
      nationalNumber.append(
          i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber(numberToParse));
    }
  
    // Delete the isdn-subaddress and everything after it if it is present.
    // Note extension won't appear at the same time with isdn-subaddress
    // according to paragraph 5.3 of the RFC3966 spec,
    /** @type {string} */
    var nationalNumberStr = nationalNumber.toString();
    var indexOfIsdn = nationalNumberStr.indexOf(
        i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_);
    if (indexOfIsdn > 0) {
      nationalNumber.clear();
      nationalNumber.append(nationalNumberStr.substring(0, indexOfIsdn));
    }
    // If both phone context and isdn-subaddress are absent but other
    // parameters are present, the parameters are left in nationalNumber. This
    // is because we are concerned about deleting content from a potential
    // number string when there is no strong evidence that the number is
    // actually written in RFC3966.
  };
  
  
  /**
   * Takes two phone numbers and compares them for equality.
   *
   * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero
   * for Italian numbers and any extension present are the same. Returns NSN_MATCH
   * if either or both has no region specified, and the NSNs and extensions are
   * the same. Returns SHORT_NSN_MATCH if either or both has no region specified,
   * or the region specified is the same, and one NSN could be a shorter version
   * of the other number. This includes the case where one has an extension
   * specified, and the other does not. Returns NO_MATCH otherwise. For example,
   * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers
   * +1 345 657 1234 and 345 657 are a NO_MATCH.
   *
   * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to
   *     compare. If it is a string it can contain formatting, and can have
   *     country calling code specified with + at the start.
   * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to
   *     compare. If it is a string it can contain formatting, and can have
   *     country calling code specified with + at the start.
   * @return {i18n.phonenumbers.PhoneNumberUtil.MatchType} NOT_A_NUMBER, NO_MATCH,
   *     SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of
   *     equality of the two numbers, described in the method definition.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch =
      function(firstNumberIn, secondNumberIn) {
  
    // If the input arguements are strings parse them to a proto buffer format.
    // Else make copies of the phone numbers so that the numbers passed in are not
    // edited.
    /** @type {i18n.phonenumbers.PhoneNumber} */
    var firstNumber;
    /** @type {i18n.phonenumbers.PhoneNumber} */
    var secondNumber;
    if (typeof firstNumberIn == 'string') {
      // First see if the first number has an implicit country calling code, by
      // attempting to parse it.
      try {
        firstNumber = this.parse(
            firstNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
      } catch (e) {
        if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
          return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
        }
        // The first number has no country calling code. EXACT_MATCH is no longer
        // possible. We parse it as if the region was the same as that for the
        // second number, and if EXACT_MATCH is returned, we replace this with
        // NSN_MATCH.
        if (typeof secondNumberIn != 'string') {
          /** @type {string} */
          var secondNumberRegion = this.getRegionCodeForCountryCode(
              secondNumberIn.getCountryCodeOrDefault());
          if (secondNumberRegion !=
              i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_) {
            try {
              firstNumber = this.parse(firstNumberIn, secondNumberRegion);
            } catch (e2) {
              return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
            }
            /** @type {i18n.phonenumbers.PhoneNumberUtil.MatchType} */
            var match = this.isNumberMatch(firstNumber, secondNumberIn);
            if (match ==
                i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH) {
              return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
            }
            return match;
          }
        }
        // If the second number is a string or doesn't have a valid country
        // calling code, we parse the first number without country calling code.
        try {
          firstNumber = this.parseHelper_(firstNumberIn, null, false, false);
        } catch (e2) {
          return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
        }
      }
    } else {
      firstNumber = firstNumberIn.clone();
    }
    if (typeof secondNumberIn == 'string') {
      try {
        secondNumber = this.parse(
            secondNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
        return this.isNumberMatch(firstNumberIn, secondNumber);
      } catch (e) {
        if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
          return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
        }
        return this.isNumberMatch(secondNumberIn, firstNumber);
      }
    } else {
      secondNumber = secondNumberIn.clone();
    }
    // First clear raw_input, country_code_source and
    // preferred_domestic_carrier_code fields and any empty-string extensions so
    // that we can use the proto-buffer equality method.
    firstNumber.clearRawInput();
    firstNumber.clearCountryCodeSource();
    firstNumber.clearPreferredDomesticCarrierCode();
    secondNumber.clearRawInput();
    secondNumber.clearCountryCodeSource();
    secondNumber.clearPreferredDomesticCarrierCode();
    if (firstNumber.hasExtension() && firstNumber.getExtension().length == 0) {
      firstNumber.clearExtension();
    }
    if (secondNumber.hasExtension() && secondNumber.getExtension().length == 0) {
      secondNumber.clearExtension();
    }
  
    // Early exit if both had extensions and these are different.
    if (firstNumber.hasExtension() && secondNumber.hasExtension() &&
        firstNumber.getExtension() != secondNumber.getExtension()) {
      return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
    }
    /** @type {number} */
    var firstNumberCountryCode = firstNumber.getCountryCodeOrDefault();
    /** @type {number} */
    var secondNumberCountryCode = secondNumber.getCountryCodeOrDefault();
    // Both had country_code specified.
    if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) {
      if (firstNumber.equals(secondNumber)) {
        return i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH;
      } else if (firstNumberCountryCode == secondNumberCountryCode &&
          this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
        // A SHORT_NSN_MATCH occurs if there is a difference because of the
        // presence or absence of an 'Italian leading zero', the presence or
        // absence of an extension, or one NSN being a shorter variant of the
        // other.
        return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
      }
      // This is not a match.
      return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
    }
    // Checks cases where one or both country_code fields were not specified. To
    // make equality checks easier, we first set the country_code fields to be
    // equal.
    firstNumber.setCountryCode(0);
    secondNumber.setCountryCode(0);
    // If all else was the same, then this is an NSN_MATCH.
    if (firstNumber.equals(secondNumber)) {
      return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
    }
    if (this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
      return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
    }
    return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
  };
  
  
  /**
   * Returns true when one national number is the suffix of the other or both are
   * the same.
   *
   * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber
   *     object.
   * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber
   *     object.
   * @return {boolean} true if one PhoneNumber is the suffix of the other one.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.isNationalNumberSuffixOfTheOther_ =
      function(firstNumber, secondNumber) {
  
    /** @type {string} */
    var firstNumberNationalNumber = '' + firstNumber.getNationalNumber();
    /** @type {string} */
    var secondNumberNationalNumber = '' + secondNumber.getNationalNumber();
    // Note that endsWith returns true if the numbers are equal.
    return goog.string.endsWith(firstNumberNationalNumber,
                                secondNumberNationalNumber) ||
           goog.string.endsWith(secondNumberNationalNumber,
                                firstNumberNationalNumber);
  };
  
  
  /**
   * Returns true if the number can be dialled from outside the region, or
   * unknown. If the number can only be dialled from within the region, returns
   * false. Does not check the number is a valid number.
   * TODO: Make this method public when we have enough metadata to make it
   * worthwhile. Currently visible for testing purposes only.
   *
   * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we
   *     want to know whether it is diallable from outside the region.
   * @return {boolean} true if the number can only be dialled from within the
   *     country.
   */
  i18n.phonenumbers.PhoneNumberUtil.prototype.canBeInternationallyDialled =
      function(number) {
    /** @type {i18n.phonenumbers.PhoneMetadata} */
    var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number));
    if (metadata == null) {
      // Note numbers belonging to non-geographical entities (e.g. +800 numbers)
      // are always internationally diallable, and will be caught here.
      return true;
    }
    /** @type {string} */
    var nationalSignificantNumber = this.getNationalSignificantNumber(number);
    return !this.isNumberMatchingDesc_(nationalSignificantNumber,
                                       metadata.getNoInternationalDialling());
  };
  
  
  /**
   * Check whether the entire input sequence can be matched against the regular
   * expression.
   *
   * @param {!RegExp|string} regex the regular expression to match against.
   * @param {string} str the string to test.
   * @return {boolean} true if str can be matched entirely against regex.
   * @private
   */
  i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_ = function(regex, str) {
    /** @type {Array.<string>} */
    var matchedGroups = (typeof regex == 'string') ?
        str.match('^(?:' + regex + ')$') : str.match(regex);
    if (matchedGroups && matchedGroups[0].length == str.length) {
      return true;
    }
    return false;
  };
  