Commits

Patrick Mézard committed 30e9d22 Merge

Merge with r426

Comments (0)

Files changed (34)

csharp/PhoneNumbers.Test/TestExampleNumbers.cs

 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Text.RegularExpressions;
 using NUnit.Framework;
 
 namespace PhoneNumbers.Test
         }
 
         [Test]
+        public void TestVoicemail()
+        {
+            HashSet<PhoneNumberType> voicemailTypes = MakeSet(PhoneNumberType.VOICEMAIL);
+            checkNumbersValidAndCorrectType(PhoneNumberType.VOICEMAIL, voicemailTypes);
+            Assert.AreEqual(0, invalidCases.Count);
+            Assert.AreEqual(0, wrongTypeCases.Count);
+        }
+
+        [Test]
         public void TestSharedCost()
         {
             HashSet<PhoneNumberType> sharedCostTypes = MakeSet(PhoneNumberType.SHARED_COST);
                 if (exampleNumber != null && phoneNumberUtil.CanBeInternationallyDialled(exampleNumber))
                 {
                     wrongTypeCases.Add(exampleNumber);
+                    // LOGGER.log(Level.SEVERE, "Number " + exampleNumber.toString()
+                    //   + " should not be internationally diallable");
                 }
             }
             Assert.AreEqual(0, wrongTypeCases.Count);
         }
 
+        // TODO: Update this to use connectsToEmergencyNumber or similar once that is
+        // implemented.
+        [Test]
+        public void TestEmergency()
+        {
+            int wrongTypeCounter = 0;
+            foreach(var regionCode in phoneNumberUtil.GetSupportedRegions())
+            {
+                PhoneNumberDesc desc =
+                    phoneNumberUtil.GetMetadataForRegion(regionCode).Emergency;
+                if (desc.HasExampleNumber)
+                {
+                    String exampleNumber = desc.ExampleNumber;
+                    if (!new PhoneRegex(desc.PossibleNumberPattern).MatchAll(exampleNumber).Success ||
+                        !new PhoneRegex(desc.NationalNumberPattern).MatchAll(exampleNumber).Success)
+                    {
+                        wrongTypeCounter++;
+                    // LOGGER.log(Level.SEVERE, "Emergency example number test failed for " + regionCode);
+                    }
+                }
+            }
+            Assert.AreEqual(0, wrongTypeCounter);
+        }
+
+        [Test]
+        public void TestGlobalNetworkNumbers()
+        {
+            foreach(var callingCode in phoneNumberUtil.GetSupportedGlobalNetworkCallingCodes())
+            {
+                PhoneNumber exampleNumber =
+                    phoneNumberUtil.GetExampleNumberForNonGeoEntity(callingCode);
+                Assert.NotNull(exampleNumber, "No example phone number for calling code " + callingCode);
+                if (!phoneNumberUtil.IsValidNumber(exampleNumber))
+                {
+                    invalidCases.Add(exampleNumber);
+                    // LOGGER.log(Level.SEVERE, "Failed validation for " + exampleNumber.toString());
+                }
+            }
+        }
+
         [Test]
         public void TestEveryRegionHasAnExampleNumber()
         {
-            foreach(var regionCode in phoneNumberUtil.GetSupportedRegions())
+            foreach (var regionCode in phoneNumberUtil.GetSupportedRegions())
             {
                 PhoneNumber exampleNumber = phoneNumberUtil.GetExampleNumber(regionCode);
                 Assert.IsNotNull(exampleNumber, "None found for region " + regionCode);

csharp/PhoneNumbers.Test/TestPhoneNumberMatcher.cs

     new NumberTest("1/12/2011", "US"),
     new NumberTest("10/12/82", "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("1979-2011 100", RegionCode.US),
     new NumberTest("+494949-4-94", "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.
   };
 
         /**

csharp/PhoneNumbers.Test/TestPhoneNumberUtil.cs

             Assert.AreEqual("+1 (650) 253-0000", phoneUtil.FormatByPattern(US_NUMBER,
                 PhoneNumberFormat.INTERNATIONAL,
                 newNumberFormats));
+            Assert.AreEqual("+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.
             Assert.That(phoneUtil.IsValidNumberForRegion(reNumber, RegionCode.RE));
             Assert.That(phoneUtil.IsValidNumberForRegion(INTERNATIONAL_TOLL_FREE, RegionCode.UN001));
             Assert.False(phoneUtil.IsValidNumberForRegion(INTERNATIONAL_TOLL_FREE, RegionCode.US));
+
+            Assert.False(phoneUtil.IsValidNumberForRegion(INTERNATIONAL_TOLL_FREE, RegionCode.ZZ));
+
+            PhoneNumber invalidNumber;
+            // Invalid country calling codes.
+            invalidNumber = new PhoneNumber.Builder().SetCountryCode(3923).SetNationalNumber(2366L).Build();
+            Assert.False(phoneUtil.IsValidNumberForRegion(invalidNumber, RegionCode.ZZ));
+            invalidNumber = new PhoneNumber.Builder().SetCountryCode(3923).SetNationalNumber(2366L).Build();
+            Assert.False(phoneUtil.IsValidNumberForRegion(invalidNumber, RegionCode.UN001));
+            invalidNumber = new PhoneNumber.Builder().SetCountryCode(0).SetNationalNumber(2366L).Build();
+            Assert.False(phoneUtil.IsValidNumberForRegion(invalidNumber, RegionCode.UN001));
+            invalidNumber = new PhoneNumber.Builder().SetCountryCode(0).Build();
+            Assert.False(phoneUtil.IsValidNumberForRegion(invalidNumber, RegionCode.ZZ));
         }
 
         [Test]
                 .SetCountryCode(64).SetNationalNumber(3316005L).Build();
             Assert.False(phoneUtil.IsValidNumber(invalidNumber));
 
+            // Invalid country calling codes.
+            invalidNumber = new PhoneNumber.Builder().SetCountryCode(3923).SetNationalNumber(2366L).Build();
+            Assert.False(phoneUtil.IsValidNumber(invalidNumber));
+            invalidNumber = new PhoneNumber.Builder().SetCountryCode(0).SetNationalNumber(2366L).Build();
+            Assert.False(phoneUtil.IsValidNumber(invalidNumber));
+
             Assert.False(phoneUtil.IsValidNumber(INTERNATIONAL_TOLL_FREE_TOO_LONG));
         }
 
             PhoneNumber usNumber = new PhoneNumber.Builder()
                 .SetCountryCode(1).SetNationalNumber(1234567890L).Build();
             Assert.AreEqual(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.
+            Assert.AreEqual(JP_STAR_NUMBER, phoneUtil.Parse("+81 *2345", RegionCode.JP));
         }
 
         [Test]
             }
             try
             {
+                String plusStar = "+***";
+                phoneUtil.Parse(plusStar, RegionCode.DE);
+                Assert.Fail("This should not parse without throwing an exception " + plusStar);
+            }
+            catch (NumberParseException e)
+            {
+                // Expected this exception.
+                Assert.AreEqual(
+                   ErrorType.NOT_A_NUMBER,
+                   e.ErrorType,
+                   "Wrong error type stored in exception.");
+            }
+            try
+            {
+                String plusStarPhoneNumber = "+*******91";
+                phoneUtil.Parse(plusStarPhoneNumber, RegionCode.DE);
+                Assert.Fail("This should not parse without throwing an exception " + plusStarPhoneNumber);
+            }
+            catch (NumberParseException e)
+            {
+                // Expected this exception.
+                Assert.AreEqual(
+                   ErrorType.NOT_A_NUMBER,
+                   e.ErrorType,
+                   "Wrong error type stored in exception.");
+            }
+            try
+            {
                 String tooShortPhoneNumber = "+49 0";
                 phoneUtil.Parse(tooShortPhoneNumber, RegionCode.DE);
                 Assert.Fail("This should not parse without throwing an exception " + tooShortPhoneNumber);

csharp/PhoneNumbers/CountryCodeToRegionCodeMap.cs

         // indicated with "isMainCountryForCode" in the metadata should be first.
         public static Dictionary<int, 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.
-            var countryCodeToRegionCodeMap = new Dictionary<int, List<String>>(280);
+            var countryCodeToRegionCodeMap = new Dictionary<int, List<String>>(281);
 
             List<String> listWithRegionCode = new List<String>(25);
             listWithRegionCode.Add("US");
             countryCodeToRegionCodeMap[98] = listWithRegionCode;
 
             listWithRegionCode = new List<String>(1);
+            listWithRegionCode.Add("SS");
+            countryCodeToRegionCodeMap[211] = listWithRegionCode;
+
+            listWithRegionCode = new List<String>(1);
             listWithRegionCode.Add("MA");
             countryCodeToRegionCodeMap[212] = listWithRegionCode;
 
             listWithRegionCode.Add("UY");
             countryCodeToRegionCodeMap[598] = listWithRegionCode;
 
-            listWithRegionCode = new List<String>(1);
+            listWithRegionCode = new List<String>(3);
+            listWithRegionCode.Add("CW");
             listWithRegionCode.Add("AN");
+            listWithRegionCode.Add("BQ");
             countryCodeToRegionCodeMap[599] = listWithRegionCode;
 
             listWithRegionCode = new List<String>(1);

csharp/PhoneNumbers/PhoneNumberMatcher.cs

             new Regex("(?:(?:[0-3]?\\d/[01]?\\d)|(?:[01]?\\d/[0-3]?\\d))/(?:[12]\\d)?\\d{2}", RegexOptions.Compiled);
 
         /**
+        * 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 readonly Regex TIME_STAMPS =
+            new Regex("[12]\\d{3}[-/]?[01]\\d[-/]?[0-3]\\d [0-2]\\d$", RegexOptions.Compiled);
+        private static readonly PhoneRegex TIME_STAMPS_SUFFIX = new PhoneRegex(":[0-5]\\d", RegexOptions.Compiled);
+
+
+        /**
         * 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.
             // Skip a match that is more likely a publication page reference or a date.
             if (PUB_PAGES.Match(candidate).Success || SLASH_SEPARATED_DATES.Match(candidate).Success)
                 return null;
+            // Skip potential time-stamps.
+            if (TIME_STAMPS.Match(candidate).Success)
+            {
+                String followingText = text.ToString().Substring(offset + candidate.Length);
+                if (TIME_STAMPS_SUFFIX.MatchBeginning(followingText).Success)
+                    return null;
+            }
+
             // Try to come up with a valid match given the entire candidate.
             String rawString = candidate;
             PhoneNumberMatch match = ParseAndVerify(rawString, offset);

csharp/PhoneNumbers/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 online numbers can be
+             found. -->
+        <nationalNumberPattern>
+          (?:
+            1[67]\d|
+            811
+          )\d{6}
+        </nationalNumberPattern>
+        <exampleNumber>811123456</exampleNumber>
+      </fixedLine>
+      <mobile>
+        <!-- Online numbers indicate that 95 is used by Vivacell, [49]77 by Gemtel, 91 by Zain,
+             9[29] by MTN (although it is unclear if 477 is still in use). 12 has been ascribed
+             to "Sudani", but it is not clear whether they are in fact still operating in South
+             Sudan. Patterns here are derived entirely from numbers found online. -->
+        <nationalNumberPattern>
+          (?:
+            1(?:
+              02|
+              2[1269]
+            )|
+            477|
+            9(?:
+              0[03689]|
+              1\d|
+              2[024-9]|
+              5[5-79]|
+              77|
+              98
+            )
+          )\d{6}
+        </nationalNumberPattern>
+        <exampleNumber>977123456</exampleNumber>
+      </mobile>
+    </territory>
+
     <!-- Sao Tome and Principe -->
     <!-- http://www.itu.int/oth/T02020000B6/en -->
     <territory id="ST" countryCode="239" internationalPrefix="00">
 
     <!-- Sint Maarten -->
     <!-- http://www.nanpa.com/pdf/PL_429.pdf -->
+    <!-- http://www.itu.int/oth/T02020000F7/en -->
     <territory id="SX" countryCode="1" leadingDigits="721"
       nationalPrefix="1" internationalPrefix="011">
       <generalDesc>
                nationalPrefix="0" nationalPrefixFormattingRule="$NP$FG"
                nationalPrefixOptionalWhenFormatting="true">
       <availableFormats>
+        <numberFormat pattern="([17]99)(\d{4})">
+          <leadingDigits>[17]99</leadingDigits>
+          <format>$1 $2</format>
+        </numberFormat>
         <numberFormat pattern="([48])(\d{4})(\d{4})">
           <leadingDigits>[48]</leadingDigits>
           <format>$1 $2 $3</format>
             2[025-79]|
             3[0136-9]|
             5[2-9]|
-            6[0-46-9]|
+            6[0-46-8]|
             7[02-79]
           </leadingDigits>
           <format>$1 $2 $3</format>
           <leadingDigits>
             1(?:
               [26]|
-              88|
+              8[68]|
               99
             )
           </leadingDigits>
       </availableFormats>
       <generalDesc>
         <nationalNumberPattern>
-          8\d{5,8}|
-          [1-79]\d{7,9}
+          [17]\d{6,9}|
+          [2-69]\d{7,9}|
+          8\d{6,8}
         </nationalNumberPattern>
         <possibleNumberPattern>\d{7,10}</possibleNumberPattern>
       </generalDesc>
+      <noInternationalDialling>
+        <nationalNumberPattern>
+          [17]99\d{4}|
+          69\d{5,6}
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{7,8}</possibleNumberPattern>
+        <exampleNumber>1992000</exampleNumber>
+      </noInternationalDialling>
       <fixedLine>
         <nationalNumberPattern>
           (?:
               [0136-9]|
               [25][01]
             )|
-            [48]\d|
+            4\d|
             5(?:
               [01][01]|
               [2-9]
             7(?:
               [02-79]|
               [18][01]
-            )
-          )\d{7}|
-          69\d{5,6}|
-          80\d{5}
-        </nationalNumberPattern>
-        <possibleNumberPattern>\d{7,10}</possibleNumberPattern>
+            )|
+            8[1-9]
+          )\d{7}
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{9,10}</possibleNumberPattern>
         <exampleNumber>2101234567</exampleNumber>
       </fixedLine>
       <mobile>
             1(?:
               2\d|
               6[3-9]|
-              88|
+              8[68]|
               99
             )
           )\d{7}
         <possibleNumberPattern>\d{8,10}</possibleNumberPattern>
         <exampleNumber>1900123456</exampleNumber>
       </premiumRate>
+      <uan>
+        <!-- These include non-geographic fixed numbers, such as for government ministries. While
+        listed as "private networks", they may actually be callable from within Vietnam. (They are
+        "private" in the sense that ordinary people could not be assigned these numbers.) -->
+        <nationalNumberPattern>
+          [17]99\d{4}|
+          69\d{5,6}|
+          80\d{5}
+        </nationalNumberPattern>
+        <possibleNumberPattern>\d{7,8}</possibleNumberPattern>
+        <exampleNumber>1992000</exampleNumber>
+      </uan>
       <emergency>
         <nationalNumberPattern>11[345]</nationalNumberPattern>
         <possibleNumberPattern>\d{3}</possibleNumberPattern>

csharp/PhoneNumbers/PhoneNumberUtil.cs

         // The PLUS_SIGN signifies the international prefix.
         internal const char PLUS_SIGN = '+';
 
+        private const char STAR_SIGN = '*';
+
         const String RFC3966_EXTN_PREFIX = ";ext=";
 
         // A map that contains characters that are essential when dialling. That means any of the
 
         internal const String PLUS_CHARS = "+\uFF0B";
         internal static readonly PhoneRegex PLUS_CHARS_PATTERN = new PhoneRegex("[" + PLUS_CHARS + "]+", RegexOptions.Compiled);
-        private static readonly Regex SEPARATOR_PATTERN = new Regex("[" + VALID_PUNCTUATION + "]+", RegexOptions.Compiled);
+        private static readonly PhoneRegex SEPARATOR_PATTERN = new PhoneRegex("[" + VALID_PUNCTUATION + "]+", RegexOptions.Compiled);
         private static readonly Regex CAPTURING_DIGIT_PATTERN;
 
         // Regular expression of acceptable characters that may start a phone number for the purposes of
         // 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])*
-        // Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
+        // plus_sign*(([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
         private static readonly String VALID_PHONE_NUMBER;
 
         // Default extension prefix to use when formatting. This will be put in front of any extension
 
             CAPTURING_EXTN_DIGITS = "(" + DIGITS + "{1,7})";
             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 + "]*";
 
             // One-character symbols that can be used to indicate an extension.
             String singleExtnSymbolsForMatching = "x\uFF58#\uFF03~\uFF5E";
         }
 
         /**
+        * Convenience method to get a list of what global network calling codes the library has metadata
+        * for.
+        */
+        public Dictionary<int, PhoneMetadata>.KeyCollection GetSupportedGlobalNetworkCallingCodes()
+        {
+            return countryCodeToNonGeographicalMetadataMap.Keys;
+        }
+
+        /**
         * 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
             }
 
             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;
 
-            var userDefinedFormatsCopy = new List<NumberFormat>(userDefinedFormats.Count);
             PhoneMetadata metadata = GetMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
-            foreach (var numFormat in userDefinedFormats)
+            StringBuilder formattedNumber = new StringBuilder(20);
+            NumberFormat formattingPattern =
+                ChooseFormattingPatternForNumber(userDefinedFormats, nationalSignificantNumber);
+            if (formattingPattern == null)
             {
-                var nationalPrefixFormattingRule = numFormat.NationalPrefixFormattingRule;
+                // If no pattern above is matched, we format the number as a whole.
+                formattedNumber.Append(nationalSignificantNumber);
+            }
+            else
+            {
+                var numFormatCopy = new NumberFormat.Builder();
+                // 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.NationalPrefixFormattingRule;
                 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.
-                    var numFormatCopy = new NumberFormat.Builder();
-                    numFormatCopy.MergeFrom(numFormat);
                     String nationalPrefix = metadata.NationalPrefix;
                     if (nationalPrefix.Length > 0)
                     {
                         // 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.Build());
                 }
-                else
-                {
-                    // Otherwise, we just add the original rule to the modified list of formats.
-                    userDefinedFormatsCopy.Add(numFormat);
-                }
+                formattedNumber.Append(
+                    FormatNsnUsingPattern(nationalSignificantNumber, numFormatCopy.Build(), numberFormat));
             }
-
-            var 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();
         }
 
 
             var formattedNumber = new StringBuilder(20);
             PhoneMetadata metadata = GetMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
-            formattedNumber.Append(FormatNationalNumber(nationalSignificantNumber,
+            formattedNumber.Append(FormatNsn(nationalSignificantNumber,
                 metadata, PhoneNumberFormat.NATIONAL, carrierCode));
-            MaybeGetFormattedExtension(number, metadata, PhoneNumberFormat.NATIONAL, formattedNumber);
-            FormatNumberByFormat(countryCallingCode, PhoneNumberFormat.NATIONAL, formattedNumber);
+            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.CountryCode;
             var nationalSignificantNumber = GetNationalSignificantNumber(number);
             if (!HasValidCountryCallingCode(countryCallingCode))
                     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.
             PhoneMetadata metadataForRegion =
                 GetMetadataForRegionOrCallingCode(countryCallingCode, regionCode);
             String formattedNationalNumber =
-                FormatNationalNumber(nationalSignificantNumber,
+                FormatNsn(nationalSignificantNumber,
                     metadataForRegion, PhoneNumberFormat.INTERNATIONAL);
             var formattedNumber = new StringBuilder(formattedNationalNumber);
-            MaybeGetFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL,
+            MaybeAppendFormattedExtension(number, metadataForRegion, PhoneNumberFormat.INTERNATIONAL,
                 formattedNumber);
             if (internationalPrefixForFormatting.Length > 0)
             {
             }
             else
             {
-                FormatNumberByFormat(countryCallingCode, PhoneNumberFormat.INTERNATIONAL,
+                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))
+            else if (IsValidRegionCode(regionCallingFrom) &&
+                countryCode == GetCountryCodeForValidRegion(regionCallingFrom))
             {
-                // Here we copy the formatting rules so we can modify the pattern we expect to match against.
-                var availableFormats = new List<NumberFormat>(metadataForRegionCallingFrom.NumberFormatCount);
-                foreach (var format in metadataForRegionCallingFrom.NumberFormatList)
-                {
-                    var newFormat = new NumberFormat.Builder();
-                    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.Build());
-                }
-                // 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 formattingPattern =
+                    ChooseFormattingPatternForNumber(metadataForRegionCallingFrom.NumberFormatList,
+                        nationalNumber);
+                if (formattingPattern == null)
+                    // If no pattern above is matched, we format the original input.
+                    return rawInput;
+
+                var newFormat = new NumberFormat.Builder();
+                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.Build(), PhoneNumberFormat.NATIONAL);
             }
             String internationalPrefixForFormatting = "";
             // If an unsupported region-calling-from is entered, or a country with multiple international
             var formattedNumber = new StringBuilder(rawInput);
             String regionCode = GetRegionCodeForCountryCode(countryCode);
             PhoneMetadata metadataForRegion = GetMetadataForRegionOrCallingCode(countryCode, regionCode);
-            MaybeGetFormattedExtension(number, metadataForRegion,
+            MaybeAppendFormattedExtension(number, metadataForRegion,
                 PhoneNumberFormat.INTERNATIONAL, formattedNumber);
             if (internationalPrefixForFormatting.Length > 0)
             {
             {
                 // 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, PhoneNumberFormat.INTERNATIONAL,
+                PrefixNumberWithCountryCallingCode(countryCode, PhoneNumberFormat.INTERNATIONAL,
                     formattedNumber);
             }
             return formattedNumber.ToString();
         /**
         * A helper function that is used by format and formatByPattern.
         */
-        private void FormatNumberByFormat(int countryCallingCode,
+        private void PrefixNumberWithCountryCallingCode(int countryCallingCode,
             PhoneNumberFormat numberFormat, StringBuilder formattedNumber)
         {
             switch (numberFormat)
             }
         }
 
-        // Simple wrapper of formatNationalNumber for the common case of no carrier code.
-        private String FormatNationalNumber(String number,
-            PhoneMetadata metadata,
-            PhoneNumberFormat numberFormat)
+        // Simple wrapper of formatNsn for the common case of no carrier code.
+        private String FormatNsn(String number, PhoneMetadata metadata, PhoneNumberFormat numberFormat)
         {
-            return FormatNationalNumber(number, metadata, numberFormat, null);
+            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,
+        private String FormatNsn(String number,
             PhoneMetadata metadata,
             PhoneNumberFormat numberFormat,
             String carrierCode)
                 (intlNumberFormats.Count == 0 || numberFormat == PhoneNumberFormat.NATIONAL)
                 ? metadata.NumberFormatList
                 : metadata.IntlNumberFormatList;
-            var formattedNationalNumber =
-                FormatAccordingToFormats(number, availableFormats, numberFormat, carrierCode);
-            if (numberFormat == PhoneNumberFormat.RFC3966)
-                formattedNationalNumber = SEPARATOR_PATTERN.Replace(formattedNationalNumber, "-");
-            return formattedNationalNumber;
+            NumberFormat formattingPattern = ChooseFormattingPatternForNumber(availableFormats, number);
+            return (formattingPattern == null)
+                ? number
+                : FormatNsnUsingPattern(number, formattingPattern, numberFormat, carrierCode);
         }
 
         private NumberFormat ChooseFormattingPatternForNumber(IList<NumberFormat> availableFormats,
         }
 
 
-        // Simple wrapper of formatAccordingToFormats for the common case of no carrier code.
-        private String FormatAccordingToFormats(String nationalNumber,
-            List<NumberFormat> availableFormats, PhoneNumberFormat numberFormat)
+        // Simple wrapper of formatNsnUsingPattern for the common case of no carrier code.
+        private String FormatNsnUsingPattern(String nationalNumber,
+             NumberFormat formattingPattern, PhoneNumberFormat numberFormat)
         {
-            return FormatAccordingToFormats(nationalNumber, availableFormats, numberFormat, null);
+            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, IList<NumberFormat> availableFormats,
+        private String FormatNsnUsingPattern(String nationalNumber, NumberFormat formattingPattern,
             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;
-            }
-            var matcher = regexCache.GetPatternForRegex(numFormat.Pattern);
-            var numberFormatRule = numFormat.Format;
+            String numberFormatRule = formattingPattern.Format;
+            var m = regexCache.GetPatternForRegex(formattingPattern.Pattern);
+            String formattedNationalNumber = "";
             if (numberFormat == PhoneNumberFormat.NATIONAL &&
                 carrierCode != null && carrierCode.Length > 0 &&
-                numFormat.DomesticCarrierCodeFormattingRule.Length > 0)
+                formattingPattern.DomesticCarrierCodeFormattingRule.Length > 0)
             {
                 // Replace the $CC in the formatting rule with the desired carrier code.
-                var carrierCodeFormattingRule = numFormat.DomesticCarrierCodeFormattingRule;
+                var carrierCodeFormattingRule = formattingPattern.DomesticCarrierCodeFormattingRule;
                 carrierCodeFormattingRule =
                     CC_PATTERN.Replace(carrierCodeFormattingRule, carrierCode, 1);
                 // 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.Replace(numberFormatRule, carrierCodeFormattingRule, 1);
-                return matcher.Replace(nationalNumber, numberFormatRule);
+                var r = FIRST_GROUP_PATTERN.Replace(numberFormatRule, carrierCodeFormattingRule, 1);
+                formattedNationalNumber = m.Replace(nationalNumber, r);
             }
             else
             {
                 // Use the national prefix formatting rule instead.
-                var nationalPrefixFormattingRule = numFormat.NationalPrefixFormattingRule;
+                var nationalPrefixFormattingRule = formattingPattern.NationalPrefixFormattingRule;
                 if (numberFormat == PhoneNumberFormat.NATIONAL &&
                     nationalPrefixFormattingRule != null &&
                     nationalPrefixFormattingRule.Length > 0)
                 {
-                    numberFormatRule = FIRST_GROUP_PATTERN.Replace(numberFormatRule,
+                    var r = FIRST_GROUP_PATTERN.Replace(numberFormatRule,
                         nationalPrefixFormattingRule, 1);
-                    return matcher.Replace(nationalNumber, numberFormatRule);
+                    formattedNationalNumber = m.Replace(nationalNumber, r);
                 }
                 else
                 {
-                    return matcher.Replace(nationalNumber, numberFormatRule);
+                    formattedNationalNumber = m.Replace(nationalNumber, numberFormatRule);
                 }
             }
+            if (numberFormat == PhoneNumberFormat.RFC3966)
+            {
+                // Strip any leading punctuation.
+                if (SEPARATOR_PATTERN.MatchBeginning(formattedNationalNumber).Success)
+                {
+                    formattedNationalNumber = SEPARATOR_PATTERN.Replace(formattedNationalNumber, "", 1);
+                }
+                // Replace the rest with a dash between each number group.
+                formattedNationalNumber = SEPARATOR_PATTERN.Replace(formattedNationalNumber, "-");
+            }
+            return formattedNationalNumber;
         }
 
         /**
                     //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,
+        private void MaybeAppendFormattedExtension(PhoneNumber number, PhoneMetadata metadata,
             PhoneNumberFormat numberFormat, StringBuilder formattedNumber)
         {
             if (number.HasExtension && number.Extension.Length > 0)
                 }
                 else
                 {
-                    FormatExtension(number.Extension, metadata, formattedNumber);
+                    if (metadata.HasPreferredExtnPrefix)
+                        formattedNumber.Append(metadata.PreferredExtnPrefix).Append(number.Extension);
+                    else
+                        formattedNumber.Append(DEFAULT_EXTN_PREFIX).Append(number.Extension);
                 }
             }
         }
 
-        /**
-        * 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.PreferredExtnPrefix).Append(extensionDigits);
-            else
-                extension.Append(DEFAULT_EXTN_PREFIX).Append(extensionDigits);
-        }
-
         PhoneNumberDesc GetNumberDescByType(PhoneMetadata metadata, PhoneNumberType type)
         {
             switch (type)
         public bool IsValidNumberForRegion(PhoneNumber number, String regionCode)
         {
             int countryCode = number.CountryCode;
-            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)))
             {
-              return false;
+                // Either the region code was invalid, or the country calling code for this number does not
+                // match that of the region code.
+                return false;
             }
-            var metadata = GetMetadataForRegionOrCallingCode(countryCode, regionCode);
             var generalNumDesc = metadata.GeneralDesc;
             var nationalSignificantNumber = GetNationalSignificantNumber(number);
 
         {
             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.CountryCode;
         }
         {
             if (!IsValidRegionCode(regionCode))
             {
-                //LOGGER.log(Level.SEVERE,
+                //LOGGER.log(Level.WARNING,
                 //    "Invalid or missing region code ("
                 //    + ((regionCode == null) ? "null" : regionCode)
                 //    + ") provided.");

csharp/PhoneNumbers/Properties/AssemblyInfo.cs

 //
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
-// [assembly: AssemblyVersion("4.5.0.10")]
-[assembly: AssemblyVersion("4.5.0.10")]
-[assembly: AssemblyFileVersion("4.5.0.10")]
+// [assembly: AssemblyVersion("4.5.0.11")]
+[assembly: AssemblyVersion("4.5.0.11")]
+[assembly: AssemblyFileVersion("4.5.0.11")]

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