Commits

Anonymous committed 0df7b4f

JAVA: libphonenumber v4.6. New countries: BQ, CW, SS, metadata updates & bug fixes.

Comments (0)

Files changed (26)

java/libphonenumber/src/com/google/i18n/phonenumbers/CountryCodeToRegionCodeMap.java

   // 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;
 
     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);
 
     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);

java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberMatcher.java

       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.
     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();

java/libphonenumber/src/com/google/i18n/phonenumbers/PhoneNumberUtil.java

   // 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
   // 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
     return normalizedNumber.toString();
   }
 
+  // @VisibleForTesting
   static synchronized PhoneNumberUtil getInstance(
       String baseFileLocation,
       Map<Integer, List<String>> countryCallingCodeToRegionCodeMap) {
   }
 
   /**
+   * 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.
       // 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);
   }
 
   /**
     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).
           // 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();
   }
 
 
     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();
   }
 
   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();
         // 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
     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();
   }
    *
    * 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
       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
     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);
     }
   /**
    * 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);
     }
   }
 
-  // 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.
         (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,
     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;
   }
 
   /**
   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);
       } catch (NumberParseException e) {
         LOGGER.log(Level.SEVERE, e.toString());
       }
+    } else {
+      LOGGER.log(Level.WARNING,
+                 "Invalid or unknown country calling code provided: " + countryCallingCode);
     }
     return null;
   }
    * 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:
    */
   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);
 
    */
   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();
   }
    */
   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.");

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AN

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_AX

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BF

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BJ

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BQ

Binary file added.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BR

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_BS

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_CW

Binary file added.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_DJ

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_FI

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_IN

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_LV

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_MW

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_RS

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SC

Binary file modified.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_SS

Binary file added.

java/libphonenumber/src/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProto_VN

Binary file modified.

java/libphonenumber/test/com/google/i18n/phonenumbers/ExampleNumbersTest.java

     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);
       }
       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);

java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberMatcherTest.java

     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),
   };
 
   /**
     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.
   };
 
   /**

java/libphonenumber/test/com/google/i18n/phonenumbers/PhoneNumberUtilTest.java

     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.
     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() {
     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));
   }
 
     // 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 {
                    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);

java/libphonenumber/test/com/google/i18n/phonenumbers/ShortNumberUtilTest.java.orig

-/*
- * Copyright (C) 2011 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.
- */
-
-package com.google.i18n.phonenumbers;
-
-import junit.framework.TestCase;
-
-import java.io.InputStream;
-
-/**
- * @author Shaopeng Jia
- */
-public class ShortNumberUtilTest extends TestCase {
-  private ShortNumberUtil shortUtil;
-  static final String TEST_META_DATA_FILE_PREFIX =
-      "/com/google/i18n/phonenumbers/data/PhoneNumberMetadataProtoForTesting";
-
-  public ShortNumberUtilTest() {
-    PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(
-        TEST_META_DATA_FILE_PREFIX,
-        CountryCodeToRegionCodeMapForTesting.getCountryCodeToRegionCodeMap());
-    shortUtil = new ShortNumberUtil(phoneUtil);
-  }
-
-  public void testConnectsToEmergencyNumber_US() {
-    assertTrue(shortUtil.connectsToEmergencyNumber("911", RegionCode.US));
-    assertTrue(shortUtil.connectsToEmergencyNumber("119", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber("999", RegionCode.US));
-  }
-
-  public void testConnectsToEmergencyNumberLongNumber_US() {
-    assertTrue(shortUtil.connectsToEmergencyNumber("9116666666", RegionCode.US));
-    assertTrue(shortUtil.connectsToEmergencyNumber("1196666666", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber("9996666666", RegionCode.US));
-  }
-
-  public void testConnectsToEmergencyNumberWithFormatting_US() {
-    assertTrue(shortUtil.connectsToEmergencyNumber("9-1-1", RegionCode.US));
-    assertTrue(shortUtil.connectsToEmergencyNumber("1-1-9", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber("9-9-9", RegionCode.US));
-  }
-
-  public void testConnectsToEmergencyNumberWithPlusSign_US() {
-    assertFalse(shortUtil.connectsToEmergencyNumber("+911", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber("\uFF0B911", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber(" +911", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber("+119", RegionCode.US));
-    assertFalse(shortUtil.connectsToEmergencyNumber("+999", RegionCode.US));
-  }
-
-  public void testConnectsToEmergencyNumber_BR() {
-    assertTrue(shortUtil.connectsToEmergencyNumber("911", RegionCode.BR));
-    assertTrue(shortUtil.connectsToEmergencyNumber("190", RegionCode.BR));
-    assertFalse(shortUtil.connectsToEmergencyNumber("999", RegionCode.BR));
-  }
-
-  public void testConnectsToEmergencyNumberLongNumber_BR() {
-    // Brazilian emergency numbers don't work when additional digits are appended.
-    assertFalse(shortUtil.connectsToEmergencyNumber("9111", RegionCode.BR));
-    assertFalse(shortUtil.connectsToEmergencyNumber("1900", RegionCode.BR));
-    assertFalse(shortUtil.connectsToEmergencyNumber("9996", RegionCode.BR));
-  }
-}

java/release_notes.txt

+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).

resources/PhoneNumberMetaData.xml

     </territory>
 
     <!-- Netherlands Antilles -->
+    <!-- Note this country no longer exists. This metadata exists only to validate old Sint Maarten
+         numbers through their parallel running period (which ends Sep 2012). -->
+    <!-- The link below no longer works, since ITU deleted this document since this country no
+         longer exists. We keep it here as a record of the last place we found information on this
+         country. -->
     <!-- http://www.itu.int/oth/T0202000097/en -->
     <territory id="AN" countryCode="599" internationalPrefix="00">
-      <availableFormats>
-        <numberFormat pattern="(\d{3})(\d{4})">
-          <leadingDigits>[13-7]</leadingDigits>
-          <format>$1 $2</format>
-        </numberFormat>
-        <numberFormat pattern="(9)(\d{3})(\d{4})">
-          <leadingDigits>9</leadingDigits>
-          <format>$1 $2 $3</format>
-        </numberFormat>
-      </availableFormats>
-      <generalDesc>
-        <nationalNumberPattern>[13-79]\d{6,7}</nationalNumberPattern>
-        <possibleNumberPattern>\d{7,8}</possibleNumberPattern>
-      </generalDesc>
-      <fixedLine>
-        <!-- The prefixes listed beginning with 5 are in fact for Sint Maarten and should be removed
-             when parallel running has ended (predicted to be September 2012). -->
-        <nationalNumberPattern>
-          (?:
-            318|
-            5(?:
-              25|
-              4\d|
-              8[239]
-            )|
-            7(?:
-              1[578]|
-              50
-            )|
-            9(?:
-              [48]\d{2}|
-              50\d|
-              7(?:
-                2[0-2]|
-                [34]\d|
-                6[35-7]|
-                77
-              )
-            )
-          )\d{4}|
-          416[0239]\d{3}
-        </nationalNumberPattern>
-        <exampleNumber>7151234</exampleNumber>
-      </fixedLine>
-      <mobile>
-        <nationalNumberPattern>
-          (?:
-            318|
-            5(?:
-              1[01]|
-              2[0-7]|
-              5\d|
-              8[016-8]
-            )|
-            7(?:
-              0[01]|
-              [89]\d
-            )|
-            9(?:
-              5(?:
-                [1246]\d|
-                3[01]
-              )|
-              6(?:
-                [1679]\d|
-                3[01]
-              )
-            )
-          )\d{4}|
-          416[15-8]\d{3}
-        </nationalNumberPattern>
-        <exampleNumber>3181234</exampleNumber>
-      </mobile>
-      <!-- Value-added services are lumped together under shared cost, since we are not sure exactly
-           what they are. -->
-      <sharedCost>
-        <nationalNumberPattern>
-          (?:
-            10|
-            69
-          )\d{5}
-        </nationalNumberPattern>
-        <exampleNumber>1011234</exampleNumber>
-      </sharedCost>
+      <!-- Shares formatting patterns with "CW". -->
+      <generalDesc>
+        <nationalNumberPattern>5\d{6}</nationalNumberPattern>
+        <possibleNumberPattern>\d{7}</possibleNumberPattern>
+      </generalDesc>
+      <fixedLine>
+        <nationalNumberPattern>
+          5(?:
+            4\d|
+            8[239]
+          )\d{4}
+        </nationalNumberPattern>
+        <exampleNumber>5451234</exampleNumber>
+      </fixedLine>
+      <mobile>
+        <nationalNumberPattern>
+          5(?:
+            1[01]|
+            2[0-7]|
+            5\d|
+            8[016-8]
+          )\d{4}
+        </nationalNumberPattern>
+        <exampleNumber>5101234</exampleNumber>
+      </mobile>
       <emergency>
         <!-- http://www.rijksdienstcn.com/index.php?view=pagina&id=126&set_language=EN -->
         <nationalNumberPattern>
         </nationalNumberPattern>
         <possibleNumberPattern>\d{5,12}</possibleNumberPattern>
       </generalDesc>
+      <noInternationalDialling>
+        <!-- According to the national numbering plan, service numbers are in general not accessible
+             from abroad, although 600/700/800 numbers may be. -->
+        <nationalNumberPattern>
+          [13]00\d{3,7}|
+          2(?:
+            0(?:
+              0\d{3,7}|
+              2[023]\d{1,6}|
+              9[89]\d{1,6}
+            )
+          )|
+          60(?:
+            [12]\d{5,6}|
+            6\d{7}
+          )|
+          7(?:
+            1\d{7}|
+            3\d{8}|
+            5[03-9]\d{2,7}
+          )
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{5,10}</possibleNumberPattern>
+        <exampleNumber>100123</exampleNumber>
+      </noInternationalDialling>
       <fixedLine>
         <nationalNumberPattern>18[1-8]\d{3,9}</nationalNumberPattern>
         <possibleNumberPattern>\d{6,12}</possibleNumberPattern>
         <exampleNumber>600123456</exampleNumber>
       </premiumRate>
       <uan>
-        <nationalNumberPattern>
-          10[1-9]\d{3,7}|
+        <!-- Covers nationwide non-geographic numbers, and nationwide "service numbers", typically
+             assigned to institutions such as universities, the national post, etc, where they are
+             not otherwise classified as toll-free or premium-rate numbers. -->
+        <nationalNumberPattern>
+          [13]0\d{4,8}|
           2(?:
             0(?:
-              [16-8]\d{3,7}|
-              2[14-9]\d{1,6}|
-              [3-5]\d{2,7}|
-              9[0-7]\d{1,6}
+              [016-8]\d{3,7}|
+              [2-59]\d{2,7}
             )|
             9\d{4,8}
           )|
-          30[1-9]\d{3,7}|
+          60(?:
+            [12]\d{5,6}|
+            6\d{7}
+          )|
           7(?:
             1\d{7}|
             3\d{8}|
         </numberFormat>
       </availableFormats>
       <generalDesc>
-        <nationalNumberPattern>[2457]\d{7}</nationalNumberPattern>
+        <nationalNumberPattern>[24-7]\d{7}</nationalNumberPattern>
         <possibleNumberPattern>\d{8}</possibleNumberPattern>
       </generalDesc>
       <fixedLine>
              since diallable numbers have been found outside the range that the document specifies.
              Including 716 as well since many numbers seem to have this prefix. -->
         <nationalNumberPattern>
-          7(?:
-            [02-68]\d|
-            1[0-4689]|
-            7[0-6]|
-            9[0-689]
+          (?:
+            60[0-3]|
+            7(?:
+              [02-68]\d|
+              1[0-4689]|
+              7[0-6]|
+              9[0-689]
+            )
           )\d{5}
         </nationalNumberPattern>
         <exampleNumber>70123456</exampleNumber>
         <possibleNumberPattern>\d{4}</possibleNumberPattern>
         <exampleNumber>7312</exampleNumber>
       </tollFree>
-      <!-- Other numbers beginning with 81 are reserved for _either_ free phone or shared-cost, but
-           there is no clear differentiation between these. -->
       <voip>
         <nationalNumberPattern>857[58]\d{4}</nationalNumberPattern>
         <possibleNumberPattern>\d{8}</possibleNumberPattern>
         <exampleNumber>85751234</exampleNumber>
       </voip>
+      <!-- Numbers beginning with 81 are reserved for _either_ free phone or shared-cost (same cost
+           as a local-call.) We model these as UAN since we have no more detailed information. -->
+      <uan>
+        <nationalNumberPattern>81\d{6}</nationalNumberPattern>
+        <possibleNumberPattern>\d{8}</possibleNumberPattern>
+        <exampleNumber>81123456</exampleNumber>
+      </uan>
       <emergency>
         <nationalNumberPattern>11[78]</nationalNumberPattern>
         <possibleNumberPattern>\d{3}</possibleNumberPattern>
       </emergency>
     </territory>
 
+    <!-- Bonaire, Sint Eustatius and Saba -->
+    <!-- http://www.itu.int/oth/T02020000F8/en -->
+    <territory id="BQ" countryCode="599" internationalPrefix="00">
+      <!-- Shares formatting patterns with CW. -->
+      <generalDesc>
+        <nationalNumberPattern>[347]\d{6}</nationalNumberPattern>
+        <possibleNumberPattern>\d{7}</possibleNumberPattern>
+      </generalDesc>
+      <fixedLine>
+        <nationalNumberPattern>
+          (?:
+            318[023]|
+            416[0239]|
+            7(?:
+              1[578]|
+              50
+            )\d
+          )\d{3}
+        </nationalNumberPattern>
+        <exampleNumber>7151234</exampleNumber>
+      </fixedLine>
+      <mobile>
+        <nationalNumberPattern>
+          (?:
+            318[1456]|
+            416[15-8]|
+            7(?:
+              0[01]|
+              [89]\d
+            )\d
+          )\d{3}|
+        </nationalNumberPattern>
+        <exampleNumber>3181234</exampleNumber>
+      </mobile>
+      <emergency>
+        <!-- http://www.rijksdienstcn.com/index.php?view=pagina&id=126&set_language=EN -->
+        <nationalNumberPattern>
+          112|
+          911
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{3}</possibleNumberPattern>
+        <exampleNumber>112</exampleNumber>
+      </emergency>
+    </territory>
+
     <!-- Brazil -->
     <!-- http://en.wikipedia.org/wiki/%2B55 -->
     <territory id="BR" countryCode="55"
         </numberFormat>
         <numberFormat pattern="([34]00\d)(\d{4})">
           <leadingDigits>[34]00</leadingDigits>
-          <leadingDigits>
-            400|
-            3003
-          </leadingDigits>
           <format>$1-$2</format>
         </numberFormat>
         <numberFormat nationalPrefixFormattingRule="$NP$FG"
         <possibleNumberPattern>\d{8,10}</possibleNumberPattern>
       </generalDesc>
       <noInternationalDialling>
-        <nationalNumberPattern>
-          (?:
-            400\d|
-            3003
-          )\d{4}
-        </nationalNumberPattern>
+        <nationalNumberPattern>[34]00\d{5}</nationalNumberPattern>
         <possibleNumberPattern>\d{8}</possibleNumberPattern>
         <exampleNumber>40041234</exampleNumber>
       </noInternationalDialling>
         <exampleNumber>300123456</exampleNumber>
       </premiumRate>
       <sharedCost>
-        <nationalNumberPattern>
-          (?:
-            400\d|
-            3003
-          )\d{4}
-        </nationalNumberPattern>
+        <nationalNumberPattern>[34]00\d{5}</nationalNumberPattern>
         <possibleNumberPattern>\d{8}</possibleNumberPattern>
         <exampleNumber>40041234</exampleNumber>
       </sharedCost>
     </territory>
 
     <!-- Bahamas -->
-    <!-- http://www.itu.int/dms_pub/itu-t/oth/02/02/T02020000100001MSWE.pdf -->
+    <!-- http://www.itu.int/oth/T0202000010/en -->
     <territory id="BS" countryCode="1" leadingDigits="242"
       nationalPrefix="1" internationalPrefix="011">
       <generalDesc>
               81
             )|
             5(?:
-              2[34]|
+              2[45]|
               3[35]|
               44|
               5[1-9]|
       </emergency>
     </territory>
 
+    <!-- Curaçao -->
+    <!-- http://www.itu.int/oth/T02020000F5/en -->
+    <territory id="CW" countryCode="599" internationalPrefix="00" mainCountryForCode="true">
+      <!-- All the formatting patterns for country-code 599 are here. -->
+      <availableFormats>
+        <numberFormat pattern="(\d{3})(\d{4})">
+          <leadingDigits>[13-7]</leadingDigits>
+          <format>$1 $2</format>
+        </numberFormat>
+        <numberFormat pattern="(9)(\d{3})(\d{4})">
+          <leadingDigits>9</leadingDigits>
+          <format>$1 $2 $3</format>
+        </numberFormat>
+      </availableFormats>
+      <generalDesc>
+        <nationalNumberPattern>[169]\d{6,7}</nationalNumberPattern>
+        <possibleNumberPattern>\d{7,8}</possibleNumberPattern>
+      </generalDesc>
+      <fixedLine>
+        <nationalNumberPattern>
+          9(?:
+            [48]\d{2}|
+            50\d|
+            7(?:
+              2[0-2]|
+              [34]\d|
+              6[35-7]|
+              77
+            )
+          )\d{4}
+        </nationalNumberPattern>
+        <exampleNumber>94151234</exampleNumber>
+      </fixedLine>
+      <mobile>
+        <nationalNumberPattern>
+          9(?:
+            5(?:
+              [1246]\d|
+              3[01]
+            )|
+            6(?:
+              [1679]\d|
+              3[01]
+            )
+          )\d{4}
+        </nationalNumberPattern>
+        <exampleNumber>95181234</exampleNumber>
+      </mobile>
+      <pager>
+        <nationalNumberPattern>955\d{5}</nationalNumberPattern>
+        <exampleNumber>95581234</exampleNumber>
+      </pager>
+      <sharedCost>
+        <!-- Value-added services are lumped together under shared cost, since we are not sure
+             exactly what they are. -->
+        <nationalNumberPattern>
+          (?:
+            10|
+            69
+          )\d{5}
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{7}</possibleNumberPattern>
+        <exampleNumber>1011234</exampleNumber>
+      </sharedCost>
+      <emergency>
+        <!-- http://www.rijksdienstcn.com/index.php?view=pagina&id=126&set_language=EN -->
+        <nationalNumberPattern>
+          112|
+          911
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{3}</possibleNumberPattern>
+        <exampleNumber>112</exampleNumber>
+      </emergency>
+    </territory>
+
     <!-- Cyprus -->
     <!-- http://www.itu.int/oth/T0202000034/en -->
     <territory id="CY" countryCode="357" internationalPrefix="00">
     <!-- http://www.itu.int/oth/T020200003A/en -->
     <territory id="DJ" countryCode="253" internationalPrefix="00">
       <availableFormats>
-        <!-- The number format here is suggested in the plan and used online,
-        although the phone numbers of the national numbering authority itself on
-        the plan do not follow this. -->
         <numberFormat pattern="(\d{2})(\d{2})(\d{2})">
           <format>$1 $2 $3</format>
         </numberFormat>
-      </availableFormats>
-      <generalDesc>
-        <nationalNumberPattern>[1-8]\d{5}</nationalNumberPattern>
-        <possibleNumberPattern>\d{6}</possibleNumberPattern>
-      </generalDesc>
-      <fixedLine>
-        <!-- Includes "Numéro long CDMA fixe" numbers starting with the digit 5. -->
+        <numberFormat pattern="(\d{2})(\d{2})(\d{2})(\d{2})">
+          <format>$1 $2 $3 $4</format>
+        </numberFormat>
+      </availableFormats>
+      <!--TODO: Remove support for 6-digit numbers after March 1st, 2012, when the national
+          numbering plan is going to migrate to 8 digits. -->
+      <generalDesc>
+        <nationalNumberPattern>[1-8]\d{5,7}</nationalNumberPattern>
+        <possibleNumberPattern>\d{6,8}</possibleNumberPattern>
+      </generalDesc>
+      <fixedLine>
+        <!-- Includes "Numéro long CDMA fixe" numbers. -->
         <nationalNumberPattern>
           (?:
             1[05]|
             [2-5]\d
-          )\d{4}
-        </nationalNumberPattern>
-        <exampleNumber>251234</exampleNumber>
-      </fixedLine>
-      <mobile>
-        <nationalNumberPattern>[6-8]\d{5}</nationalNumberPattern>
-        <exampleNumber>601234</exampleNumber>
+          )\d{4}|
+          2(?:
+            1[2-5]|
+            7[45]|
+          )\d{5}
+        </nationalNumberPattern>
+        <exampleNumber>21360003</exampleNumber>
+      </fixedLine>
+      <mobile>
+        <nationalNumberPattern>(?:77)?[6-8]\d{5}</nationalNumberPattern>
+        <exampleNumber>77831001</exampleNumber>
       </mobile>
       <emergency>
         <nationalNumberPattern>1[78]</nationalNumberPattern>
     <territory id="FI" countryCode="358" internationalPrefix="00|99[049]" nationalPrefix="0"
                nationalPrefixFormattingRule="$NP$FG" mainCountryForCode="true">
       <availableFormats>
+        <numberFormat pattern="(\d{3})(\d{3,7})">
+          <leadingDigits>
+            (?:
+              [1-3]00|
+              [6-8]0
+            )
+          </leadingDigits>
+          <format>$1 $2</format>
+        </numberFormat>
         <numberFormat pattern="(\d{2})(\d{4,10})">
           <leadingDigits>
             2[09]|
           </leadingDigits>
           <format>$1 $2</format>
         </numberFormat>
-        <numberFormat pattern="([6-8]00)(\d{4,7})">
-          <leadingDigits>[6-8]0</leadingDigits>
-          <format>$1 $2</format>
-        </numberFormat>
       </availableFormats>
       <generalDesc>
         <nationalNumberPattern>
         </nationalNumberPattern>
         <possibleNumberPattern>\d{5,12}</possibleNumberPattern>
       </generalDesc>
+      <noInternationalDialling>
+        <!-- According to the national numbering plan, service numbers are in general not accessible
+             from abroad, although 600/700/800 numbers may be. -->
+        <nationalNumberPattern>
+          [13]00\d{3,7}|
+          2(?:
+            0(?:
+              0\d{3,7}|
+              2[023]\d{1,6}|
+              9[89]\d{1,6}
+            )
+          )|
+          60(?:
+            [12]\d{5,6}|
+            6\d{7}
+          )|
+          7(?:
+            1\d{7}|
+            3\d{8}|
+            5[03-9]\d{2,7}
+          )
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{5,10}</possibleNumberPattern>
+        <exampleNumber>100123</exampleNumber>
+      </noInternationalDialling>
       <fixedLine>
         <!-- This is limited to geographic numbers - non-geographic nationwide subscriber numbers
              are listed under UAN. It also excludes Åland numbers. -->
         <exampleNumber>600123456</exampleNumber>
       </premiumRate>
       <uan>
-        <nationalNumberPattern>
-          10[1-9]\d{3,7}|
+        <!-- Covers nationwide non-geographic numbers, and nationwide "service numbers", typically
+             assigned to institutions such as universities, the national post, etc, where they are
+             not otherwise classified as toll-free or premium-rate numbers. -->
+        <nationalNumberPattern>
+          [13]0\d{4,8}|
           2(?:
             0(?:
-              [16-8]\d{3,7}|
-              2[14-9]\d{1,6}|
-              [3-5]\d{2,7}|
-              9[0-7]\d{1,6}
+              [016-8]\d{3,7}|
+              [2-59]\d{2,7}
             )|
             9\d{4,8}
           )|
-          30[1-9]\d{3,7}|
+          60(?:
+            [12]\d{5,6}|
+            6\d{7}
+          )|
           7(?:
             1\d{7}|
             3\d{8}|
                2[236-9]|
                3[0479]|
                4[0-68]|
-               5[0-579]
+               5[0-57-9]
                6[05789]
-               7[12569]|
+               7[123569]|
                8[0124-9]|
                9[02-9]
              )|
                  9[689]
                )|
                4(?:
-                 0[245789]|
+                 0[1245789]|
                  1[15-9]|
                  [29][89]|
                  39|
                  8[567]
                )|
                3(?:
-                 0[235-8]|
+                 0[0235-8]|
                  4[14789]|
                  74|
                  90
                  30|
                  4[47]|
                  53|
+                 85|
                  7[45]|
                  9[015]
                )|
                )|
                7(?:
                  1[24]|
+                 33|
                  [2569]
                )|
                8(?:
                  17|
                  2[024-8]|
                  44|
-                 5[389]|
+                 5[3589]|
                  6[0167]
                )|
                9(?:
                  [057-9]|
                  2[35-9]|
-                 3[09]|
+                 3[019]|
                  4[03678]|
                  6[0-46-9]
                )
         <!-- A couple of additional prefixes not found on the wikipedia page, are added because SMS
              messages have been successfully sent to these numbers. It seems almost impossible to
              know for some of these numbers whether they are land-line or mobile, since the ranges
-             overlap. Extra prefixes added: 7277, 730[124-689], 735[0-4789], 738[1-9], 740[47-9],
-             750[79], 7520, 7796, 787[2-4], 789[146], 810[0-8], 811[56], 812[0-2569], 814[0-35],
-             8171, 8179, 8197, 822[1-689], 823\d, 8252, 826[0-7], 827[01357], 828[567],
-             829[0-246-9], the ranges in 83X excepting 8303, 8344 and 8390, 840[0-57-9], 842[2-689],
-             843[0-59], 844[0-489], 845[0-24-9], 846[09], 847[0135], 848[0-8], 850[079], 8511,
-             852[0-689], 8530, 854[47], 857[45], 8595, 860[125-9], 865[03-79], 867[09], 868[0-579],
-             869[0-467], 8712, 872[013-9], 875[1-35-9], 876[0-8], 879[24589], 882[04], 885[89],
-             8887, 892[679], 894[6-8], 896[3469].  -->
+             overlap. Extra prefixes added: 7277, 730[124-689], 735[0-2478], 738[1-57], 740[479],
+             750[79], 7796, 787[34], 7896, 810[1-358], 811[56], 812[02569], 814[01], 8171, 8179,
+             822[1-689], 823[0-24-9], 826[0-35-7], 827[0137], 829[0-2479], the ranges in 83X
+             excepting 830[037], 834[14] and 8390, 840[02-57-9], 842[24-689], 843[0-59], 844[0-489],
+             845[0-24-689], 846[09], 847[0135], 848[0-8], 850[79], 852[02-589], 8530, 854[47], 8595,
+             860[1259], 865[03-79], 867[09], 868[349], 869[0-46], 872[013-9], 875[1-35-9],
+             876[0-47], 879[4589], 8824, 8859, 892[67], 894[6-8], 896[346].  -->
         <nationalNumberPattern>
           (?:
             7(?:
                 9[689]
               )|
               4(?:
-                0[245789]|
+                0[1245789]|
                 1[15-9]|
                 [29][89]|
                 39|
                 8[567]
               )|
               3(?:
-                0[235-8]|
+                0[0235-8]|
                 4[14789]|
                 74|
                 90
                 4[47]|
                 53|
                 7[45]|
+                85|
                 9[015]
               )|
               6(?:
               )|
               7(?:
                 1[24]|
+                33|
                 [2569]\d
               )|
               8(?:
                 17|
                 2[024-8]|
                 44|
-                5[389]|
+                5[3589]|
                 6[0167]
               )|
               9(?:
                 [057-9]\d|
                 2[35-9]|
-                3[09]|
+                3[019]|
                 4[036-8]|
                 6[0-46-9]
               )
 
     <!-- Latvia -->
     <!-- http://www.itu.int/oth/T0202000076/en -->
+    <!-- http://en.wikipedia.org/wiki/+371 -->
     <territory id="LV" countryCode="371" internationalPrefix="00">
       <availableFormats>
         <numberFormat pattern="([2689]\d)(\d{3})(\d{3})">
         <possibleNumberPattern>\d{8}</possibleNumberPattern>
       </generalDesc>
       <fixedLine>
-        <nationalNumberPattern>6\d{7}</nationalNumberPattern>
-        <exampleNumber>61234567</exampleNumber>
+        <nationalNumberPattern>6[3-8]\d{6}</nationalNumberPattern>
+        <exampleNumber>63123456</exampleNumber>
       </fixedLine>
       <mobile>
         <nationalNumberPattern>2\d{7}</nationalNumberPattern>
         <nationalNumberPattern>90\d{6}</nationalNumberPattern>
         <exampleNumber>90123456</exampleNumber>
       </premiumRate>
+      <sharedCost>
+        <nationalNumberPattern>81\d{6}</nationalNumberPattern>
+        <exampleNumber>81123456</exampleNumber>
+      </sharedCost>
       <emergency>
         <nationalNumberPattern>
           0[123]|
                nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG">
       <availableFormats>
         <numberFormat pattern="(\d)(\d{3})(\d{3})">
-          <leadingDigits>[13-5]</leadingDigits>
+          <leadingDigits>1</leadingDigits>
           <format>$1 $2 $3</format>
         </numberFormat>
         <numberFormat pattern="(2\d{2})(\d{3})(\d{3})">
           <leadingDigits>[1789]</leadingDigits>
           <format>$1 $2 $3 $4</format>
         </numberFormat>
-        <!-- Delete in Jan 2012. -->
-        <numberFormat pattern="(\d)(\d{3})(\d{3})">
-          <leadingDigits>[89]</leadingDigits>
-          <format>$1 $2 $3</format>
-        </numberFormat>
-      </availableFormats>
-      <!-- According to the plan, the switch from 7 to 9 digits for mobile numbers happened in July
-           2009. However, online numbers don't seem to reflect this - even on the telephone company
-           websites. Recent information provided by ITU stated that final migration happened on 30th
-           November 2011, and from December 1st only the 9-digit plan will be in use. We will delete
-           the old-format numbers in January 2010. -->
-      <generalDesc>
-        <nationalNumberPattern>
-          (?:
-            [3-5]|
-            [27]\d{2}|
-            [189](?:
+      </availableFormats>
+      <generalDesc>
+        <nationalNumberPattern>
+          (?:
+            1(?:
               \d{2}
-            )?
+            )?|
+            [2789]\d{2}
           )\d{6}
         </nationalNumberPattern>
         <possibleNumberPattern>\d{7,9}</possibleNumberPattern>
         <nationalNumberPattern>
           (?:
             111|
-            [3-5]|
             77\d|
-            8(?:
-              8\d
-            )?|
-            9(?:
-              9\d
-            )?
-          )\d{6}
-        </nationalNumberPattern>
+            88\d|
+            99\d
+          )\d{6}
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{9}</possibleNumberPattern>
         <exampleNumber>991234567</exampleNumber>
       </mobile>
       <emergency>
         </numberFormat>
       </availableFormats>
       <generalDesc>
-        <nationalNumberPattern>[1-36-9]\d{4,11}</nationalNumberPattern>
+        <!-- The complicated pattern here is to distinguish between Pristina (area code 38, followed
+             by 2-9) and the country calling code (381). -->
+        <nationalNumberPattern>
+          [126-9]\d{4,11}|
+          3(?:
+            [0-79]\d{3,10}|
+            8[2-9]\d{2,9}
+          )
+        </nationalNumberPattern>
         <possibleNumberPattern>\d{5,12}</possibleNumberPattern>
       </generalDesc>
       <fixedLine>
-        <nationalNumberPattern>[1-3]\d{6,11}</nationalNumberPattern>
+        <!-- Most subscriber numbers may not start with 0 or 1. Exceptionally, the prefix 11 1[5-7]
+             has been issused, so we allow 11 1X here. -->
+        <nationalNumberPattern>
+          (?:
+            1(?:
+              [02-9][2-9]|
+              1[1-9]
+            )\d|
+            2(?:
+              [0-24-7][2-9]\d|
+              [389](?:
+                0[2-9]|
+                [2-9]\d
+              )
+            )|
+            3(?:
+              [0-8][2-9]\d|
+              9(?:
+                [2-9]\d|
+                0[2-9]
+              )
+            )
+          )\d{3,8}
+        </nationalNumberPattern>
         <possibleNumberPattern>\d{5,12}</possibleNumberPattern>
-        <exampleNumber>101234567</exampleNumber>
+        <exampleNumber>10234567</exampleNumber>
       </fixedLine>
       <mobile>
         <nationalNumberPattern>
         <exampleNumber>4217123</exampleNumber>
       </fixedLine>
       <mobile>
+        <!-- Although wikipedia says the prefix 28 is as-of-yet unallocated, open-source users have
+             already reported seeing numbers with this prefix. -->
         <nationalNumberPattern>
           2(?:
             5(?:
             7(?:
               [0-79]\d|
               8[24-9]
-            )
+            )|
+            8\d{2}
           )\d{3}
         </nationalNumberPattern>
         <possibleNumberPattern>\d{7}</possibleNumberPattern>
       </emergency>
     </territory>
 
+    <!-- South Sudan -->
+    <!-- http://www.itu.int/oth/T02020000F9/en -->
+    <!-- http://en.wikipedia.org/wiki/+211 -->
+    <!-- These number sources disagree over whether the number length should be 7 or 10 digits. The
+         contact numbers for the South Sudan telecommunications authority, along with all numbers
+         seen online, are 9 digits, so we follow this instead. -->
+    <territory id="SS" countryCode="211" internationalPrefix="00" nationalPrefix="0">
+      <availableFormats>
+        <numberFormat pattern="(\d{3})(\d{3})(\d{3})" nationalPrefixFormattingRule="$NP$FG">
+          <format>$1 $2 $3</format>
+        </numberFormat>
+      </availableFormats>
+      <generalDesc>
+        <nationalNumberPattern>[1489]\d{8}</nationalNumberPattern>
+        <possibleNumberPattern>\d{9}</possibleNumberPattern>
+      </generalDesc>
+      <fixedLine>
+        <!-- 1[67] has been included as per the ITU document, even though no