Update libphonenumber to v4.6

Change-Id: Ibc040a53cce8b85d901c0155dcb06f4d609e20fb
diff --git a/README.android b/README.android
index 9978794..e84d172 100644
--- a/README.android
+++ b/README.android
@@ -1,5 +1,5 @@
 URL: http://code.google.com/p/libphonenumber/
-Version: 4.5 (r415)
+Version: 4.6 (r429)
 License: Apache 2
 Description: Google Phone Number Library.
 Local Modification:
diff --git a/java/release_notes.txt b/java/release_notes.txt
index 4df4e8d..5970332 100644
--- a/java/release_notes.txt
+++ b/java/release_notes.txt
@@ -1,3 +1,19 @@
+February 9th, 2012: libphonenumber-4.6
+* Bug fixes
+ - Fix for formatByPattern to enable RFC formatting to work
+ - Fix for RFC formatting to work even when the international formatting rule starts with
+   punctuation
+ - Logging consistency changes - some warnings are no longer printed, others have become only
+   WARNINGS
+ - Fix for isValidNumberForRegion potentially throwing a NPE
+ - Parsing Israeli * numbers written in international format now works
+ - PhoneNumberMatcher doesn't match timestamps as phone-numbers
+* Metadata changes
+ - Updates for AN, AX, BF, BJ, BR, BS, DJ, FI, IN, LV, MW, RS, SC, VN
+ - New countries supported: SS (South Sudan), CW (Curaçao) and BQ (Bonaire, Sint Eustatius and Saba)
+* Refactoring of the private formatting functions in PhoneNumberUtil to ensure names are more
+  descriptive and to reduce code duplication.
+
 January 19th, 2012: libphonenumber-4.5
 * Code changes
  - Support for non-geographical country calling codes (e.g. +800).
diff --git a/java/src/com/android/i18n/phonenumbers/CountryCodeToRegionCodeMap.java b/java/src/com/android/i18n/phonenumbers/CountryCodeToRegionCodeMap.java
index 10b492e..69bb351 100644
--- a/java/src/com/android/i18n/phonenumbers/CountryCodeToRegionCodeMap.java
+++ b/java/src/com/android/i18n/phonenumbers/CountryCodeToRegionCodeMap.java
@@ -31,10 +31,10 @@
   // countries sharing a calling code, such as the NANPA countries, the one
   // indicated with "isMainCountryForCode" in the metadata should be first.
   static Map<Integer, List<String>> getCountryCodeToRegionCodeMap() {
-    // The capacity is set to 280 as there are 210 different country codes,
+    // The capacity is set to 281 as there are 211 different country codes,
     // and this offers a load factor of roughly 0.75.
     Map<Integer, List<String>> countryCodeToRegionCodeMap =
-        new HashMap<Integer, List<String>>(280);
+        new HashMap<Integer, List<String>>(281);
 
     ArrayList<String> listWithRegionCode;
 
@@ -254,6 +254,10 @@
     countryCodeToRegionCodeMap.put(98, listWithRegionCode);
 
     listWithRegionCode = new ArrayList<String>(1);
+    listWithRegionCode.add("SS");
+    countryCodeToRegionCodeMap.put(211, listWithRegionCode);
+
+    listWithRegionCode = new ArrayList<String>(1);
     listWithRegionCode.add("MA");
     countryCodeToRegionCodeMap.put(212, listWithRegionCode);
 
@@ -685,8 +689,10 @@
     listWithRegionCode.add("UY");
     countryCodeToRegionCodeMap.put(598, listWithRegionCode);
 
-    listWithRegionCode = new ArrayList<String>(1);
+    listWithRegionCode = new ArrayList<String>(3);
+    listWithRegionCode.add("CW");
     listWithRegionCode.add("AN");
+    listWithRegionCode.add("BQ");
     countryCodeToRegionCodeMap.put(599, listWithRegionCode);
 
     listWithRegionCode = new ArrayList<String>(1);
diff --git a/java/src/com/android/i18n/phonenumbers/PhoneNumberMatcher.java b/java/src/com/android/i18n/phonenumbers/PhoneNumberMatcher.java
index 3ddc773..64eaf1b 100644
--- a/java/src/com/android/i18n/phonenumbers/PhoneNumberMatcher.java
+++ b/java/src/com/android/i18n/phonenumbers/PhoneNumberMatcher.java
@@ -71,6 +71,14 @@
       Pattern.compile("(?:(?:[0-3]?\\d/[01]?\\d)|(?:[01]?\\d/[0-3]?\\d))/(?:[12]\\d)?\\d{2}");
 
   /**
+   * Matches timestamps. Examples: "2012-01-02 08:00". Note that the reg-ex does not include the
+   * trailing ":\d\d" -- that is covered by TIME_STAMPS_SUFFIX.
+   */
+  private static final Pattern TIME_STAMPS =
+      Pattern.compile("[12]\\d{3}[-/]?[01]\\d[-/]?[0-3]\\d [0-2]\\d$");
+  private static final Pattern TIME_STAMPS_SUFFIX = Pattern.compile(":[0-5]\\d");
+
+  /**
    * Pattern to check that brackets match. Opening brackets should be closed within a phone number.
    * This also checks that there is something inside the brackets. Having no brackets at all is also
    * fine.
@@ -310,6 +318,13 @@
     if (PUB_PAGES.matcher(candidate).find() || SLASH_SEPARATED_DATES.matcher(candidate).find()) {
       return null;
     }
+    // Skip potential time-stamps.
+    if (TIME_STAMPS.matcher(candidate).find()) {
+      String followingText = text.toString().substring(offset + candidate.length());
+      if (TIME_STAMPS_SUFFIX.matcher(followingText).lookingAt()) {
+        return null;
+      }
+    }
 
     // Try to come up with a valid match given the entire candidate.
     String rawString = candidate.toString();
diff --git a/java/src/com/android/i18n/phonenumbers/PhoneNumberUtil.java b/java/src/com/android/i18n/phonenumbers/PhoneNumberUtil.java
index 53e72c5..5120aab 100644
--- a/java/src/com/android/i18n/phonenumbers/PhoneNumberUtil.java
+++ b/java/src/com/android/i18n/phonenumbers/PhoneNumberUtil.java
@@ -95,6 +95,8 @@
   // The PLUS_SIGN signifies the international prefix.
   static final char PLUS_SIGN = '+';
 
+  private static final char STAR_SIGN = '*';
+
   private static final String RFC3966_EXTN_PREFIX = ";ext=";
 
   // A map that contains characters that are essential when dialling. That means any of the
@@ -256,11 +258,11 @@
   // carrier codes, for example in Brazilian phone numbers. We also allow multiple "+" characters at
   // the start.
   // Corresponds to the following:
-  // plus_sign*([punctuation]*[digits]){3,}([punctuation]|[digits]|[alpha])*
+  // plus_sign*(([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
   // Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
   private static final String VALID_PHONE_NUMBER =
-      "[" + PLUS_CHARS + "]*(?:[" + VALID_PUNCTUATION + "]*" + DIGITS + "){3,}[" +
-      VALID_PUNCTUATION + VALID_ALPHA + DIGITS + "]*";
+      "[" + PLUS_CHARS + "]*(?:[" + VALID_PUNCTUATION + STAR_SIGN + "]*" + DIGITS + "){3,}[" +
+      VALID_PUNCTUATION + STAR_SIGN + VALID_ALPHA + 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
@@ -993,6 +995,7 @@
     return normalizedNumber.toString();
   }
 
+  // @VisibleForTesting
   static synchronized PhoneNumberUtil getInstance(
       String baseFileLocation,
       Map<Integer, List<String>> countryCallingCodeToRegionCodeMap) {
@@ -1020,6 +1023,14 @@
   }
 
   /**
+   * Convenience method to get a list of what global network calling codes the library has metadata
+   * for.
+   */
+  public Set<Integer> getSupportedGlobalNetworkCallingCodes() {
+    return countryCodeToNonGeographicalMetadataMap.keySet();
+  }
+
+  /**
    * Gets a {@link PhoneNumberUtil} instance to carry out international phone number formatting,
    * parsing, or validation. The instance is loaded with phone number metadata for a number of most
    * commonly used regions.
@@ -1091,23 +1102,24 @@
       // Early exit for E164 case since no formatting of the national number needs to be applied.
       // Extensions are not formatted.
       formattedNumber.append(nationalSignificantNumber);
-      formatNumberByFormat(countryCallingCode, PhoneNumberFormat.E164, formattedNumber);
+      prefixNumberWithCountryCallingCode(countryCallingCode, PhoneNumberFormat.E164,
+                                         formattedNumber);
       return;
     }
     // 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.
     String regionCode = getRegionCodeForCountryCode(countryCallingCode);
-   if (!hasValidCountryCallingCode(countryCallingCode)) {
+    if (!hasValidCountryCallingCode(countryCallingCode)) {
       formattedNumber.append(nationalSignificantNumber);
       return;
     }
 
     PhoneMetadata metadata =
         getMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
-    formattedNumber.append(formatNationalNumber(nationalSignificantNumber, metadata, numberFormat));
-    maybeGetFormattedExtension(number, metadata, numberFormat, formattedNumber);
-    formatNumberByFormat(countryCallingCode, numberFormat, formattedNumber);
+    formattedNumber.append(formatNsn(nationalSignificantNumber, metadata, numberFormat));
+    maybeAppendFormattedExtension(number, metadata, numberFormat, formattedNumber);
+    prefixNumberWithCountryCallingCode(countryCallingCode, numberFormat, formattedNumber);
   }
 
   /**
@@ -1133,18 +1145,24 @@
     if (!hasValidCountryCallingCode(countryCallingCode)) {
       return nationalSignificantNumber;
     }
-    List<NumberFormat> userDefinedFormatsCopy =
-        new ArrayList<NumberFormat>(userDefinedFormats.size());
     PhoneMetadata metadata =
         getMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
-    for (NumberFormat numFormat : userDefinedFormats) {
-      String nationalPrefixFormattingRule = numFormat.getNationalPrefixFormattingRule();
+
+    StringBuilder formattedNumber = new StringBuilder(20);
+
+    NumberFormat formattingPattern =
+        chooseFormattingPatternForNumber(userDefinedFormats, nationalSignificantNumber);
+    if (formattingPattern == null) {
+      // If no pattern above is matched, we format the number as a whole.
+      formattedNumber.append(nationalSignificantNumber);
+    } else {
+      NumberFormat numFormatCopy = new NumberFormat();
+      // 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.
+      numFormatCopy.mergeFrom(formattingPattern);
+      String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule();
       if (nationalPrefixFormattingRule.length() > 0) {
-        // 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.
-        NumberFormat numFormatCopy = new NumberFormat();
-        numFormatCopy.mergeFrom(numFormat);
         String nationalPrefix = metadata.getNationalPrefix();
         if (nationalPrefix.length() > 0) {
           // Replace $NP with national prefix and $FG with the first group ($1).
@@ -1157,19 +1175,12 @@
           // We don't want to have a rule for how to format the national prefix if there isn't one.
           numFormatCopy.clearNationalPrefixFormattingRule();
         }
-        userDefinedFormatsCopy.add(numFormatCopy);
-      } else {
-        // Otherwise, we just add the original rule to the modified list of formats.
-        userDefinedFormatsCopy.add(numFormat);
       }
+      formattedNumber.append(
+          formatNsnUsingPattern(nationalSignificantNumber, numFormatCopy, numberFormat));
     }
-
-    StringBuilder formattedNumber =
-        new StringBuilder(formatAccordingToFormats(nationalSignificantNumber,
-                                                   userDefinedFormatsCopy,
-                                                   numberFormat));
-    maybeGetFormattedExtension(number, metadata, numberFormat, formattedNumber);
-    formatNumberByFormat(countryCallingCode, numberFormat, formattedNumber);
+    maybeAppendFormattedExtension(number, metadata, numberFormat, formattedNumber);
+    prefixNumberWithCountryCallingCode(countryCallingCode, numberFormat, formattedNumber);
     return formattedNumber.toString();
   }
 
@@ -1197,12 +1208,11 @@
 
     StringBuilder formattedNumber = new StringBuilder(20);
     PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
-    formattedNumber.append(formatNationalNumber(nationalSignificantNumber,
-                                                metadata,
-                                                PhoneNumberFormat.NATIONAL,
-                                                carrierCode));
-    maybeGetFormattedExtension(number, metadata, PhoneNumberFormat.NATIONAL, formattedNumber);
-    formatNumberByFormat(countryCallingCode, PhoneNumberFormat.NATIONAL, formattedNumber);
+    formattedNumber.append(formatNsn(nationalSignificantNumber, metadata,
+                                     PhoneNumberFormat.NATIONAL, carrierCode));
+    maybeAppendFormattedExtension(number, metadata, PhoneNumberFormat.NATIONAL, formattedNumber);
+    prefixNumberWithCountryCallingCode(countryCallingCode, PhoneNumberFormat.NATIONAL,
+                                       formattedNumber);
     return formattedNumber.toString();
   }
 
@@ -1314,6 +1324,10 @@
   public String formatOutOfCountryCallingNumber(PhoneNumber number,
                                                 String regionCallingFrom) {
     if (!isValidRegionCode(regionCallingFrom)) {
+      LOGGER.log(Level.WARNING,
+                 "Trying to format number from invalid region "
+                 + regionCallingFrom
+                 + ". International formatting applied.");
       return format(number, PhoneNumberFormat.INTERNATIONAL);
     }
     int countryCallingCode = number.getCountryCode();
@@ -1327,7 +1341,7 @@
         // country calling code.
         return countryCallingCode + " " + format(number, PhoneNumberFormat.NATIONAL);
       }
-    } else if (countryCallingCode == getCountryCodeForRegion(regionCallingFrom)) {
+    } else if (countryCallingCode == getCountryCodeForValidRegion(regionCallingFrom)) {
     // For regions that 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
@@ -1353,18 +1367,17 @@
     PhoneMetadata metadataForRegion =
         getMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
     String formattedNationalNumber =
-        formatNationalNumber(nationalSignificantNumber,
-                             metadataForRegion, PhoneNumberFormat.INTERNATIONAL);
+        formatNsn(nationalSignificantNumber, metadataForRegion, PhoneNumberFormat.INTERNATIONAL);
     StringBuilder formattedNumber = new StringBuilder(formattedNationalNumber);
-    maybeGetFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL,
-                               formattedNumber);
+    maybeAppendFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL,
+                                  formattedNumber);
     if (internationalPrefixForFormatting.length() > 0) {
       formattedNumber.insert(0, " ").insert(0, countryCallingCode).insert(0, " ")
           .insert(0, internationalPrefixForFormatting);
     } else {
-      formatNumberByFormat(countryCallingCode,
-                           PhoneNumberFormat.INTERNATIONAL,
-                           formattedNumber);
+      prefixNumberWithCountryCallingCode(countryCallingCode,
+                                         PhoneNumberFormat.INTERNATIONAL,
+                                         formattedNumber);
     }
     return formattedNumber.toString();
   }
@@ -1379,6 +1392,7 @@
    *
    * Note this method guarantees no digit will be inserted, removed or modified as a result of
    * formatting.
+   *
    * @param number  the phone number that needs to be formatted in its original number format
    * @param regionCallingFrom  the region whose IDD needs to be prefixed if the original number
    *     has one
@@ -1565,26 +1579,27 @@
       if (isNANPACountry(regionCallingFrom)) {
         return countryCode + " " + rawInput;
       }
-    } else if (countryCode == getCountryCodeForRegion(regionCallingFrom)) {
-      // Here we copy the formatting rules so we can modify the pattern we expect to match against.
-      List<NumberFormat> availableFormats =
-          new ArrayList<NumberFormat>(metadataForRegionCallingFrom.numberFormatSize());
-      for (NumberFormat format : metadataForRegionCallingFrom.numberFormats()) {
-        NumberFormat newFormat = new NumberFormat();
-        newFormat.mergeFrom(format);
-        // The first group is the first group of digits that the user determined.
-        newFormat.setPattern("(\\d+)(.*)");
-        // Here we just concatenate them back together after the national prefix has been fixed.
-        newFormat.setFormat("$1$2");
-        availableFormats.add(newFormat);
+    } else if (isValidRegionCode(regionCallingFrom) &&
+               countryCode == getCountryCodeForValidRegion(regionCallingFrom)) {
+      NumberFormat formattingPattern =
+          chooseFormattingPatternForNumber(metadataForRegionCallingFrom.numberFormats(),
+                                           nationalNumber);
+      if (formattingPattern == null) {
+        // If no pattern above is matched, we format the original input.
+        return rawInput;
       }
-      // Now we format using these patterns instead of the default pattern, but with the national
-      // prefix prefixed if necessary, by choosing the format rule based on the leading digits
-      // present in the unformatted national number.
+      NumberFormat newFormat = new NumberFormat();
+      newFormat.mergeFrom(formattingPattern);
+      // 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 formatAccordingToFormats(rawInput, availableFormats, PhoneNumberFormat.NATIONAL);
+      return formatNsnUsingPattern(rawInput, newFormat, PhoneNumberFormat.NATIONAL);
     }
     String internationalPrefixForFormatting = "";
     // If an unsupported region-calling-from is entered, or a country with multiple international
@@ -1600,15 +1615,15 @@
     StringBuilder formattedNumber = new StringBuilder(rawInput);
     String regionCode = getRegionCodeForCountryCode(countryCode);
     PhoneMetadata metadataForRegion = getMetadataForRegionOrCallingCode(countryCode, regionCode);
-    maybeGetFormattedExtension(number, metadataForRegion,
-                               PhoneNumberFormat.INTERNATIONAL, formattedNumber);
+    maybeAppendFormattedExtension(number, metadataForRegion,
+                                  PhoneNumberFormat.INTERNATIONAL, formattedNumber);
     if (internationalPrefixForFormatting.length() > 0) {
       formattedNumber.insert(0, " ").insert(0, countryCode).insert(0, " ")
           .insert(0, internationalPrefixForFormatting);
     } else {
       // Invalid region entered as country-calling-from (so no metadata was found for it) or the
       // region chosen has multiple international dialling prefixes.
-      formatNumberByFormat(countryCode,
+      prefixNumberWithCountryCallingCode(countryCode,
                            PhoneNumberFormat.INTERNATIONAL,
                            formattedNumber);
     }
@@ -1632,9 +1647,9 @@
   /**
    * A helper function that is used by format and formatByPattern.
    */
-  private void formatNumberByFormat(int countryCallingCode,
-                                    PhoneNumberFormat numberFormat,
-                                    StringBuilder formattedNumber) {
+  private void prefixNumberWithCountryCallingCode(int countryCallingCode,
+                                                  PhoneNumberFormat numberFormat,
+                                                  StringBuilder formattedNumber) {
     switch (numberFormat) {
       case E164:
         formattedNumber.insert(0, countryCallingCode).insert(0, PLUS_SIGN);
@@ -1651,21 +1666,19 @@
     }
   }
 
-  // Simple wrapper of formatNationalNumber for the common case of no carrier code.
-  private String formatNationalNumber(String number,
-                                      PhoneMetadata metadata,
-                                      PhoneNumberFormat numberFormat) {
-    return formatNationalNumber(number, metadata, numberFormat, null);
+  // Simple wrapper of formatNsn for the common case of no carrier code.
+  private String formatNsn(String number, PhoneMetadata metadata, PhoneNumberFormat numberFormat) {
+    return formatNsn(number, metadata, numberFormat, null);
   }
 
   // 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.
-  private String formatNationalNumber(String number,
-                                      PhoneMetadata metadata,
-                                      PhoneNumberFormat numberFormat,
-                                      String carrierCode) {
+  private String formatNsn(String number,
+                           PhoneMetadata metadata,
+                           PhoneNumberFormat numberFormat,
+                           String carrierCode) {
     List<NumberFormat> intlNumberFormats = metadata.intlNumberFormats();
     // When the intlNumberFormats exists, we use that to format national number for the
     // INTERNATIONAL format instead of using the numberDesc.numberFormats.
@@ -1673,13 +1686,10 @@
         (intlNumberFormats.size() == 0 || numberFormat == PhoneNumberFormat.NATIONAL)
         ? metadata.numberFormats()
         : metadata.intlNumberFormats();
-    String formattedNationalNumber =
-        formatAccordingToFormats(number, availableFormats, numberFormat, carrierCode);
-    if (numberFormat == PhoneNumberFormat.RFC3966) {
-      formattedNationalNumber =
-          SEPARATOR_PATTERN.matcher(formattedNationalNumber).replaceAll("-");
-    }
-    return formattedNationalNumber;
+    NumberFormat formattingPattern = chooseFormattingPatternForNumber(availableFormats, number);
+    return (formattingPattern == null)
+        ? number
+        : formatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode);
   }
 
   private NumberFormat chooseFormattingPatternForNumber(List<NumberFormat> availableFormats,
@@ -1698,50 +1708,58 @@
     return null;
   }
 
-  // Simple wrapper of formatAccordingToFormats for the common case of no carrier code.
-  private String formatAccordingToFormats(String nationalNumber,
-                                          List<NumberFormat> availableFormats,
-                                          PhoneNumberFormat numberFormat) {
-    return formatAccordingToFormats(nationalNumber, availableFormats, numberFormat, null);
+  // Simple wrapper of formatNsnUsingPattern for the common case of no carrier code.
+  private String formatNsnUsingPattern(String nationalNumber,
+                                       NumberFormat formattingPattern,
+                                       PhoneNumberFormat numberFormat) {
+    return formatNsnUsingPattern(nationalNumber, formattingPattern, numberFormat, null);
   }
 
   // Note that carrierCode is optional - if NULL or an empty string, no carrier code replacement
   // will take place.
-  private String formatAccordingToFormats(String nationalNumber,
-                                          List<NumberFormat> availableFormats,
-                                          PhoneNumberFormat numberFormat,
-                                          String carrierCode) {
-    NumberFormat numFormat = chooseFormattingPatternForNumber(availableFormats, nationalNumber);
-    if (numFormat == null) {
-      // If no pattern above is matched, we format the number as a whole.
-      return nationalNumber;
-    }
-    String numberFormatRule = numFormat.getFormat();
-    Matcher m = regexCache.getPatternForRegex(numFormat.getPattern()).matcher(nationalNumber);
+  private String formatNsnUsingPattern(String nationalNumber,
+                                       NumberFormat formattingPattern,
+                                       PhoneNumberFormat numberFormat,
+                                       String carrierCode) {
+    String numberFormatRule = formattingPattern.getFormat();
+    Matcher m =
+        regexCache.getPatternForRegex(formattingPattern.getPattern()).matcher(nationalNumber);
+    String formattedNationalNumber = "";
     if (numberFormat == PhoneNumberFormat.NATIONAL &&
         carrierCode != null && carrierCode.length() > 0 &&
-        numFormat.getDomesticCarrierCodeFormattingRule().length() > 0) {
+        formattingPattern.getDomesticCarrierCodeFormattingRule().length() > 0) {
       // Replace the $CC in the formatting rule with the desired carrier code.
-      String carrierCodeFormattingRule = numFormat.getDomesticCarrierCodeFormattingRule();
+      String carrierCodeFormattingRule = formattingPattern.getDomesticCarrierCodeFormattingRule();
       carrierCodeFormattingRule =
           CC_PATTERN.matcher(carrierCodeFormattingRule).replaceFirst(carrierCode);
       // Now replace the $FG in the formatting rule with the first group and the carrier code
       // combined in the appropriate way.
       numberFormatRule = FIRST_GROUP_PATTERN.matcher(numberFormatRule)
           .replaceFirst(carrierCodeFormattingRule);
-      return m.replaceAll(numberFormatRule);
+      formattedNationalNumber = m.replaceAll(numberFormatRule);
     } else {
       // Use the national prefix formatting rule instead.
-      String nationalPrefixFormattingRule = numFormat.getNationalPrefixFormattingRule();
+      String nationalPrefixFormattingRule = formattingPattern.getNationalPrefixFormattingRule();
       if (numberFormat == PhoneNumberFormat.NATIONAL &&
           nationalPrefixFormattingRule != null &&
           nationalPrefixFormattingRule.length() > 0) {
         Matcher firstGroupMatcher = FIRST_GROUP_PATTERN.matcher(numberFormatRule);
-        return m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule));
+        formattedNationalNumber =
+            m.replaceAll(firstGroupMatcher.replaceFirst(nationalPrefixFormattingRule));
       } else {
-        return m.replaceAll(numberFormatRule);
+        formattedNationalNumber = m.replaceAll(numberFormatRule);
       }
     }
+    if (numberFormat == PhoneNumberFormat.RFC3966) {
+      // Strip any leading punctuation.
+      Matcher matcher = SEPARATOR_PATTERN.matcher(formattedNationalNumber);
+      if (matcher.lookingAt()) {
+        formattedNationalNumber = matcher.replaceFirst("");
+      }
+      // Replace the rest with a dash between each number group.
+      formattedNationalNumber = matcher.reset(formattedNationalNumber).replaceAll("-");
+    }
+    return formattedNationalNumber;
   }
 
   /**
@@ -1769,7 +1787,7 @@
   public PhoneNumber getExampleNumberForType(String regionCode, PhoneNumberType type) {
     // Check the region code is valid.
     if (!isValidRegionCode(regionCode)) {
-      LOGGER.log(Level.SEVERE, "Invalid or unknown region code provided: " + regionCode);
+      LOGGER.log(Level.WARNING, "Invalid or unknown region code provided: " + regionCode);
       return null;
     }
     PhoneNumberDesc desc = getNumberDescByType(getMetadataForRegion(regionCode), type);
@@ -1802,6 +1820,9 @@
       } catch (NumberParseException e) {
         LOGGER.log(Level.SEVERE, e.toString());
       }
+    } else {
+      LOGGER.log(Level.WARNING,
+                 "Invalid or unknown country calling code provided: " + countryCallingCode);
     }
     return null;
   }
@@ -1810,32 +1831,22 @@
    * Appends the formatted extension of a phone number to formattedNumber, if the phone number had
    * an extension specified.
    */
-  private void maybeGetFormattedExtension(PhoneNumber number, PhoneMetadata metadata,
-                                          PhoneNumberFormat numberFormat,
-                                          StringBuilder formattedNumber) {
+  private void maybeAppendFormattedExtension(PhoneNumber number, PhoneMetadata metadata,
+                                             PhoneNumberFormat numberFormat,
+                                             StringBuilder formattedNumber) {
     if (number.hasExtension() && number.getExtension().length() > 0) {
       if (numberFormat == PhoneNumberFormat.RFC3966) {
         formattedNumber.append(RFC3966_EXTN_PREFIX).append(number.getExtension());
       } else {
-        formatExtension(number.getExtension(), metadata, formattedNumber);
+        if (metadata.hasPreferredExtnPrefix()) {
+          formattedNumber.append(metadata.getPreferredExtnPrefix()).append(number.getExtension());
+        } else {
+          formattedNumber.append(DEFAULT_EXTN_PREFIX).append(number.getExtension());
+        }
       }
     }
   }
 
-  /**
-   * Formats the extension part of the phone number by prefixing it with the appropriate extension
-   * prefix. This will be the default extension prefix, unless overridden by a preferred
-   * extension prefix for this region.
-   */
-  private void formatExtension(String extensionDigits, PhoneMetadata metadata,
-                               StringBuilder extension) {
-    if (metadata.hasPreferredExtnPrefix()) {
-      extension.append(metadata.getPreferredExtnPrefix()).append(extensionDigits);
-    } else {
-      extension.append(DEFAULT_EXTN_PREFIX).append(extensionDigits);
-    }
-  }
-
   PhoneNumberDesc getNumberDescByType(PhoneMetadata metadata, PhoneNumberType type) {
     switch (type) {
       case PREMIUM_RATE:
@@ -1992,12 +2003,14 @@
    */
   public boolean isValidNumberForRegion(PhoneNumber number, String regionCode) {
     int countryCode = number.getCountryCode();
-    if (countryCode == 0 ||
+    PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode);
+    if ((metadata == null) ||
         (!REGION_CODE_FOR_NON_GEO_ENTITY.equals(regionCode) &&
-         countryCode != getCountryCodeForRegion(regionCode))) {
+         countryCode != 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;
     }
-    PhoneMetadata metadata = getMetadataForRegionOrCallingCode(countryCode, regionCode);
     PhoneNumberDesc generalNumDesc = metadata.getGeneralDesc();
     String nationalSignificantNumber = getNationalSignificantNumber(number);
 
@@ -2072,12 +2085,23 @@
    */
   public int getCountryCodeForRegion(String regionCode) {
     if (!isValidRegionCode(regionCode)) {
-      LOGGER.log(Level.SEVERE,
+      LOGGER.log(Level.WARNING,
                  "Invalid or missing region code ("
                   + ((regionCode == null) ? "null" : regionCode)
                   + ") provided.");
       return 0;
     }
+    return 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 regionCode  the region that we want to get the country calling code for
+   * @return  the country calling code for the region denoted by regionCode
+   */
+  private int getCountryCodeForValidRegion(String regionCode) {
     PhoneMetadata metadata = getMetadataForRegion(regionCode);
     return metadata.getCountryCode();
   }
@@ -2098,7 +2122,7 @@
    */
   public String getNddPrefixForRegion(String regionCode, boolean stripNonDigits) {
     if (!isValidRegionCode(regionCode)) {
-      LOGGER.log(Level.SEVERE,
+      LOGGER.log(Level.WARNING,
                  "Invalid or missing region code ("
                   + ((regionCode == null) ? "null" : regionCode)
                   + ") provided.");
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AN b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AN
index ece2723..10f648f 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AN
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AN
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AX b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AX
index 91d11b5..18ca4d0 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AX
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_AX
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF
index 01ca8c3..802997e 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BJ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BJ
index af2439c..09eee90 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BJ
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BJ
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BQ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BQ
new file mode 100644
index 0000000..6ac0880
--- /dev/null
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BQ
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR
index 845377b..31ed9bc 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BS b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BS
index 2a8b978..d280135 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BS
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_BS
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_CW b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_CW
new file mode 100644
index 0000000..8f4170e
--- /dev/null
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_CW
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_DJ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_DJ
index 57af3c0..0683a64 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_DJ
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_DJ
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_FI b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_FI
index 1e7307e..9995781 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_FI
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_FI
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN
index 326d131..f07407a 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_LV b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_LV
index 335c85d..fd64fb8 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_LV
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_LV
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_MW b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_MW
index 2fb6952..fdb4093 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_MW
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_MW
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_RS b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_RS
index 81c0848..bf324e6 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_RS
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_RS
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC
index 39ee643..7f55e5a 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SS b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SS
new file mode 100644
index 0000000..a8293fd
--- /dev/null
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_SS
Binary files differ
diff --git a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_VN b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_VN
index 2d29291..d775464 100644
--- a/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_VN
+++ b/java/src/com/android/i18n/phonenumbers/data/PhoneNumberMetadataProto_VN
Binary files differ
diff --git a/java/test/com/android/i18n/phonenumbers/ExampleNumbersTest.java b/java/test/com/android/i18n/phonenumbers/ExampleNumbersTest.java
index 9f19826..04e2c7f 100644
--- a/java/test/com/android/i18n/phonenumbers/ExampleNumbersTest.java
+++ b/java/test/com/android/i18n/phonenumbers/ExampleNumbersTest.java
@@ -141,6 +141,13 @@
     assertEquals(0, wrongTypeCases.size());
   }
 
+  public void testVoicemail() throws Exception {
+    Set<PhoneNumberType> voicemailTypes = EnumSet.of(PhoneNumberType.VOICEMAIL);
+    checkNumbersValidAndCorrectType(PhoneNumberType.VOICEMAIL, voicemailTypes);
+    assertEquals(0, invalidCases.size());
+    assertEquals(0, wrongTypeCases.size());
+  }
+
   public void testSharedCost() throws Exception {
     Set<PhoneNumberType> sharedCostTypes = EnumSet.of(PhoneNumberType.SHARED_COST);
     checkNumbersValidAndCorrectType(PhoneNumberType.SHARED_COST, sharedCostTypes);
@@ -162,11 +169,44 @@
       }
       if (exampleNumber != null && phoneNumberUtil.canBeInternationallyDialled(exampleNumber)) {
         wrongTypeCases.add(exampleNumber);
+        LOGGER.log(Level.SEVERE, "Number " + exampleNumber.toString()
+                   + " should not be internationally diallable");
       }
     }
     assertEquals(0, wrongTypeCases.size());
   }
 
+  // TODO: Update this to use connectsToEmergencyNumber or similar once that is
+  // implemented.
+  public void testEmergency() throws Exception {
+    int wrongTypeCounter = 0;
+    for (String regionCode : phoneNumberUtil.getSupportedRegions()) {
+      PhoneNumberDesc desc =
+          phoneNumberUtil.getMetadataForRegion(regionCode).getEmergency();
+      if (desc.hasExampleNumber()) {
+        String exampleNumber = desc.getExampleNumber();
+        if (!exampleNumber.matches(desc.getPossibleNumberPattern()) ||
+            !exampleNumber.matches(desc.getNationalNumberPattern())) {
+          wrongTypeCounter++;
+          LOGGER.log(Level.SEVERE, "Emergency example number test failed for " + regionCode);
+        }
+      }
+    }
+    assertEquals(0, wrongTypeCounter);
+  }
+
+  public void testGlobalNetworkNumbers() throws Exception {
+    for (Integer callingCode : phoneNumberUtil.getSupportedGlobalNetworkCallingCodes()) {
+      PhoneNumber exampleNumber =
+          phoneNumberUtil.getExampleNumberForNonGeoEntity(callingCode);
+      assertNotNull("No example phone number for calling code " + callingCode, exampleNumber);
+      if (!phoneNumberUtil.isValidNumber(exampleNumber)) {
+        invalidCases.add(exampleNumber);
+        LOGGER.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
+      }
+    }
+  }
+
   public void testEveryRegionHasAnExampleNumber() throws Exception {
     for (String regionCode : phoneNumberUtil.getSupportedRegions()) {
       PhoneNumber exampleNumber = phoneNumberUtil.getExampleNumber(regionCode);
diff --git a/java/test/com/android/i18n/phonenumbers/PhoneNumberMatcherTest.java b/java/test/com/android/i18n/phonenumbers/PhoneNumberMatcherTest.java
index a00ef33..dea226d 100644
--- a/java/test/com/android/i18n/phonenumbers/PhoneNumberMatcherTest.java
+++ b/java/test/com/android/i18n/phonenumbers/PhoneNumberMatcherTest.java
@@ -370,6 +370,9 @@
     new NumberTest("1/12/2011", RegionCode.US),
     new NumberTest("10/12/82", RegionCode.DE),
     new NumberTest("650x2531234", RegionCode.US),
+    new NumberTest("2012-01-02 08:00", RegionCode.US),
+    new NumberTest("2012/01/02 08:00", RegionCode.US),
+    new NumberTest("20120102 08:00", RegionCode.US),
   };
 
   /**
@@ -398,12 +401,13 @@
     new NumberTest("9002309. 158", RegionCode.US),
     new NumberTest("12 7/8 - 14 12/34 - 5", RegionCode.US),
     new NumberTest("12.1 - 23.71 - 23.45", RegionCode.US),
-
     new NumberTest("800 234 1 111x1111", RegionCode.US),
     new NumberTest("1979-2011 100", RegionCode.US),
     new NumberTest("+494949-4-94", RegionCode.DE),  // National number in wrong format
     new NumberTest("\uFF14\uFF11\uFF15\uFF16\uFF16\uFF16\uFF16-\uFF17\uFF17\uFF17", RegionCode.US),
-
+    new NumberTest("2012-0102 08", RegionCode.US),  // Very strange formatting.
+    new NumberTest("2012-01-02 08", RegionCode.US),
+    new NumberTest("1800-10-10 22", RegionCode.AU),  // Breakdown assistance number.
   };
 
   /**
diff --git a/java/test/com/android/i18n/phonenumbers/PhoneNumberUtilTest.java b/java/test/com/android/i18n/phonenumbers/PhoneNumberUtilTest.java
index 66693e5..00718bb 100644
--- a/java/test/com/android/i18n/phonenumbers/PhoneNumberUtilTest.java
+++ b/java/test/com/android/i18n/phonenumbers/PhoneNumberUtilTest.java
@@ -709,6 +709,9 @@
     assertEquals("+1 (650) 253-0000", phoneUtil.formatByPattern(US_NUMBER,
                                                                 PhoneNumberFormat.INTERNATIONAL,
                                                                 newNumberFormats));
+    assertEquals("+1-650-253-0000", phoneUtil.formatByPattern(US_NUMBER,
+                                                              PhoneNumberFormat.RFC3966,
+                                                              newNumberFormats));
 
     // $NP is set to '1' for the US. Here we check that for other NANPA countries the US rules are
     // followed.
@@ -1027,6 +1030,18 @@
     assertTrue(phoneUtil.isValidNumberForRegion(reNumber, RegionCode.RE));
     assertTrue(phoneUtil.isValidNumberForRegion(INTERNATIONAL_TOLL_FREE, RegionCode.UN001));
     assertFalse(phoneUtil.isValidNumberForRegion(INTERNATIONAL_TOLL_FREE, RegionCode.US));
+    assertFalse(phoneUtil.isValidNumberForRegion(INTERNATIONAL_TOLL_FREE, RegionCode.ZZ));
+
+    PhoneNumber invalidNumber = new PhoneNumber();
+    // Invalid country calling codes.
+    invalidNumber.setCountryCode(3923).setNationalNumber(2366L);
+    assertFalse(phoneUtil.isValidNumberForRegion(invalidNumber, RegionCode.ZZ));
+    invalidNumber.setCountryCode(3923).setNationalNumber(2366L);
+    assertFalse(phoneUtil.isValidNumberForRegion(invalidNumber, RegionCode.UN001));
+    invalidNumber.setCountryCode(0).setNationalNumber(2366L);
+    assertFalse(phoneUtil.isValidNumberForRegion(invalidNumber, RegionCode.UN001));
+    invalidNumber.setCountryCode(0);
+    assertFalse(phoneUtil.isValidNumberForRegion(invalidNumber, RegionCode.ZZ));
   }
 
   public void testIsNotValidNumber() {
@@ -1048,6 +1063,13 @@
     invalidNumber.setCountryCode(64).setNationalNumber(3316005L);
     assertFalse(phoneUtil.isValidNumber(invalidNumber));
 
+    invalidNumber.clear();
+    // Invalid country calling codes.
+    invalidNumber.setCountryCode(3923).setNationalNumber(2366L);
+    assertFalse(phoneUtil.isValidNumber(invalidNumber));
+    invalidNumber.setCountryCode(0);
+    assertFalse(phoneUtil.isValidNumber(invalidNumber));
+
     assertFalse(phoneUtil.isValidNumber(INTERNATIONAL_TOLL_FREE_TOO_LONG));
   }
 
@@ -1551,6 +1573,10 @@
     // already possible.
     usNumber.setCountryCode(1).setNationalNumber(1234567890L);
     assertEquals(usNumber, phoneUtil.parse("123-456-7890", RegionCode.US));
+
+    // Test star numbers. Although this is not strictly valid, we would like to make sure we can
+    // parse the output we produce when formatting the number.
+    assertEquals(JP_STAR_NUMBER, phoneUtil.parse("+81 *2345", RegionCode.JP));
   }
 
   public void testParseNumberWithAlphaCharacters() throws Exception {
@@ -1703,6 +1729,26 @@
                    e.getErrorType());
     }
     try {
+      String plusStar = "+***";
+      phoneUtil.parse(plusStar, RegionCode.DE);
+      fail("This should not parse without throwing an exception " + plusStar);
+    } catch (NumberParseException e) {
+      // Expected this exception.
+      assertEquals("Wrong error type stored in exception.",
+                   NumberParseException.ErrorType.NOT_A_NUMBER,
+                   e.getErrorType());
+    }
+    try {
+      String plusStarPhoneNumber = "+*******91";
+      phoneUtil.parse(plusStarPhoneNumber, RegionCode.DE);
+      fail("This should not parse without throwing an exception " + plusStarPhoneNumber);
+    } catch (NumberParseException e) {
+      // Expected this exception.
+      assertEquals("Wrong error type stored in exception.",
+                   NumberParseException.ErrorType.NOT_A_NUMBER,
+                   e.getErrorType());
+    }
+    try {
       String tooShortPhoneNumber = "+49 0";
       phoneUtil.parse(tooShortPhoneNumber, RegionCode.DE);
       fail("This should not parse without throwing an exception " + tooShortPhoneNumber);