Project import
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d9a10c0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,176 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..532bd0a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,76 @@
+# libPhoneNumber for iOS (ARC)
+
+* NBPhoneNumber, NBNumberFormat, NBPhoneNumberDesc, NBPhoneMetaData (Metadata classes) 
+
+* NBPhoneNumberUtil (from phonenumberutil.js)
+* NBAsYouTypeFormatter 
+
+## Install with CocoaPods
+### Use [CocoaPods](http://cocoapods.org/?q=libPhoneNumber-iOS)
+
+## Install without CocoaPods
+### Add source files to your projects from libPhoneNumber
+    - NBPhoneNumberUtil.h, .m
+    - NBAsYouTypeFormatter.h, .m
+    
+    - NBNumberFormat.h, .m
+    - NBPhoneNumber.h, .m
+    - NBPhoneNumberDesc.h, .m
+    - NBPhoneNumberDefines.h
+    
+    - NBPhoneNumberMetadata.h, .m
+    - NBPhoneNumberMetadataForTesting.h, .m
+    
+    - Add "NBPhoneNumberMetadata.plist" and "NBPhoneNumberMetadataForTesting.plist" to bundle resources
+    - Add "CoreTelephony.framework"
+
+    See sample test code from "libPhoneNumber-iOS / libPhoneNumberTests / libPhoneNumberTests.m"
+
+## Sample Usage
+    NBPhoneNumberUtil *phoneUtil = [NBPhoneNumberUtil sharedInstance];
+    
+    NSError *aError = nil;
+    NBPhoneNumber *myNumber = [phoneUtil parse:@"6766077303" defaultRegion:@"AT" error:&aError];
+    
+    if (aError == nil) {
+        // Should check error
+        NSLog(@"isValidPhoneNumber ? [%@]", [phoneUtil isValidNumber:myNumber] ? @"YES":@"NO");
+        NSLog(@"E164          : %@", [phoneUtil format:myNumber numberFormat:NBEPhoneNumberFormatE164 
+                                                 error:&aError]);
+        NSLog(@"INTERNATIONAL : %@", [phoneUtil format:myNumber numberFormat:NBEPhoneNumberFormatINTERNATIONAL 
+                                                 error:&aError]);
+        NSLog(@"NATIONAL      : %@", [phoneUtil format:myNumber numberFormat:NBEPhoneNumberFormatNATIONAL 
+                                                 error:&aError]);
+        NSLog(@"RFC3966       : %@", [phoneUtil format:myNumber numberFormat:NBEPhoneNumberFormatRFC3966 
+                                                 error:&aError]);
+    }
+    else {
+        NSLog(@"Error : %@", [aError localizedDescription]);
+    }
+    
+    NSLog (@"extractCountryCode [%ld]", [phoneUtil extractCountryCode:@"823213123123" 
+                                                       nationalNumber:nil]);
+    
+    NSString *res = nil;
+    UInt32 dRes = [phoneUtil extractCountryCode:@"823213123123" nationalNumber:&res];
+    
+    NSLog (@"extractCountryCode [%lu] [%@]", dRes, res);
+
+
+### Visit http://code.google.com/p/libphonenumber/ for more information
+#### or zen.isis@gmail.com
+
+## Metadata managing (updating metadata) 
+#### Step1. Fetch "metadata.js" and "metadatafortesting.js" from Repositories
+    svn checkout http://libphonenumber.googlecode.com/svn/trunk/ libphonenumber-read-only
+      
+#### Step2. Convert Javascript Object to JSON using PHP scripts 
+    Output - "PhoneNumberMetaData.json" and "PhoneNumberMetaDataForTesting.json"
+
+#### Step3. Generate binary file from NBPhoneMetaDataGenerator
+    Output - "NBPhoneNumberMetadata.plist" and "NBPhoneNumberMetadataForTesting.plist"
+
+#### Step4. Update exists "NBPhoneNumberMetadata.plist" and "NBPhoneNumberMetadataForTesting.plist" files
+
+## Porting Rules
+* **Remain** javascript libPhonenumber code logic (and comments etc) as possible for maintenance with *.js
diff --git a/libPhoneNumber/NBAsYouTypeFormatter.h b/libPhoneNumber/NBAsYouTypeFormatter.h
new file mode 100644
index 0000000..c994fd5
--- /dev/null
+++ b/libPhoneNumber/NBAsYouTypeFormatter.h
@@ -0,0 +1,21 @@
+//
+//  NBAsYouTypeFormatter.h
+//  libPhoneNumber
+//
+//  Created by ishtar on 13. 2. 25..
+//  Copyright (c) 2013년 NHN. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NBAsYouTypeFormatter : NSObject
+
+- (id)initWithRegionCode:(NSString*)regionCode;
+- (id)initWithRegionCodeForTest:(NSString*)regionCode;
+
+- (NSString*)inputDigit:(NSString*)nextChar;
+- (NSString*)inputDigitAndRememberPosition:(NSString*)nextChar;
+- (NSInteger)getRememberedPosition;
+- (void)clear;
+
+@end
diff --git a/libPhoneNumber/NBAsYouTypeFormatter.m b/libPhoneNumber/NBAsYouTypeFormatter.m
new file mode 100644
index 0000000..742199d
--- /dev/null
+++ b/libPhoneNumber/NBAsYouTypeFormatter.m
@@ -0,0 +1,1146 @@
+//
+//  NBAsYouTypeFormatter.m
+//  libPhoneNumber
+//
+//  Created by ishtar on 13. 2. 25..
+//  Copyright (c) 2013년 NHN. All rights reserved.
+//
+
+#import "NBAsYouTypeFormatter.h"
+
+#import "NBPhoneNumberUtil.h"
+#import "NBPhoneMetaData.h"
+#import "NBNumberFormat.h"
+
+
+@interface NBAsYouTypeFormatter ()
+
+@property (nonatomic, strong, readwrite) NSString *DIGIT_PLACEHOLDER_;
+@property (nonatomic, assign, readwrite) NSString *SEPARATOR_BEFORE_NATIONAL_NUMBER_;
+@property (nonatomic, strong, readwrite) NSString *currentOutput_, *currentFormattingPattern_;
+@property (nonatomic, strong, readwrite) NSString *defaultCountry_;
+@property (nonatomic, strong, readwrite) NSString *nationalPrefixExtracted_;
+@property (nonatomic, strong, readwrite) NSMutableString *formattingTemplate_, *accruedInput_, *prefixBeforeNationalNumber_, *accruedInputWithoutFormatting_, *nationalNumber_;
+@property (nonatomic, strong, readwrite) NSRegularExpression *DIGIT_PATTERN_, *NATIONAL_PREFIX_SEPARATORS_PATTERN_, *CHARACTER_CLASS_PATTERN_, *STANDALONE_DIGIT_PATTERN_;
+@property (nonatomic, strong, readwrite) NSRegularExpression *ELIGIBLE_FORMAT_PATTERN_;
+@property (nonatomic, assign, readwrite) BOOL ableToFormat_, inputHasFormatting_, isCompleteNumber_, isExpectingCountryCallingCode_, shouldAddSpaceAfterNationalPrefix_;
+@property (nonatomic, strong, readwrite) NBPhoneNumberUtil *phoneUtil_;
+@property (nonatomic, assign, readwrite) NSUInteger lastMatchPosition_, originalPosition_, positionToRemember_;
+@property (nonatomic, assign, readwrite) NSUInteger MIN_LEADING_DIGITS_LENGTH_;
+@property (nonatomic, strong, readwrite) NSMutableArray *possibleFormats_;
+@property (nonatomic, strong, readwrite) NBPhoneMetaData *currentMetaData_, *defaultMetaData_, *EMPTY_METADATA_;
+
+@end
+
+
+@implementation NBAsYouTypeFormatter
+
+- (id)init
+{
+    self = [super init];
+    
+    if (self) {
+        /**
+         * @type {i18n.phonenumbers.PhoneNumberUtil}
+         * @private
+         */
+        self.phoneUtil_ = [NBPhoneNumberUtil sharedInstance];
+        
+        /**
+         * The digits that have not been entered yet will be represented by a \u2008,
+         * the punctuation space.
+         * @const
+         * @type {string}
+         * @private
+         */
+        self.DIGIT_PLACEHOLDER_ = @"\u2008";
+        
+        /**
+         * Character used when appropriate to separate a prefix, such as a long NDD or a
+         * country calling code, from the national number.
+         * @const
+         * @type {string}
+         * @private
+         */
+        self.SEPARATOR_BEFORE_NATIONAL_NUMBER_ = @" ";
+        
+        /**
+         * This is the minimum length of national number accrued that is required to
+         * trigger the formatter. The first element of the leadingDigitsPattern of
+         * each numberFormat contains a regular expression that matches up to this
+         * number of digits.
+         * @const
+         * @type {number}
+         * @private
+         */
+        self.MIN_LEADING_DIGITS_LENGTH_ = 3;
+        
+        /**
+         * @type {string}
+         * @private
+         */
+        self.currentOutput_ = @"";
+        
+        /**
+         * @type {!goog.string.StringBuffer}
+         * @private
+         */
+        self.formattingTemplate_ = [NSMutableString stringWithString:@""];
+        
+        NSError *aError = nil;
+        
+        /**
+         * @type {RegExp}
+         * @private
+         */
+        self.DIGIT_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:self.DIGIT_PLACEHOLDER_ options:0 error:&aError];
+        
+        /**
+         * A set of characters that, if found in a national prefix formatting rules, are
+         * an indicator to us that we should separate the national prefix from the
+         * number when formatting.
+         * @const
+         * @type {RegExp}
+         * @private
+         */
+        self.NATIONAL_PREFIX_SEPARATORS_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:@"[- ]" options:0 error:&aError];
+        
+        /**
+         * A pattern that is used to match character classes in regular expressions.
+         * An example of a character class is [1-4].
+         * @const
+         * @type {RegExp}
+         * @private
+         */
+        self.CHARACTER_CLASS_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:@"\\[([^\\[\\]])*\\]" options:0 error:&aError];
+        
+        /**
+         * Any digit in a regular expression that actually denotes a digit. For
+         * example, in the regular expression 80[0-2]\d{6,10}, the first 2 digits
+         * (8 and 0) are standalone digits, but the rest are not.
+         * Two look-aheads are needed because the number following \\d could be a
+         * two-digit number, since the phone number can be as long as 15 digits.
+         * @const
+         * @type {RegExp}
+         * @private
+         */
+        self.STANDALONE_DIGIT_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:@"\\d(?=[^,}][^,}])" options:0 error:&aError];
+        
+        /**
+         * A pattern that is used to determine if a numberFormat under availableFormats
+         * is eligible to be used by the AYTF. It is eligible when the format element
+         * under numberFormat contains groups of the dollar sign followed by a single
+         * digit, separated by valid phone number punctuation. This prevents invalid
+         * punctuation (such as the star sign in Israeli star numbers) getting into the
+         * output of the AYTF.
+         * @const
+         * @type {RegExp}
+         * @private
+         */
+        NSString *eligible_format = @"^[-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~]*(\\$\\d[-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~]*)+$";
+        self.ELIGIBLE_FORMAT_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:eligible_format options:0 error:&aError];
+        
+        /**
+         * The pattern from numberFormat that is currently used to create
+         * formattingTemplate.
+         * @type {string}
+         * @private
+         */
+        self.currentFormattingPattern_ = @"";
+        
+        /**
+         * @type {!goog.string.StringBuffer}
+         * @private
+         */
+        self.accruedInput_ = [NSMutableString stringWithString:@""];
+        
+        /**
+         * @type {!goog.string.StringBuffer}
+         * @private
+         */
+        self.accruedInputWithoutFormatting_ = [NSMutableString stringWithString:@""];
+        
+        /**
+         * This indicates whether AsYouTypeFormatter is currently doing the
+         * formatting.
+         * @type {BOOL}
+         * @private
+         */
+        self.ableToFormat_ = YES;
+        
+        /**
+         * Set to YES when users enter their own formatting. AsYouTypeFormatter will
+         * do no formatting at all when this is set to YES.
+         * @type {BOOL}
+         * @private
+         */
+        self.inputHasFormatting_ = NO;
+        
+        /**
+         * This is set to YES when we know the user is entering a full national
+         * significant number, since we have either detected a national prefix or an
+         * international dialing prefix. When this is YES, we will no longer use
+         * local number formatting patterns.
+         * @type {BOOL}
+         * @private
+         */
+        self.isCompleteNumber_ = NO;
+        
+        /**
+         * @type {BOOL}
+         * @private
+         */
+        self.isExpectingCountryCallingCode_ = NO;
+        
+        /**
+         * @type {number}
+         * @private
+         */
+        self.lastMatchPosition_ = 0;
+        
+        /**
+         * The position of a digit upon which inputDigitAndRememberPosition is most
+         * recently invoked, as found in the original sequence of characters the user
+         * entered.
+         * @type {number}
+         * @private
+         */
+        self.originalPosition_ = 0;
+        
+        /**
+         * The position of a digit upon which inputDigitAndRememberPosition is most
+         * recently invoked, as found in accruedInputWithoutFormatting.
+         * entered.
+         * @type {number}
+         * @private
+         */
+        self.positionToRemember_ = 0;
+        
+        /**
+         * This contains anything that has been entered so far preceding the national
+         * significant number, and it is formatted (e.g. with space inserted). For
+         * example, this can contain IDD, country code, and/or NDD, etc.
+         * @type {!goog.string.StringBuffer}
+         * @private
+         */
+        self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""];
+        
+        /**
+         * @type {BOOL}
+         * @private
+         */
+        self.shouldAddSpaceAfterNationalPrefix_ = NO;
+        
+        /**
+         * This contains the national prefix that has been extracted. It contains only
+         * digits without formatting.
+         * @type {string}
+         * @private
+         */
+        self.nationalPrefixExtracted_ = @"";
+        
+        /**
+         * @type {!goog.string.StringBuffer}
+         * @private
+         */
+        self.nationalNumber_ = [NSMutableString stringWithString:@""];
+        
+        /**
+         * @type {Array.<i18n.phonenumbers.NumberFormat>}
+         * @private
+         */
+        self.possibleFormats_ = [[NSMutableArray alloc] init];
+    }
+    
+    return self;
+}
+
+/**
+ * Constructs an AsYouTypeFormatter for the specific region.
+ *
+ * @param {string} regionCode the ISO 3166-1 two-letter region code that denotes
+ *     the region where the phone number is being entered.
+ * @constructor
+ */
+
+- (id)initWithRegionCode:(NSString*)regionCode
+{
+    self = [self init];
+    
+    if (self) {
+        /**
+         * @type {string}
+         * @private
+         */
+        self.defaultCountry_ = regionCode;
+        self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_];
+        /**
+         * @type {i18n.phonenumbers.PhoneMetadata}
+         * @private
+         */
+        self.defaultMetaData_ = self.currentMetaData_;
+        
+        /**
+         * @const
+         * @type {i18n.phonenumbers.PhoneMetadata}
+         * @private
+         */
+        self.EMPTY_METADATA_ = [[NBPhoneMetaData alloc] init];
+        [self.EMPTY_METADATA_ setInternationalPrefix:@"NA"];
+    }
+    
+    return self;
+}
+
+- (id)initWithRegionCodeForTest:(NSString*)regionCode
+{
+    self = [self init];
+    
+    if (self) {
+        self.phoneUtil_ = [NBPhoneNumberUtil sharedInstanceForTest];
+        
+        self.defaultCountry_ = regionCode;
+        self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_];
+        self.defaultMetaData_ = self.currentMetaData_;
+        self.EMPTY_METADATA_ = [[NBPhoneMetaData alloc] init];
+        [self.EMPTY_METADATA_ setInternationalPrefix:@"NA"];
+    }
+    
+    return self;
+}
+
+/**
+ * The metadata needed by this class is the same for all regions sharing the
+ * same country calling code. Therefore, we return the metadata for "main"
+ * region for this country calling code.
+ * @param {string} regionCode an ISO 3166-1 two-letter region code.
+ * @return {i18n.phonenumbers.PhoneMetadata} main metadata for this region.
+ * @private
+ */
+- (NBPhoneMetaData*)getMetadataForRegion_:(NSString*)regionCode
+{
+    
+    /** @type {number} */
+    NSNumber *countryCallingCode = [self.phoneUtil_ getCountryCodeForRegion:regionCode];
+    /** @type {string} */
+    NSString *mainCountry = [self.phoneUtil_ getRegionCodeForCountryCode:countryCallingCode];
+    /** @type {i18n.phonenumbers.PhoneMetadata} */
+    NBPhoneMetaData *metadata = [self.phoneUtil_ getMetadataForRegion:mainCountry];
+    if (metadata != nil) {
+        return metadata;
+    }
+    // Set to a default instance of the metadata. This allows us to function with
+    // an incorrect region code, even if formatting only works for numbers
+    // specified with '+'.
+    return self.EMPTY_METADATA_;
+};
+
+
+/**
+ * @return {BOOL} YES if a new template is created as opposed to reusing the
+ *     existing template.
+ * @private
+ */
+- (BOOL)maybeCreateNewTemplate_
+{
+    // When there are multiple available formats, the formatter uses the first
+    // format where a formatting template could be created.
+    /** @type {number} */
+    NSUInteger possibleFormatsLength = [self.possibleFormats_ count];
+    for (NSUInteger i = 0; i < possibleFormatsLength; ++i)
+    {
+        /** @type {i18n.phonenumbers.NumberFormat} */
+        NBNumberFormat *numberFormat = [self.possibleFormats_ safeObjectAtIndex:i];
+        /** @type {string} */
+        NSString *pattern = numberFormat.pattern;
+        
+        if ([self.currentFormattingPattern_ isEqualToString:pattern]) {
+            return NO;
+        }
+        
+        if ([self createFormattingTemplate_:numberFormat ])
+        {
+            self.currentFormattingPattern_ = pattern;
+            NSRange nationalPrefixRange = NSMakeRange(0, [numberFormat.nationalPrefixFormattingRule length]);
+            if (nationalPrefixRange.length > 0) {
+                NSTextCheckingResult *matchResult =
+                [self.NATIONAL_PREFIX_SEPARATORS_PATTERN_ firstMatchInString:numberFormat.nationalPrefixFormattingRule
+                                                                     options:0
+                                                                       range:nationalPrefixRange];
+                self.shouldAddSpaceAfterNationalPrefix_ = (matchResult != nil);
+            } else {
+                self.shouldAddSpaceAfterNationalPrefix_ = NO;
+            }
+            // With a new formatting template, the matched position using the old
+            // template needs to be reset.
+            self.lastMatchPosition_ = 0;
+            return YES;
+        }
+    }
+    self.ableToFormat_ = NO;
+    return NO;
+};
+
+
+/**
+ * @param {string} leadingThreeDigits first three digits of entered number.
+ * @private
+ */
+- (void)getAvailableFormats_:(NSString*)leadingThreeDigits
+{
+    /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
+    BOOL isIntlNumberFormats = (self.isCompleteNumber_ && self.currentMetaData_.intlNumberFormats.count > 0);
+    NSMutableArray *formatList = isIntlNumberFormats ? self.currentMetaData_.intlNumberFormats : self.currentMetaData_.numberFormats;
+    
+    /** @type {number} */
+    NSUInteger formatListLength = formatList.count;
+    
+    for (NSUInteger i = 0; i < formatListLength; ++i)
+    {
+        /** @type {i18n.phonenumbers.NumberFormat} */
+        NBNumberFormat *format = [formatList safeObjectAtIndex:i];
+        /** @type {BOOL} */
+        BOOL nationalPrefixIsUsedByCountry = (self.currentMetaData_.nationalPrefix && self.currentMetaData_.nationalPrefix.length > 0);
+        
+        if (!nationalPrefixIsUsedByCountry || self.isCompleteNumber_ || format.nationalPrefixOptionalWhenFormatting ||
+            [self.phoneUtil_ formattingRuleHasFirstGroupOnly:format.nationalPrefixFormattingRule])
+        {
+            if ([self isFormatEligible_:format.format]) {
+                [self.possibleFormats_ addObject:format];
+            }
+        }
+    }
+    
+    [self narrowDownPossibleFormats_:leadingThreeDigits];
+};
+
+
+/**
+ * @param {string} format
+ * @return {BOOL}
+ * @private
+ */
+- (BOOL)isFormatEligible_:(NSString*)format
+{
+    NSTextCheckingResult *matchResult =
+        [self.ELIGIBLE_FORMAT_PATTERN_ firstMatchInString:format options:0 range:NSMakeRange(0, [format length])];
+    return (matchResult != nil);
+};
+
+
+/**
+ * @param {string} leadingDigits
+ * @private
+ */
+- (void)narrowDownPossibleFormats_:(NSString *)leadingDigits
+{
+    /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
+    NSMutableArray *possibleFormats = [[NSMutableArray alloc] init];
+    /** @type {number} */
+    NSUInteger indexOfLeadingDigitsPattern = leadingDigits.length - self.MIN_LEADING_DIGITS_LENGTH_;
+    /** @type {number} */
+    NSUInteger possibleFormatsLength = self.possibleFormats_.count;
+    for (NSUInteger i = 0; i < possibleFormatsLength; ++i)
+    {
+        /** @type {i18n.phonenumbers.NumberFormat} */
+        NBNumberFormat *format = [self.possibleFormats_ safeObjectAtIndex:i];
+        if (format.leadingDigitsPatterns.count > indexOfLeadingDigitsPattern)
+        {
+            /** @type {string} */
+            NSString *leadingDigitsPattern = [format.leadingDigitsPatterns safeObjectAtIndex:indexOfLeadingDigitsPattern];
+            
+            if ([self.phoneUtil_ stringPositionByRegex:leadingDigits regex:leadingDigitsPattern] == 0)
+            {
+                [possibleFormats addObject:format];
+            }
+        } else {
+            // else the particular format has no more specific leadingDigitsPattern,
+            // and it should be retained.
+            [possibleFormats addObject:[self.possibleFormats_ safeObjectAtIndex:i]];
+        }
+    }
+    self.possibleFormats_ = possibleFormats;
+};
+
+
+/**
+ * @param {i18n.phonenumbers.NumberFormat} format
+ * @return {BOOL}
+ * @private
+ */
+- (BOOL)createFormattingTemplate_:(NBNumberFormat*)format
+{
+    /** @type {string} */
+    NSString *numberPattern = format.pattern;
+    
+    // The formatter doesn't format numbers when numberPattern contains '|', e.g.
+    // (20|3)\d{4}. In those cases we quickly return.
+    NSRange stringRange = [numberPattern rangeOfString:@"|"];
+    if (stringRange.location != NSNotFound) {
+        return NO;
+    }
+    
+    // Replace anything in the form of [..] with \d
+    numberPattern = [self.CHARACTER_CLASS_PATTERN_ stringByReplacingMatchesInString:numberPattern
+                                                                            options:0 range:NSMakeRange(0, [numberPattern length])
+                                                                       withTemplate:@"\\\\d"];
+    
+    // Replace any standalone digit (not the one in d{}) with \d
+    numberPattern = [self.STANDALONE_DIGIT_PATTERN_ stringByReplacingMatchesInString:numberPattern
+                                                                             options:0 range:NSMakeRange(0, [numberPattern length])
+                                                                        withTemplate:@"\\\\d"];
+    self.formattingTemplate_ = [NSMutableString stringWithString:@""];
+    
+    /** @type {string} */
+    NSString *tempTemplate = [self getFormattingTemplate_:numberPattern numberFormat:format.format];
+    if (tempTemplate.length > 0) {
+        [self.formattingTemplate_ appendString:tempTemplate];
+        return YES;
+    }
+    return NO;
+};
+
+
+/**
+ * Gets a formatting template which can be used to efficiently format a
+ * partial number where digits are added one by one.
+ *
+ * @param {string} numberPattern
+ * @param {string} numberFormat
+ * @return {string}
+ * @private
+ */
+- (NSString*)getFormattingTemplate_:(NSString*)numberPattern numberFormat:(NSString*)numberFormat
+{
+    // Creates a phone number consisting only of the digit 9 that matches the
+    // numberPattern by applying the pattern to the longestPhoneNumber string.
+    /** @type {string} */
+    NSString *longestPhoneNumber = @"999999999999999";
+    
+    /** @type {Array.<string>} */
+    NSArray *m = [self.phoneUtil_ matchedStringByRegex:longestPhoneNumber regex:numberPattern];
+    
+    // this match will always succeed
+    /** @type {string} */
+    NSString *aPhoneNumber = [m safeObjectAtIndex:0];
+    // No formatting template can be created if the number of digits entered so
+    // far is longer than the maximum the current formatting rule can accommodate.
+    if (aPhoneNumber.length < self.nationalNumber_.length) {
+        return @"";
+    }
+    // Formats the number according to numberFormat
+    /** @type {string} */
+    NSString *template = [self.phoneUtil_ replaceStringByRegex:aPhoneNumber regex:numberPattern withTemplate:numberFormat];
+    
+    // Replaces each digit with character DIGIT_PLACEHOLDER
+    template = [self.phoneUtil_ replaceStringByRegex:template regex:@"9" withTemplate:self.DIGIT_PLACEHOLDER_];
+    return template;
+};
+
+
+/**
+ * Clears the internal state of the formatter, so it can be reused.
+ */
+- (void)clear
+{
+    self.currentOutput_ = @"";
+    self.accruedInput_ = [NSMutableString stringWithString:@""];
+    self.accruedInputWithoutFormatting_ = [NSMutableString stringWithString:@""];
+    self.formattingTemplate_ = [NSMutableString stringWithString:@""];
+    self.lastMatchPosition_ = 0;
+    self.currentFormattingPattern_ = @"";
+    self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""];
+    self.nationalPrefixExtracted_ = @"";
+    self.nationalNumber_ = [NSMutableString stringWithString:@""];
+    self.ableToFormat_ = YES;
+    self.inputHasFormatting_ = NO;
+    self.positionToRemember_ = 0;
+    self.originalPosition_ = 0;
+    self.isCompleteNumber_ = NO;
+    self.isExpectingCountryCallingCode_ = NO;
+    [self.possibleFormats_ removeAllObjects];
+    self.shouldAddSpaceAfterNationalPrefix_ = NO;
+    
+    if (self.currentMetaData_ != self.defaultMetaData_) {
+        self.currentMetaData_ = [self getMetadataForRegion_:self.defaultCountry_];
+    }
+}
+
+
+/**
+ * Formats a phone number on-the-fly as each digit is entered.
+ *
+ * @param {string} nextChar the most recently entered digit of a phone number.
+ *     Formatting characters are allowed, but as soon as they are encountered
+ *     this method formats the number as entered and not 'as you type' anymore.
+ *     Full width digits and Arabic-indic digits are allowed, and will be shown
+ *     as they are.
+ * @return {string} the partially formatted phone number.
+ */
+- (NSString*)inputDigit:(NSString*)nextChar
+{
+    self.currentOutput_ = [self inputDigitWithOptionToRememberPosition_:nextChar rememberPosition:NO];
+    return self.currentOutput_;
+}
+
+
+/**
+ * Same as {@link #inputDigit}, but remembers the position where
+ * {@code nextChar} is inserted, so that it can be retrieved later by using
+ * {@link #getRememberedPosition}. The remembered position will be automatically
+ * adjusted if additional formatting characters are later inserted/removed in
+ * front of {@code nextChar}.
+ *
+ * @param {string} nextChar
+ * @return {string}
+ */
+- (NSString*)inputDigitAndRememberPosition:(NSString*)nextChar
+{
+    self.currentOutput_ = [self inputDigitWithOptionToRememberPosition_:nextChar rememberPosition:YES];
+    return self.currentOutput_;
+};
+
+
+/**
+ * @param {string} nextChar
+ * @param {BOOL} rememberPosition
+ * @return {string}
+ * @private
+ */
+- (NSString*)inputDigitWithOptionToRememberPosition_:(NSString*)nextChar rememberPosition:(BOOL)rememberPosition
+{
+    [self.accruedInput_ appendString:nextChar];
+    
+    if (rememberPosition) {
+        self.originalPosition_ = self.accruedInput_.length;
+    }
+    
+    // We do formatting on-the-fly only when each character entered is either a
+    // digit, or a plus sign (accepted at the start of the number only).
+    if (![self isDigitOrLeadingPlusSign_:nextChar])
+    {
+        self.ableToFormat_ = NO;
+        self.inputHasFormatting_ = YES;
+    } else {
+        nextChar = [self normalizeAndAccrueDigitsAndPlusSign_:nextChar rememberPosition:rememberPosition];
+    }
+    
+    if (!self.ableToFormat_) {
+        // When we are unable to format because of reasons other than that
+        // formatting chars have been entered, it can be due to really long IDDs or
+        // NDDs. If that is the case, we might be able to do formatting again after
+        // extracting them.
+        if (self.inputHasFormatting_) {
+            return [NSString stringWithString:self.accruedInput_];
+        }
+        else if ([self attemptToExtractIdd_]) {
+            if ([self attemptToExtractCountryCallingCode_]) {
+                return [self attemptToChoosePatternWithPrefixExtracted_];
+            }
+        }
+        else if ([self ableToExtractLongerNdd_]) {
+            // Add an additional space to separate long NDD and national significant
+            // number for readability. We don't set shouldAddSpaceAfterNationalPrefix_
+            // to YES, since we don't want this to change later when we choose
+            // formatting templates.
+            [self.prefixBeforeNationalNumber_ appendString:[NSString stringWithFormat: @"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_]];
+            return [self attemptToChoosePatternWithPrefixExtracted_];
+        }
+        return self.accruedInput_;
+    }
+    
+    // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
+    // digits (the plus sign is counted as a digit as well for this purpose) have
+    // been entered.
+    switch (self.accruedInputWithoutFormatting_.length)
+    {
+        case 0:
+        case 1:
+        case 2:
+            return self.accruedInput_;
+        case 3:
+            if ([self attemptToExtractIdd_]) {
+                self.isExpectingCountryCallingCode_ = YES;
+            } else {
+                // No IDD or plus sign is found, might be entering in national format.
+                self.nationalPrefixExtracted_ = [self removeNationalPrefixFromNationalNumber_];
+                return [self attemptToChooseFormattingPattern_];
+            }
+        default:
+            if (self.isExpectingCountryCallingCode_) {
+                if ([self attemptToExtractCountryCallingCode_]) {
+                    self.isExpectingCountryCallingCode_ = NO;
+                }
+                return [NSString stringWithFormat:@"%@%@", self.prefixBeforeNationalNumber_, self.nationalNumber_];
+            }
+            
+            if (self.possibleFormats_.count > 0) {
+                // The formatting pattern is already chosen.
+                /** @type {string} */
+                NSString *tempNationalNumber = [self inputDigitHelper_:nextChar];
+                // See if the accrued digits can be formatted properly already. If not,
+                // use the results from inputDigitHelper, which does formatting based on
+                // the formatting pattern chosen.
+                /** @type {string} */
+                NSString *formattedNumber = [self attemptToFormatAccruedDigits_];
+                if (formattedNumber.length > 0) {
+                    return formattedNumber;
+                }
+                
+                [self narrowDownPossibleFormats_:self.nationalNumber_];
+                
+                if ([self maybeCreateNewTemplate_]) {
+                    return [self inputAccruedNationalNumber_];
+                }
+                
+                return self.ableToFormat_ ? [self appendNationalNumber_:tempNationalNumber] : self.accruedInput_;
+            }
+            else {
+                return [self attemptToChooseFormattingPattern_];
+            }
+    }
+};
+
+
+/**
+ * @return {string}
+ * @private
+ */
+- (NSString*)attemptToChoosePatternWithPrefixExtracted_
+{
+    self.ableToFormat_ = YES;
+    self.isExpectingCountryCallingCode_ = NO;
+    [self.possibleFormats_ removeAllObjects];
+    return [self attemptToChooseFormattingPattern_];
+};
+
+
+/**
+ * Some national prefixes are a substring of others. If extracting the shorter
+ * NDD doesn't result in a number we can format, we try to see if we can extract
+ * a longer version here.
+ * @return {BOOL}
+ * @private
+ */
+- (BOOL)ableToExtractLongerNdd_
+{
+    if (self.nationalPrefixExtracted_.length > 0)
+    {
+        // Put the extracted NDD back to the national number before attempting to
+        // extract a new NDD.
+        /** @type {string} */
+        NSString *nationalNumberStr = [NSString stringWithString:self.nationalNumber_];
+        self.nationalNumber_ = [NSMutableString stringWithString:@""];
+        [self.nationalNumber_ appendString:self.nationalPrefixExtracted_];
+        [self.nationalNumber_ appendString:nationalNumberStr];
+        // Remove the previously extracted NDD from prefixBeforeNationalNumber. We
+        // cannot simply set it to empty string because people sometimes incorrectly
+        // enter national prefix after the country code, e.g. +44 (0)20-1234-5678.
+        /** @type {string} */
+        NSString *prefixBeforeNationalNumberStr = [NSString stringWithString:self.prefixBeforeNationalNumber_];
+        NSRange lastRange = [prefixBeforeNationalNumberStr rangeOfString:self.nationalPrefixExtracted_ options:NSBackwardsSearch];
+        /** @type {number} */
+        NSUInteger indexOfPreviousNdd = lastRange.location;
+        self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""];
+        [self.prefixBeforeNationalNumber_ appendString:[prefixBeforeNationalNumberStr substringWithRange:NSMakeRange(0, indexOfPreviousNdd)]];
+    }
+    
+    return self.nationalPrefixExtracted_ != [self removeNationalPrefixFromNationalNumber_];
+};
+
+
+/**
+ * @param {string} nextChar
+ * @return {BOOL}
+ * @private
+ */
+- (BOOL)isDigitOrLeadingPlusSign_:(NSString*)nextChar
+{
+    NSString *digitPattern = [NSString stringWithFormat:@"([%@])", [self.phoneUtil_ VALID_DIGITS_STRING]];
+    NSString *plusPattern = [NSString stringWithFormat:@"[%@]+", [self.phoneUtil_ PLUS_CHARS_]];
+    
+    BOOL isDigitPattern = [[self.phoneUtil_ matchesByRegex:nextChar regex:digitPattern] count] > 0;
+    BOOL isPlusPattern = [[self.phoneUtil_ matchesByRegex:nextChar regex:plusPattern] count] > 0;
+    
+    return isDigitPattern || (self.accruedInput_.length == 1 && isPlusPattern);
+};
+
+
+/**
+ * Check to see if there is an exact pattern match for these digits. If so, we
+ * should use this instead of any other formatting template whose
+ * leadingDigitsPattern also matches the input.
+ * @return {string}
+ * @private
+ */
+- (NSString*)attemptToFormatAccruedDigits_
+{
+    /** @type {string} */
+    NSString *nationalNumber = [NSString stringWithString:self.nationalNumber_];
+    
+    /** @type {number} */
+    NSUInteger possibleFormatsLength = self.possibleFormats_.count;
+    for (NSUInteger i = 0; i < possibleFormatsLength; ++i)
+    {
+        /** @type {i18n.phonenumbers.NumberFormat} */
+        NBNumberFormat *numberFormat = self.possibleFormats_[i];
+        /** @type {string} */
+        NSString * pattern = numberFormat.pattern;
+        /** @type {RegExp} */
+        NSString *patternRegExp = [NSString stringWithFormat:@"^(?:%@)$", pattern];
+        BOOL isPatternRegExp = [[self.phoneUtil_ matchesByRegex:nationalNumber regex:patternRegExp] count] > 0;
+        if (isPatternRegExp) {
+            if (numberFormat.nationalPrefixFormattingRule.length > 0) {
+                NSArray *matches = [self.NATIONAL_PREFIX_SEPARATORS_PATTERN_ matchesInString:numberFormat.nationalPrefixFormattingRule
+                                                                                     options:0
+                                                                                       range:NSMakeRange(0, numberFormat.nationalPrefixFormattingRule.length)];
+                self.shouldAddSpaceAfterNationalPrefix_ = [matches count] > 0;
+            } else {
+                self.shouldAddSpaceAfterNationalPrefix_ = NO;
+            }
+            
+            /** @type {string} */
+            NSString *formattedNumber = [self.phoneUtil_ replaceStringByRegex:nationalNumber
+                                                                        regex:pattern
+                                                                 withTemplate:numberFormat.format];
+            return [self appendNationalNumber_:formattedNumber];
+        }
+    }
+    return @"";
+};
+
+
+/**
+ * Combines the national number with any prefix (IDD/+ and country code or
+ * national prefix) that was collected. A space will be inserted between them if
+ * the current formatting template indicates this to be suitable.
+ * @param {string} nationalNumber The number to be appended.
+ * @return {string} The combined number.
+ * @private
+ */
+- (NSString*)appendNationalNumber_:(NSString*)nationalNumber
+{
+    /** @type {number} */
+    NSUInteger prefixBeforeNationalNumberLength = self.prefixBeforeNationalNumber_.length;
+    unichar blank_char = [self.SEPARATOR_BEFORE_NATIONAL_NUMBER_ characterAtIndex:0];
+    if (self.shouldAddSpaceAfterNationalPrefix_ && prefixBeforeNationalNumberLength > 0 &&
+        [self.prefixBeforeNationalNumber_ characterAtIndex:prefixBeforeNationalNumberLength - 1] != blank_char)
+    {
+        // We want to add a space after the national prefix if the national prefix
+        // formatting rule indicates that this would normally be done, with the
+        // exception of the case where we already appended a space because the NDD
+        // was surprisingly long.
+        
+        return [NSString stringWithFormat:@"%@%@%@", self.prefixBeforeNationalNumber_, self.SEPARATOR_BEFORE_NATIONAL_NUMBER_, nationalNumber];
+    } else {
+        return [NSString stringWithFormat:@"%@%@", self.prefixBeforeNationalNumber_, nationalNumber];
+    }
+};
+
+
+/**
+ * Returns the current position in the partially formatted phone number of the
+ * character which was previously passed in as the parameter of
+ * {@link #inputDigitAndRememberPosition}.
+ *
+ * @return {number}
+ */
+- (NSInteger)getRememberedPosition
+{
+    if (!self.ableToFormat_) {
+        return self.originalPosition_;
+    }
+    /** @type {number} */
+    NSUInteger accruedInputIndex = 0;
+    /** @type {number} */
+    NSUInteger currentOutputIndex = 0;
+    /** @type {string} */
+    NSString *accruedInputWithoutFormatting = self.accruedInputWithoutFormatting_;
+    /** @type {string} */
+    NSString *currentOutput = self.currentOutput_;
+    
+    while (accruedInputIndex < self.positionToRemember_ && currentOutputIndex < currentOutput.length)
+    {
+        if ([accruedInputWithoutFormatting characterAtIndex:accruedInputIndex] == [currentOutput characterAtIndex:currentOutputIndex])
+        {
+            accruedInputIndex++;
+        }
+        currentOutputIndex++;
+    }
+    return currentOutputIndex;
+};
+
+
+/**
+ * Attempts to set the formatting template and returns a string which contains
+ * the formatted version of the digits entered so far.
+ *
+ * @return {string}
+ * @private
+ */
+- (NSString*)attemptToChooseFormattingPattern_
+{
+    /** @type {string} */
+    NSString *nationalNumber = [self.nationalNumber_ copy];
+    // We start to attempt to format only when as least MIN_LEADING_DIGITS_LENGTH
+    // digits of national number (excluding national prefix) have been entered.
+    if (nationalNumber.length >= self.MIN_LEADING_DIGITS_LENGTH_) {
+        [self getAvailableFormats_:[nationalNumber substringWithRange:NSMakeRange(0, self.MIN_LEADING_DIGITS_LENGTH_)]];
+        return [self maybeCreateNewTemplate_] ? [self inputAccruedNationalNumber_] : self.accruedInput_;
+    } else {
+        return [self appendNationalNumber_:nationalNumber];
+    }
+}
+
+
+/**
+ * Invokes inputDigitHelper on each digit of the national number accrued, and
+ * returns a formatted string in the end.
+ *
+ * @return {string}
+ * @private
+ */
+- (NSString*)inputAccruedNationalNumber_
+{
+    /** @type {string} */
+    NSString *nationalNumber = [self.nationalNumber_ copy];
+    /** @type {number} */
+    NSUInteger lengthOfNationalNumber = nationalNumber.length;
+    if (lengthOfNationalNumber > 0) {
+        /** @type {string} */
+        NSString *tempNationalNumber = @"";
+        for (NSUInteger i = 0; i < lengthOfNationalNumber; i++)
+        {
+            tempNationalNumber = [self inputDigitHelper_:[NSString stringWithFormat: @"%C", [nationalNumber characterAtIndex:i]]];
+        }
+        return self.ableToFormat_ ? [self appendNationalNumber_:tempNationalNumber] : self.accruedInput_;
+    } else {
+        return self.prefixBeforeNationalNumber_;
+    }
+};
+
+
+/**
+ * @return {BOOL} YES if the current country is a NANPA country and the
+ *     national number begins with the national prefix.
+ * @private
+ */
+- (BOOL)isNanpaNumberWithNationalPrefix_
+{
+    // For NANPA numbers beginning with 1[2-9], treat the 1 as the national
+    // prefix. The reason is that national significant numbers in NANPA always
+    // start with [2-9] after the national prefix. Numbers beginning with 1[01]
+    // can only be short/emergency numbers, which don't need the national prefix.
+    if (![self.currentMetaData_.countryCode isEqualToNumber:@1]) {
+        return NO;
+    }
+    
+    /** @type {string} */
+    NSString *nationalNumber = [self.nationalNumber_ copy];
+    return ([nationalNumber characterAtIndex:0] == '1') && ([nationalNumber characterAtIndex:1] != '0') &&
+        ([nationalNumber characterAtIndex:1] != '1');
+};
+
+
+/**
+ * Returns the national prefix extracted, or an empty string if it is not
+ * present.
+ * @return {string}
+ * @private
+ */
+- (NSString*)removeNationalPrefixFromNationalNumber_
+{
+    /** @type {string} */
+    NSString *nationalNumber = [self.nationalNumber_ copy];
+    /** @type {number} */
+    NSUInteger startOfNationalNumber = 0;
+    
+    if ([self isNanpaNumberWithNationalPrefix_]) {
+        startOfNationalNumber = 1;
+        [self.prefixBeforeNationalNumber_ appendString:@"1"];
+        [self.prefixBeforeNationalNumber_ appendFormat:@"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_];
+        self.isCompleteNumber_ = YES;
+    }
+    else if (self.currentMetaData_.nationalPrefixForParsing != nil && self.currentMetaData_.nationalPrefixForParsing.length > 0)
+    {
+        /** @type {RegExp} */
+        NSString *nationalPrefixForParsing = [NSString stringWithFormat:@"^(?:%@)", self.currentMetaData_.nationalPrefixForParsing];
+        /** @type {Array.<string>} */
+        NSArray *m = [self.phoneUtil_ matchedStringByRegex:nationalNumber regex:nationalPrefixForParsing];
+        NSString *firstString = [m safeObjectAtIndex:0];
+        if (m != nil && firstString != nil && firstString.length > 0) {
+            // When the national prefix is detected, we use international formatting
+            // rules instead of national ones, because national formatting rules could
+            // contain local formatting rules for numbers entered without area code.
+            self.isCompleteNumber_ = YES;
+            startOfNationalNumber = firstString.length;
+            [self.prefixBeforeNationalNumber_ appendString:[nationalNumber substringWithRange:NSMakeRange(0, startOfNationalNumber)]];
+        }
+    }
+    
+    self.nationalNumber_ = [NSMutableString stringWithString:@""];
+    [self.nationalNumber_ appendString:[nationalNumber substringFromIndex:startOfNationalNumber]];
+    return [nationalNumber substringWithRange:NSMakeRange(0, startOfNationalNumber)];
+};
+
+
+/**
+ * Extracts IDD and plus sign to prefixBeforeNationalNumber when they are
+ * available, and places the remaining input into nationalNumber.
+ *
+ * @return {BOOL} YES when accruedInputWithoutFormatting begins with the
+ *     plus sign or valid IDD for defaultCountry.
+ * @private
+ */
+- (BOOL)attemptToExtractIdd_
+{
+    /** @type {string} */
+    NSString *accruedInputWithoutFormatting = [self.accruedInputWithoutFormatting_ copy];
+    /** @type {RegExp} */
+    NSString *internationalPrefix = [NSString stringWithFormat:@"^(?:\\+|%@)", self.currentMetaData_.internationalPrefix];
+    /** @type {Array.<string>} */
+    NSArray *m = [self.phoneUtil_ matchedStringByRegex:accruedInputWithoutFormatting regex:internationalPrefix];
+    
+    NSString *firstString = [m safeObjectAtIndex:0];
+    
+    if (m != nil && firstString != nil && firstString.length > 0) {
+        self.isCompleteNumber_ = YES;
+        /** @type {number} */
+        NSUInteger startOfCountryCallingCode = firstString.length;
+        self.nationalNumber_ = [NSMutableString stringWithString:@""];
+        [self.nationalNumber_ appendString:[accruedInputWithoutFormatting substringFromIndex:startOfCountryCallingCode]];
+        self.prefixBeforeNationalNumber_ = [NSMutableString stringWithString:@""];
+        [self.prefixBeforeNationalNumber_ appendString:[accruedInputWithoutFormatting substringWithRange:NSMakeRange(0, startOfCountryCallingCode)]];
+        
+        if ([accruedInputWithoutFormatting characterAtIndex:0] != '+')
+        {
+            [self.prefixBeforeNationalNumber_ appendString:[NSString stringWithFormat: @"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_]];
+        }
+        return YES;
+    }
+    return NO;
+};
+
+
+/**
+ * Extracts the country calling code from the beginning of nationalNumber to
+ * prefixBeforeNationalNumber when they are available, and places the remaining
+ * input into nationalNumber.
+ *
+ * @return {BOOL} YES when a valid country calling code can be found.
+ * @private
+ */
+- (BOOL)attemptToExtractCountryCallingCode_
+{
+    if (self.nationalNumber_.length == 0) {
+        return NO;
+    }
+    
+    /** @type {!goog.string.StringBuffer} */
+    NSString *numberWithoutCountryCallingCode = @"";
+    
+    /** @type {number} */
+    NSNumber *countryCode = [self.phoneUtil_ extractCountryCode:self.nationalNumber_ nationalNumber:&numberWithoutCountryCallingCode];
+    
+    if ([countryCode isEqualToNumber:@0]) {
+        return NO;
+    }
+    
+    self.nationalNumber_ = [NSMutableString stringWithString:@""];
+    [self.nationalNumber_ appendString:numberWithoutCountryCallingCode];
+    
+    /** @type {string} */
+    NSString *newRegionCode = [self.phoneUtil_ getRegionCodeForCountryCode:countryCode];
+    
+    if ([[self.phoneUtil_ REGION_CODE_FOR_NON_GEO_ENTITY] isEqualToString:newRegionCode]) {
+        self.currentMetaData_ = [self.phoneUtil_ getMetadataForNonGeographicalRegion:countryCode];
+    } else if (newRegionCode != self.defaultCountry_)
+    {
+        self.currentMetaData_ = [self getMetadataForRegion_:newRegionCode];
+    }
+    
+    /** @type {string} */
+    NSString *countryCodeString = [NSString stringWithFormat:@"%@", countryCode];
+    [self.prefixBeforeNationalNumber_ appendString:countryCodeString];
+    [self.prefixBeforeNationalNumber_ appendString:[NSString stringWithFormat: @"%@", self.SEPARATOR_BEFORE_NATIONAL_NUMBER_]];
+    return YES;
+};
+
+
+/**
+ * Accrues digits and the plus sign to accruedInputWithoutFormatting for later
+ * use. If nextChar contains a digit in non-ASCII format (e.g. the full-width
+ * version of digits), it is first normalized to the ASCII version. The return
+ * value is nextChar itself, or its normalized version, if nextChar is a digit
+ * in non-ASCII format. This method assumes its input is either a digit or the
+ * plus sign.
+ *
+ * @param {string} nextChar
+ * @param {BOOL} rememberPosition
+ * @return {string}
+ * @private
+ */
+- (NSString*)normalizeAndAccrueDigitsAndPlusSign_:(NSString *)nextChar rememberPosition:(BOOL)rememberPosition
+{
+    /** @type {string} */
+    NSString *normalizedChar;
+    
+    if ([nextChar isEqualToString:@"+"]) {
+        normalizedChar = nextChar;
+        [self.accruedInputWithoutFormatting_ appendString:nextChar];
+    } else {
+        normalizedChar = [[self.phoneUtil_ DIGIT_MAPPINGS] objectForKey:nextChar];
+        [self.accruedInputWithoutFormatting_ appendString:normalizedChar];
+        [self.nationalNumber_ appendString:normalizedChar];
+    }
+    
+    if (rememberPosition) {
+        self.positionToRemember_ = self.accruedInputWithoutFormatting_.length;
+    }
+    
+    return normalizedChar;
+};
+
+
+/**
+ * @param {string} nextChar
+ * @return {string}
+ * @private
+ */
+- (NSString*)inputDigitHelper_:(NSString *)nextChar
+{
+    /** @type {string} */
+    NSString *formattingTemplate = [self.formattingTemplate_ copy];
+    NSString *subedString = @"";
+    
+    if (formattingTemplate.length > self.lastMatchPosition_) {
+        subedString = [formattingTemplate substringFromIndex:self.lastMatchPosition_];
+    }
+    
+    if ([self.phoneUtil_ stringPositionByRegex:subedString regex:self.DIGIT_PLACEHOLDER_] >= 0) {
+        /** @type {number} */
+        NSUInteger digitPatternStart = [self.phoneUtil_ stringPositionByRegex:formattingTemplate regex:self.DIGIT_PLACEHOLDER_];
+        
+        /** @type {string} */
+        NSRange tempRange = [formattingTemplate rangeOfString:self.DIGIT_PLACEHOLDER_];
+        NSString *tempTemplate = [formattingTemplate stringByReplacingOccurrencesOfString:self.DIGIT_PLACEHOLDER_
+                                                                               withString:nextChar
+                                                                                  options:NSLiteralSearch
+                                                                                    range:tempRange];
+        self.formattingTemplate_ = [NSMutableString stringWithString:@""];
+        [self.formattingTemplate_ appendString:tempTemplate];
+        self.lastMatchPosition_ = digitPatternStart;
+        return [tempTemplate substringWithRange:NSMakeRange(0, self.lastMatchPosition_ + 1)];
+    } else {
+        if (self.possibleFormats_.count == 1)
+        {
+            // More digits are entered than we could handle, and there are no other
+            // valid patterns to try.
+            self.ableToFormat_ = NO;
+        }  // else, we just reset the formatting pattern.
+        self.currentFormattingPattern_ = @"";
+        return self.accruedInput_;
+    }
+};
+
+@end
diff --git a/libPhoneNumber/NBNumberFormat.h b/libPhoneNumber/NBNumberFormat.h
new file mode 100644
index 0000000..d2e8749
--- /dev/null
+++ b/libPhoneNumber/NBNumberFormat.h
@@ -0,0 +1,22 @@
+//
+//  NBPhoneNumberFormat.h
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NBNumberFormat : NSObject
+
+// from phonemetadata.pb.js
+/* 1 */ @property (nonatomic, strong, readwrite) NSString *pattern;
+/* 2 */ @property (nonatomic, strong, readwrite) NSString *format;
+/* 3 */ @property (nonatomic, strong, readwrite) NSMutableArray *leadingDigitsPatterns;
+/* 4 */ @property (nonatomic, strong, readwrite) NSString *nationalPrefixFormattingRule;
+/* 6 */ @property (nonatomic, assign, readwrite) BOOL nationalPrefixOptionalWhenFormatting;
+/* 5 */ @property (nonatomic, strong, readwrite) NSString *domesticCarrierCodeFormattingRule;
+
+- (id)initWithData:(id)data;
+
+@end
diff --git a/libPhoneNumber/NBNumberFormat.m b/libPhoneNumber/NBNumberFormat.m
new file mode 100644
index 0000000..5f261a7
--- /dev/null
+++ b/libPhoneNumber/NBNumberFormat.m
@@ -0,0 +1,139 @@
+//
+//  NBPhoneNumberFormat.m
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import "NBNumberFormat.h"
+#import "NBPhoneNumberDefines.h"
+
+@implementation NBNumberFormat
+
+@synthesize pattern, format, leadingDigitsPatterns, nationalPrefixFormattingRule, nationalPrefixOptionalWhenFormatting, domesticCarrierCodeFormattingRule;
+
+
+- (id)initWithData:(id)data
+{
+    self = [self init];
+    
+    if (self && data != nil && [data isKindOfClass:[NSArray class]])
+    {
+        /* 1 */ self.pattern = [data safeObjectAtIndex:1];
+        /* 2 */ self.format = [data safeObjectAtIndex:2];
+        /* 3 */ self.leadingDigitsPatterns = [self stringArrayFromData:[data safeObjectAtIndex:3]]; // NSString array
+        /* 4 */ self.nationalPrefixFormattingRule = [data safeObjectAtIndex:4];
+        /* 6 */ self.nationalPrefixOptionalWhenFormatting = [[data safeObjectAtIndex:6] boolValue];
+        /* 5 */ self.domesticCarrierCodeFormattingRule = [data safeObjectAtIndex:5];
+    }
+    
+    return self;
+}
+
+
+- (id)init
+{
+    self = [super init];
+    
+    if (self)
+    {
+        self.nationalPrefixOptionalWhenFormatting = NO;
+        self.leadingDigitsPatterns = [[NSMutableArray alloc] init];
+    }
+    
+    return self;
+}
+
+
+- (NSMutableArray*)stringArrayFromData:(id)data
+{
+    NSMutableArray *resArray = [[NSMutableArray alloc] init];
+    if (data != nil && [data isKindOfClass:[NSArray class]])
+    {
+        for (id numFormat in data)
+        {
+            if ([numFormat isKindOfClass:[NSString class]])
+            {
+                [resArray addObject:numFormat];
+            }
+            else
+            {
+                [resArray addObject:[numFormat stringValue]];
+            }
+        }
+    }
+    
+    return resArray;
+}
+
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"[pattern:%@, format:%@, leadingDigitsPattern:%@, nationalPrefixFormattingRule:%@, nationalPrefixOptionalWhenFormatting:%@, domesticCarrierCodeFormattingRule:%@]",
+            self.pattern, self.format, self.leadingDigitsPatterns, self.nationalPrefixFormattingRule, self.nationalPrefixOptionalWhenFormatting?@"Y":@"N", self.domesticCarrierCodeFormattingRule];
+}
+
+
+- (id)copyWithZone:(NSZone *)zone
+{
+	NBNumberFormat *phoneFormatCopy = [[NBNumberFormat allocWithZone:zone] init];
+    
+    /*
+     1 @property (nonatomic, strong, readwrite) NSString *pattern;
+     2 @property (nonatomic, strong, readwrite) NSString *format;
+     3 @property (nonatomic, strong, readwrite) NSString *leadingDigitsPattern;
+     4 @property (nonatomic, strong, readwrite) NSString *nationalPrefixFormattingRule;
+     6 @property (nonatomic, assign, readwrite) BOOL nationalPrefixOptionalWhenFormatting;
+     5 @property (nonatomic, strong, readwrite) NSString *domesticCarrierCodeFormattingRule;
+    */
+    
+    phoneFormatCopy.pattern = [self.pattern copy];
+    phoneFormatCopy.format = [self.format copy];
+    phoneFormatCopy.leadingDigitsPatterns = [self.leadingDigitsPatterns copy];
+    phoneFormatCopy.nationalPrefixFormattingRule = [self.nationalPrefixFormattingRule copy];
+    phoneFormatCopy.nationalPrefixOptionalWhenFormatting = self.nationalPrefixOptionalWhenFormatting;
+    phoneFormatCopy.domesticCarrierCodeFormattingRule = [self.domesticCarrierCodeFormattingRule copy];
+    
+	return phoneFormatCopy;
+}
+
+
+- (id)initWithCoder:(NSCoder*)coder
+{
+    if (self = [super init])
+    {
+        self.pattern = [coder decodeObjectForKey:@"pattern"];
+        self.format = [coder decodeObjectForKey:@"format"];
+        self.leadingDigitsPatterns = [coder decodeObjectForKey:@"leadingDigitsPatterns"];
+        self.nationalPrefixFormattingRule = [coder decodeObjectForKey:@"nationalPrefixFormattingRule"];
+        self.nationalPrefixOptionalWhenFormatting = [[coder decodeObjectForKey:@"nationalPrefixOptionalWhenFormatting"] boolValue];
+        self.domesticCarrierCodeFormattingRule = [coder decodeObjectForKey:@"domesticCarrierCodeFormattingRule"];
+    }
+    return self;
+}
+
+
+- (void)encodeWithCoder:(NSCoder*)coder
+{
+    [coder encodeObject:self.pattern forKey:@"pattern"];
+    [coder encodeObject:self.format forKey:@"format"];
+    [coder encodeObject:self.leadingDigitsPatterns forKey:@"leadingDigitsPatterns"];
+    [coder encodeObject:self.nationalPrefixFormattingRule forKey:@"nationalPrefixFormattingRule"];
+    [coder encodeObject:[NSNumber numberWithBool:self.nationalPrefixOptionalWhenFormatting] forKey:@"nationalPrefixOptionalWhenFormatting"];
+    [coder encodeObject:self.domesticCarrierCodeFormattingRule forKey:@"domesticCarrierCodeFormattingRule"];
+}
+
+
+- (void)setData:(id)data
+{
+    if ([data isKindOfClass:[NSArray class]] || [data isKindOfClass:[NSMutableArray class]])
+    {
+        
+    }
+    else if ([data isKindOfClass:[NSDictionary class]] || [data isKindOfClass:[NSMutableDictionary class]])
+    {
+        
+    }
+}
+
+@end
diff --git a/libPhoneNumber/NBPhoneMetaData.h b/libPhoneNumber/NBPhoneMetaData.h
new file mode 100644
index 0000000..6767492
--- /dev/null
+++ b/libPhoneNumber/NBPhoneMetaData.h
@@ -0,0 +1,45 @@
+//
+//  M2PhoneMetaData.h
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import <Foundation/Foundation.h>
+
+@class NBPhoneNumberDesc, NBNumberFormat;
+
+@interface NBPhoneMetaData : NSObject
+
+// from phonemetadata.pb.js
+/*  1 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *generalDesc;
+/*  2 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *fixedLine;
+/*  3 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *mobile;
+/*  4 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *tollFree;
+/*  5 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *premiumRate;
+/*  6 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *sharedCost;
+/*  7 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *personalNumber;
+/*  8 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *voip;
+/* 21 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *pager;
+/* 25 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *uan;
+/* 27 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *emergency;
+/* 28 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *voicemail;
+/* 24 */ @property (nonatomic, strong, readwrite) NBPhoneNumberDesc *noInternationalDialling;
+/*  9 */ @property (nonatomic, strong, readwrite) NSString *codeID;
+/* 10 */ @property (nonatomic, strong, readwrite) NSNumber *countryCode;
+/* 11 */ @property (nonatomic, strong, readwrite) NSString *internationalPrefix;
+/* 17 */ @property (nonatomic, strong, readwrite) NSString *preferredInternationalPrefix;
+/* 12 */ @property (nonatomic, strong, readwrite) NSString *nationalPrefix;
+/* 13 */ @property (nonatomic, strong, readwrite) NSString *preferredExtnPrefix;
+/* 15 */ @property (nonatomic, strong, readwrite) NSString *nationalPrefixForParsing;
+/* 16 */ @property (nonatomic, strong, readwrite) NSString *nationalPrefixTransformRule;
+/* 18 */ @property (nonatomic, assign, readwrite) BOOL sameMobileAndFixedLinePattern;
+/* 19 */ @property (nonatomic, strong, readwrite) NSMutableArray *numberFormats;
+/* 20 */ @property (nonatomic, strong, readwrite) NSMutableArray *intlNumberFormats;
+/* 22 */ @property (nonatomic, assign, readwrite) BOOL mainCountryForCode;
+/* 23 */ @property (nonatomic, strong, readwrite) NSString *leadingDigits;
+/* 26 */ @property (nonatomic, assign, readwrite) BOOL leadingZeroPossible;
+
+- (void)buildData:(id)data;
+
+@end
diff --git a/libPhoneNumber/NBPhoneMetaData.m b/libPhoneNumber/NBPhoneMetaData.m
new file mode 100644
index 0000000..8aa30d8
--- /dev/null
+++ b/libPhoneNumber/NBPhoneMetaData.m
@@ -0,0 +1,458 @@
+//
+//  NBPhoneMetaData.m
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import "NBPhoneMetaData.h"
+#import "NBPhoneNumberDesc.h"
+#import "NBNumberFormat.h"
+#import "NBPhoneNumberDefines.h"
+
+@implementation NBPhoneMetaData
+
+@synthesize generalDesc, fixedLine, mobile, tollFree, premiumRate, sharedCost, personalNumber, voip, pager, uan, emergency, voicemail, noInternationalDialling;
+@synthesize codeID, countryCode;
+@synthesize internationalPrefix, preferredInternationalPrefix, nationalPrefix, preferredExtnPrefix, nationalPrefixForParsing, nationalPrefixTransformRule, sameMobileAndFixedLinePattern, numberFormats, intlNumberFormats, mainCountryForCode, leadingDigits, leadingZeroPossible;
+
+- (id)init
+{
+    self = [super init];
+    
+    if (self)
+    {
+        [self setNumberFormats:[[NSMutableArray alloc] init]];
+        [self setIntlNumberFormats:[[NSMutableArray alloc] init]];
+
+        self.leadingZeroPossible = NO;
+        self.mainCountryForCode = NO;
+    }
+    
+    return self;
+}
+
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"* codeID[%@] countryCode[%@] generalDesc[%@] fixedLine[%@] mobile[%@] tollFree[%@] premiumRate[%@] sharedCost[%@] personalNumber[%@] voip[%@] pager[%@] uan[%@] emergency[%@] voicemail[%@] noInternationalDialling[%@] internationalPrefix[%@] preferredInternationalPrefix[%@] nationalPrefix[%@] preferredExtnPrefix[%@] nationalPrefixForParsing[%@] nationalPrefixTransformRule[%@] sameMobileAndFixedLinePattern[%@] numberFormats[%@] intlNumberFormats[%@] mainCountryForCode[%@] leadingDigits[%@] leadingZeroPossible[%@]",
+             self.codeID, self.countryCode, self.generalDesc, self.fixedLine, self.mobile, self.tollFree, self.premiumRate, self.sharedCost, self.personalNumber, self.voip, self.pager, self.uan, self.emergency, self.voicemail, self.noInternationalDialling, self.internationalPrefix, self.preferredInternationalPrefix, self.nationalPrefix, self.preferredExtnPrefix, self.nationalPrefixForParsing, self.nationalPrefixTransformRule, self.sameMobileAndFixedLinePattern?@"Y":@"N", self.numberFormats, self.intlNumberFormats, self.mainCountryForCode?@"Y":@"N", self.leadingDigits, self.leadingZeroPossible?@"Y":@"N"];
+}
+
+
+- (void)buildData:(id)data
+{
+    if (data != nil && [data isKindOfClass:[NSArray class]] )
+    {
+        /*  1 */ self.generalDesc = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:1]];
+        /*  2 */ self.fixedLine = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:2]];
+        /*  3 */ self.mobile = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:3]];
+        /*  4 */ self.tollFree = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:4]];
+        /*  5 */ self.premiumRate = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:5]];
+        /*  6 */ self.sharedCost = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:6]];
+        /*  7 */ self.personalNumber = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:7]];
+        /*  8 */ self.voip = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:8]];
+        /* 21 */ self.pager = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:21]];
+        /* 25 */ self.uan = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:25]];
+        /* 27 */ self.emergency = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:27]];
+        /* 28 */ self.voicemail = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:28]];
+        /* 24 */ self.noInternationalDialling = [[NBPhoneNumberDesc alloc] initWithData:[data safeObjectAtIndex:24]];
+        /*  9 */ self.codeID = [data safeObjectAtIndex:9];
+        /* 10 */ self.countryCode = [data safeObjectAtIndex:10];
+        /* 11 */ self.internationalPrefix = [data safeObjectAtIndex:11];
+        /* 17 */ self.preferredInternationalPrefix = [data safeObjectAtIndex:17];
+        /* 12 */ self.nationalPrefix = [data safeObjectAtIndex:12];
+        /* 13 */ self.preferredExtnPrefix = [data safeObjectAtIndex:13];
+        /* 15 */ self.nationalPrefixForParsing = [data safeObjectAtIndex:15];
+        /* 16 */ self.nationalPrefixTransformRule = [data safeObjectAtIndex:16];
+        /* 18 */ self.sameMobileAndFixedLinePattern = [[data safeObjectAtIndex:18] boolValue];
+        /* 19 */ self.numberFormats = [self numberFormatArrayFromData:[data safeObjectAtIndex:19]];     // NBNumberFormat array
+        /* 20 */ self.intlNumberFormats = [self numberFormatArrayFromData:[data safeObjectAtIndex:20]]; // NBNumberFormat array
+        /* 22 */ self.mainCountryForCode = [[data safeObjectAtIndex:22] boolValue];
+        /* 23 */ self.leadingDigits = [data safeObjectAtIndex:23];
+        /* 26 */ self.leadingZeroPossible = [[data safeObjectAtIndex:26] boolValue];
+    }
+    else
+    {
+        NSLog(@"nil data or wrong data type");
+    }
+}
+
+
+- (id)initWithCoder:(NSCoder*)coder
+{
+    if (self = [super init])
+    {
+        self.generalDesc = [coder decodeObjectForKey:@"generalDesc"];
+        self.fixedLine = [coder decodeObjectForKey:@"fixedLine"];
+        self.mobile = [coder decodeObjectForKey:@"mobile"];
+        self.tollFree = [coder decodeObjectForKey:@"tollFree"];
+        self.premiumRate = [coder decodeObjectForKey:@"premiumRate"];
+        self.sharedCost = [coder decodeObjectForKey:@"sharedCost"];
+        self.personalNumber = [coder decodeObjectForKey:@"personalNumber"];
+        self.voip = [coder decodeObjectForKey:@"voip"];
+        self.pager = [coder decodeObjectForKey:@"pager"];
+        self.uan = [coder decodeObjectForKey:@"uan"];
+        self.emergency = [coder decodeObjectForKey:@"emergency"];
+        self.voicemail = [coder decodeObjectForKey:@"voicemail"];
+        self.noInternationalDialling = [coder decodeObjectForKey:@"noInternationalDialling"];
+        self.codeID = [coder decodeObjectForKey:@"codeID"];
+        self.countryCode = [coder decodeObjectForKey:@"countryCode"];
+        self.internationalPrefix = [coder decodeObjectForKey:@"internationalPrefix"];
+        self.preferredInternationalPrefix = [coder decodeObjectForKey:@"preferredInternationalPrefix"];
+        self.nationalPrefix = [coder decodeObjectForKey:@"nationalPrefix"];
+        self.preferredExtnPrefix = [coder decodeObjectForKey:@"preferredExtnPrefix"];
+        self.nationalPrefixForParsing = [coder decodeObjectForKey:@"nationalPrefixForParsing"];
+        self.nationalPrefixTransformRule = [coder decodeObjectForKey:@"nationalPrefixTransformRule"];
+        self.sameMobileAndFixedLinePattern = [[coder decodeObjectForKey:@"sameMobileAndFixedLinePattern"] boolValue];
+        self.numberFormats = [coder decodeObjectForKey:@"numberFormats"];
+        self.intlNumberFormats = [coder decodeObjectForKey:@"intlNumberFormats"];
+        self.mainCountryForCode = [[coder decodeObjectForKey:@"mainCountryForCode"] boolValue];
+        self.leadingDigits = [coder decodeObjectForKey:@"leadingDigits"];
+        self.leadingZeroPossible = [[coder decodeObjectForKey:@"leadingZeroPossible"] boolValue];
+    }
+    return self;
+}
+
+
+- (void)encodeWithCoder:(NSCoder*)coder
+{
+    [coder encodeObject:self.generalDesc forKey:@"generalDesc"];
+    [coder encodeObject:self.fixedLine forKey:@"fixedLine"];
+    [coder encodeObject:self.mobile forKey:@"mobile"];
+    [coder encodeObject:self.tollFree forKey:@"tollFree"];
+    [coder encodeObject:self.premiumRate forKey:@"premiumRate"];
+    [coder encodeObject:self.sharedCost forKey:@"sharedCost"];
+    [coder encodeObject:self.personalNumber forKey:@"personalNumber"];
+    [coder encodeObject:self.voip forKey:@"voip"];
+    [coder encodeObject:self.pager forKey:@"pager"];
+    [coder encodeObject:self.uan forKey:@"uan"];
+    [coder encodeObject:self.emergency forKey:@"emergency"];
+    [coder encodeObject:self.voicemail forKey:@"voicemail"];
+    [coder encodeObject:self.noInternationalDialling forKey:@"noInternationalDialling"];
+    [coder encodeObject:self.codeID forKey:@"codeID"];
+    [coder encodeObject:self.countryCode forKey:@"countryCode"];
+    [coder encodeObject:self.internationalPrefix forKey:@"internationalPrefix"];
+    [coder encodeObject:self.preferredInternationalPrefix forKey:@"preferredInternationalPrefix"];
+    [coder encodeObject:self.nationalPrefix forKey:@"nationalPrefix"];
+    [coder encodeObject:self.preferredExtnPrefix forKey:@"preferredExtnPrefix"];
+    [coder encodeObject:self.nationalPrefixForParsing forKey:@"nationalPrefixForParsing"];
+    [coder encodeObject:self.nationalPrefixTransformRule forKey:@"nationalPrefixTransformRule"];
+    [coder encodeObject:[NSNumber numberWithBool:self.sameMobileAndFixedLinePattern] forKey:@"sameMobileAndFixedLinePattern"];
+    [coder encodeObject:self.numberFormats forKey:@"numberFormats"];
+    [coder encodeObject:self.intlNumberFormats forKey:@"intlNumberFormats"];
+    [coder encodeObject:[NSNumber numberWithBool:self.mainCountryForCode] forKey:@"mainCountryForCode"];
+    [coder encodeObject:self.leadingDigits forKey:@"leadingDigits"];
+    [coder encodeObject:[NSNumber numberWithBool:self.leadingZeroPossible] forKey:@"leadingZeroPossible"];
+}
+
+
+- (NSMutableArray*)numberFormatArrayFromData:(id)data
+{
+    NSMutableArray *resArray = [[NSMutableArray alloc] init];
+    if (data != nil && [data isKindOfClass:[NSArray class]])
+    {
+        for (id numFormat in data)
+        {
+            NBNumberFormat *newNumberFormat = [[NBNumberFormat alloc] initWithData:numFormat];
+            [resArray addObject:newNumberFormat];
+        }
+    }
+    
+    return resArray;
+}
+
+/*
+- (NSString*)getNormalizedNationalPrefixFormattingRule
+{
+    NSString *replacedFormattingRule = [self.nationalPrefixFormattingRule stringByReplacingOccurrencesOfString:@"$NP" withString:self.nationalPrefix];
+    return replacedFormattingRule;
+}
+
+
+- (BOOL)sameMobileAndFixedLinePattern
+{
+    if ([self.mobile isEqual:self.fixedLine]) return YES;
+    return NO;
+}
+
+
+- (NBPhoneNumberDesc*)inheriteValues:(NBPhoneNumberDesc*)targetDesc
+{
+    if (targetDesc == nil)
+    {
+        targetDesc = [[NBPhoneNumberDesc alloc] init];
+    }
+    
+    if (self.generalDesc != nil)
+    {
+        if (targetDesc.nationalNumberPattern == nil)
+        {
+            if (self.generalDesc.nationalNumberPattern != nil)
+                targetDesc.nationalNumberPattern = [self.generalDesc.nationalNumberPattern copy];
+        }
+        
+        if (targetDesc.possibleNumberPattern == nil)
+        {
+            if (self.generalDesc.possibleNumberPattern != nil)
+                targetDesc.possibleNumberPattern = [self.generalDesc.possibleNumberPattern copy];
+        }
+        
+        if (targetDesc.exampleNumber == nil)
+        {
+            if (self.generalDesc.exampleNumber != nil)
+                targetDesc.exampleNumber = [self.generalDesc.exampleNumber copy];
+        }
+    }
+    
+    return targetDesc;
+}
+
+
+- (void)updateDescriptions
+{
+    self.fixedLine = [[self inheriteValues:self.fixedLine] copy];
+    self.mobile = [[self inheriteValues:self.mobile] copy];
+    self.tollFree = [[self inheriteValues:self.tollFree] copy];
+    self.premiumRate = [[self inheriteValues:self.premiumRate] copy];
+    self.sharedCost = [[self inheriteValues:self.sharedCost] copy];
+    self.personalNumber = [[self inheriteValues:self.personalNumber] copy];
+    self.voip = [[self inheriteValues:self.voip] copy];
+    self.pager = [[self inheriteValues:self.pager] copy];
+    self.uan = [[self inheriteValues:self.uan] copy];
+    self.emergency = [[self inheriteValues:self.emergency] copy];
+    self.voicemail = [[self inheriteValues:self.voicemail] copy];
+    self.noInternationalDialling = [[self inheriteValues:self.noInternationalDialling] copy];
+}
+
+
+- (void)setAttributes:(NSDictionary*)data
+{
+    NSString *attributeName = [data valueForKey:@"attributeName"];
+    id attributeContent = [data valueForKey:@"nodeContent"];
+    
+    if ([attributeContent isKindOfClass:[NSString class]] && [attributeContent length] > 0)
+        attributeContent = [NBPhoneNumberManager stringByTrimming:attributeContent];
+    
+    if (attributeName && [attributeName isKindOfClass:[NSString class]] && [attributeName length]  > 0 && [attributeName isEqualToString:@"id"] &&
+        attributeContent && [attributeContent isKindOfClass:[NSString class]] && [attributeContent length] > 0)
+    {
+        [self setCodeID:attributeContent];
+    }
+    else if (attributeName && [attributeName isKindOfClass:[NSString class]] && [attributeName length]  > 0 && attributeContent && [attributeContent isKindOfClass:[NSString class]] && [attributeContent length] > 0)
+    {
+        @try {
+            if ([[attributeContent lowercaseString] isEqualToString:@"true"])
+            {
+                [self setValue:[NSNumber numberWithBool:YES] forKey:attributeName];
+            }
+            else if ([[attributeContent lowercaseString] isEqualToString:@"false"])
+            {
+                [self setValue:[NSNumber numberWithBool:NO] forKey:attributeName];
+            }
+            else
+            {
+                [self setValue:attributeContent forKey:attributeName];
+            }
+        }
+        @catch (NSException *ex) {
+            NSLog(@"setAttributes setValue:%@ forKey:%@ error [%@]", attributeContent, attributeName, [attributeContent class]);
+        }
+    }
+}
+
+
+- (BOOL)setChilds:(id)data
+{
+    if (data && [data isKindOfClass:[NSDictionary class]])
+    {
+        NSString *nodeName = [data valueForKey:@"nodeName"];
+        id nodeContent = [data valueForKey:@"nodeContent"];
+        
+        if ([nodeContent isKindOfClass:[NSString class]] && [nodeContent length] > 0)
+            nodeContent = [NBPhoneNumberManager stringByTrimming:nodeContent];
+        
+        // [TYPE] PhoneNumberDesc
+        if ([nodeName isEqualToString:@"generalDesc"] || [nodeName isEqualToString:@"fixedLine"] || [nodeName isEqualToString:@"mobile"] || [nodeName isEqualToString:@"shortCode"] || [nodeName isEqualToString:@"emergency"] || [nodeName isEqualToString:@"voip"] || [nodeName isEqualToString:@"voicemail"] || [nodeName isEqualToString:@"uan"] || [nodeName isEqualToString:@"premiumRate"] || [nodeName isEqualToString:@"nationalNumberPattern"] || [nodeName isEqualToString:@"sharedCost"] || [nodeName isEqualToString:@"tollFree"] || [nodeName isEqualToString:@"noInternationalDialling"] || [nodeName isEqualToString:@"personalNumber"] || [nodeName isEqualToString:@"pager"] || [nodeName isEqualToString:@"areaCodeOptional"])
+        {
+            [self setNumberDescData:data];
+            return YES;
+        }
+        else if ([nodeName isEqualToString:@"availableFormats"])
+        {
+            [self setNumberFormatsData:data];
+            return YES;
+        }
+        else if ([nodeName isEqualToString:@"comment"] == NO && [nodeContent isKindOfClass:[NSString class]])
+        {
+            [self setValue:nodeContent forKey:nodeName];
+            return YES;
+        }
+        else if ([nodeName isEqualToString:@"comment"])
+        {
+            return YES;
+        }
+    }
+    
+    return NO;
+}
+
+
+- (void)setNumberFormatsData:(id)data
+{
+    NSArray *nodeChildArray = [data valueForKey:@"nodeChildArray"];
+    
+    for (id childNumberFormat in nodeChildArray)
+    {
+        NSArray *nodeChildAttributeNumberFormatArray = [childNumberFormat valueForKey:@"nodeAttributeArray"];
+        NSArray *nodeChildNodeNumberFormatArray = [childNumberFormat valueForKey:@"nodeChildArray"];
+        
+        NSString *nodeName = [childNumberFormat valueForKey:@"nodeName"];
+        
+        if ([nodeName isEqualToString:@"numberFormat"])
+        {
+            NBNumberFormat *newNumberFormat = [[NBNumberFormat alloc] init];
+            
+            for (id childAttribute in nodeChildAttributeNumberFormatArray)
+            {
+                NSString *childNodeName = [childAttribute valueForKey:@"attributeName"];
+                NSString *childNodeContent = nil;
+                
+                if ([childNodeName isEqualToString:@"comment"])
+                {
+                    continue;
+                }
+                
+                childNodeContent = [NBPhoneNumberManager stringByTrimming:[childAttribute valueForKey:@"nodeContent"]];
+                
+                @try {
+                    [newNumberFormat setValue:childNodeContent forKey:childNodeName];
+                }
+                @catch (NSException *ex) {
+                    NSLog(@"nodeChildAttributeArray setValue:%@ forKey:%@ error [%@] %@", childNodeContent, childNodeName, [childNodeContent class], childAttribute);
+                }
+            }
+            
+            for (id childNode in nodeChildNodeNumberFormatArray)
+            {
+                NSString *childNodeName = [childNode valueForKey:@"nodeName"];
+                NSString *childNodeContent = nil;
+                
+                if ([childNodeName isEqualToString:@"comment"])
+                {
+                    continue;
+                }
+                
+                childNodeContent = [NBPhoneNumberManager stringByTrimming:[childNode valueForKey:@"nodeContent"]];
+                
+                @try {
+                    if ([childNodeName isEqualToString:@"leadingDigits"])
+                    {
+                        [newNumberFormat.leadingDigitsPattern addObject:childNodeContent];
+                    }
+                    else
+                    {
+                        if ([[childNodeContent lowercaseString] isEqualToString:@"true"])
+                        {
+                            [newNumberFormat setValue:[NSNumber numberWithBool:YES] forKey:childNodeName];
+                        }
+                        else if ([[childNodeContent lowercaseString] isEqualToString:@"false"])
+                        {
+                            [newNumberFormat setValue:[NSNumber numberWithBool:NO] forKey:childNodeName];
+                        }
+                        else
+                        {
+                            [newNumberFormat setValue:childNodeContent forKey:childNodeName];
+                        }
+                    }
+                }
+                @catch (NSException *ex) {
+                    NSLog(@"nodeChildArray setValue:%@ forKey:%@ error [%@] %@", childNodeContent, childNodeName, [childNodeContent class], childNode);
+                }
+            }
+            [self.numberFormats addObject:newNumberFormat];
+        }
+        else if ([nodeName isEqualToString:@"comment"] == NO)
+        {
+            NSLog(@"process ========== %@", childNumberFormat);
+        }
+    }
+}
+
+
+- (void)setNumberDescData:(id)data
+{
+    NSString *nodeName = [data valueForKey:@"nodeName"];
+    NSArray *nodeChildArray = [data valueForKey:@"nodeChildArray"];
+    
+    NBPhoneNumberDesc *newNumberDesc = [[NBPhoneNumberDesc alloc] init];
+    
+    for (id childNode in nodeChildArray)
+    {
+        NSString *childNodeName = [childNode valueForKey:@"nodeName"];
+        NSString *childNodeContent = [NBPhoneNumberManager stringByTrimming:[childNode valueForKey:@"nodeContent"]];
+        
+        if ([childNodeName isEqualToString:@"comment"])
+        {
+            continue;
+        }
+        
+        @try {
+            if (childNodeContent && childNodeContent.length > 0)
+            {
+                [newNumberDesc setValue:childNodeContent forKey:childNodeName];
+            }
+        }
+        @catch (NSException *ex) {
+            NSLog(@"setNumberDesc setValue:%@ forKey:%@ error [%@]", childNodeContent, childNodeName, [childNodeContent class]);
+        }
+    }
+    
+    nodeName = [nodeName lowercaseString];
+    
+    if ([nodeName isEqualToString:[@"generalDesc" lowercaseString]])
+        self.generalDesc = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"fixedLine" lowercaseString]])
+        self.fixedLine = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"mobile" lowercaseString]])
+        self.mobile = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"tollFree" lowercaseString]]) {
+        [self setTollFree:newNumberDesc];
+    }
+    
+    if ([nodeName isEqualToString:[@"premiumRate" lowercaseString]])
+        self.premiumRate = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"sharedCost" lowercaseString]]) {
+        self.sharedCost = newNumberDesc;
+    }
+    
+    if ([nodeName isEqualToString:[@"personalNumber" lowercaseString]])
+        self.personalNumber = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"voip" lowercaseString]])
+        self.voip = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"pager" lowercaseString]])
+        self.pager = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"uan" lowercaseString]])
+        self.uan = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"emergency" lowercaseString]])
+        self.emergency = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"voicemail" lowercaseString]])
+        self.voicemail = newNumberDesc;
+    
+    if ([nodeName isEqualToString:[@"noInternationalDialling" lowercaseString]])
+        self.noInternationalDialling = newNumberDesc;
+    
+    [self updateDescriptions];
+}
+*/
+
+@end
\ No newline at end of file
diff --git a/libPhoneNumber/NBPhoneNumber.h b/libPhoneNumber/NBPhoneNumber.h
new file mode 100644
index 0000000..dfa3b17
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumber.h
@@ -0,0 +1,25 @@
+//
+//  NBPhoneNumber.h
+//  libPhoneNumber
+//  
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import <Foundation/Foundation.h>
+#import "NBPhoneNumberDefines.h"
+
+@interface NBPhoneNumber : NSObject <NSCopying>
+
+// from phonemetadata.pb.js
+/* 1 */ @property (nonatomic, strong, readwrite) NSNumber *countryCode;
+/* 2 */ @property (nonatomic, strong, readwrite) NSNumber *nationalNumber;
+/* 3 */ @property (nonatomic, strong, readwrite) NSString *extension;
+/* 4 */ @property (nonatomic, assign, readwrite) BOOL italianLeadingZero;
+/* 5 */ @property (nonatomic, strong, readwrite) NSString *rawInput;
+/* 6 */ @property (nonatomic, strong, readwrite) NSNumber *countryCodeSource;
+/* 7 */ @property (nonatomic, strong, readwrite) NSString *preferredDomesticCarrierCode;
+
+- (void)clearCountryCodeSource;
+- (NBECountryCodeSource)getCountryCodeSourceOrDefault;
+
+@end
\ No newline at end of file
diff --git a/libPhoneNumber/NBPhoneNumber.m b/libPhoneNumber/NBPhoneNumber.m
new file mode 100644
index 0000000..cd79761
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumber.m
@@ -0,0 +1,121 @@
+//
+//  NBPhoneNumber.m
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import "NBPhoneNumber.h"
+#import "NBPhoneNumberDefines.h"
+
+@implementation NBPhoneNumber
+
+@synthesize countryCode, nationalNumber, extension, italianLeadingZero, rawInput, countryCodeSource, preferredDomesticCarrierCode;
+
+- (id)init
+{
+    self = [super init];
+    
+    if (self)
+    {
+        self.countryCodeSource = nil;
+        self.italianLeadingZero = NO;
+        self.nationalNumber = @-1;
+        self.countryCode = @-1;
+    }
+    
+    return self;
+}
+
+
+- (void)clearCountryCodeSource
+{
+    [self setCountryCodeSource:nil];
+}
+
+
+- (NBECountryCodeSource)getCountryCodeSourceOrDefault
+{
+    if (self.countryCodeSource == nil)
+        return NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN;
+    
+    return [self.countryCodeSource intValue];
+}
+
+
+- (BOOL)isEqualToObject:(NBPhoneNumber*)otherObj
+{
+    return [self isEqual:otherObj];
+}
+
+
+- (NSUInteger)hash
+{
+    NSData *selfObject = [NSKeyedArchiver archivedDataWithRootObject:self];
+    return [selfObject hash];
+}
+
+
+- (BOOL)isEqual:(id)object
+{
+    if ([object isKindOfClass:[NBPhoneNumber class]] == NO)
+        return NO;
+    
+    NBPhoneNumber *other = object;
+    return ([self.countryCode isEqualToNumber: other.countryCode]) && ([self.nationalNumber isEqualToNumber: other.nationalNumber]) &&
+        (self.italianLeadingZero == other.italianLeadingZero) &&
+        ((self.extension == nil && other.extension == nil) || [self.extension isEqualToString:other.extension]);
+}
+
+
+- (id)copyWithZone:(NSZone *)zone
+{
+	NBPhoneNumber *phoneNumberCopy = [[NBPhoneNumber allocWithZone:zone] init];
+    
+	phoneNumberCopy.countryCode = [self.countryCode copy];
+    phoneNumberCopy.nationalNumber = [self.nationalNumber copy];
+    phoneNumberCopy.extension = [self.extension copy];
+    phoneNumberCopy.italianLeadingZero = self.italianLeadingZero;
+    phoneNumberCopy.rawInput = [self.rawInput copy];
+    phoneNumberCopy.countryCodeSource = [self.countryCodeSource copy];
+    phoneNumberCopy.preferredDomesticCarrierCode = [self.preferredDomesticCarrierCode copy];
+    
+	return phoneNumberCopy;
+}
+
+
+- (id)initWithCoder:(NSCoder*)coder
+{
+    if (self = [super init])
+    {
+        self.countryCode = [coder decodeObjectForKey:@"countryCode"];
+        self.nationalNumber = [coder decodeObjectForKey:@"nationalNumber"];
+        self.extension = [coder decodeObjectForKey:@"extension"];
+        self.italianLeadingZero = [[coder decodeObjectForKey:@"italianLeadingZero"] boolValue];
+        self.rawInput = [coder decodeObjectForKey:@"rawInput"];
+        self.countryCodeSource = [coder decodeObjectForKey:@"countryCodeSource"];
+        self.preferredDomesticCarrierCode = [coder decodeObjectForKey:@"preferredDomesticCarrierCode"];
+    }
+    return self;
+}
+
+
+- (void)encodeWithCoder:(NSCoder*)coder
+{
+    [coder encodeObject:self.countryCode forKey:@"countryCode"];
+    [coder encodeObject:self.nationalNumber forKey:@"nationalNumber"];
+    [coder encodeObject:self.extension forKey:@"extension"];
+    [coder encodeObject:[NSNumber numberWithBool:self.italianLeadingZero] forKey:@"italianLeadingZero"];
+    [coder encodeObject:self.rawInput forKey:@"rawInput"];
+    [coder encodeObject:self.countryCodeSource forKey:@"countryCodeSource"];
+    [coder encodeObject:self.preferredDomesticCarrierCode forKey:@"preferredDomesticCarrierCode"];
+}
+
+
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@" - countryCode[%@], nationalNumber[%@], extension[%@], italianLeadingZero[%@], rawInput[%@] countryCodeSource[%d] preferredDomesticCarrierCode[%@]", self.countryCode, self.nationalNumber, self.extension, self.italianLeadingZero?@"Y":@"N", self.rawInput, [self.countryCodeSource intValue], self.preferredDomesticCarrierCode];
+}
+
+@end
diff --git a/libPhoneNumber/NBPhoneNumberDefines.h b/libPhoneNumber/NBPhoneNumberDefines.h
new file mode 100644
index 0000000..f7c9bf8
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumberDefines.h
@@ -0,0 +1,107 @@
+//
+//  NBPhoneNumberDefines.h
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#ifndef libPhoneNumber_NBPhoneNumberDefines_h
+#define libPhoneNumber_NBPhoneNumberDefines_h
+
+#define NB_YES [NSNumber numberWithBool:YES]
+#define NB_NO [NSNumber numberWithBool:NO]
+
+#pragma mark - Enum -
+
+typedef enum {
+    NBEPhoneNumberFormatE164 = 0,
+    NBEPhoneNumberFormatINTERNATIONAL = 1,
+    NBEPhoneNumberFormatNATIONAL = 2,
+    NBEPhoneNumberFormatRFC3966 = 3
+} NBEPhoneNumberFormat;
+
+
+typedef enum {
+    NBEPhoneNumberTypeFIXED_LINE = 0,
+    NBEPhoneNumberTypeMOBILE = 1,
+    // In some regions (e.g. the USA), it is impossible to distinguish between
+    // fixed-line and mobile numbers by looking at the phone number itself.
+    NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE = 2,
+    // Freephone lines
+    NBEPhoneNumberTypeTOLL_FREE = 3,
+    NBEPhoneNumberTypePREMIUM_RATE = 4,
+    // The cost of this call is shared between the caller and the recipient, and
+    // is hence typically less than PREMIUM_RATE calls. See
+    // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
+    NBEPhoneNumberTypeSHARED_COST = 5,
+    // Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
+    NBEPhoneNumberTypeVOIP = 6,
+    // A personal number is associated with a particular person, and may be routed
+    // to either a MOBILE or FIXED_LINE number. Some more information can be found
+    // here = http://en.wikipedia.org/wiki/Personal_Numbers
+    NBEPhoneNumberTypePERSONAL_NUMBER = 7,
+    NBEPhoneNumberTypePAGER = 8,
+    // Used for 'Universal Access Numbers' or 'Company Numbers'. They may be
+    // further routed to specific offices, but allow one number to be used for a
+    // company.
+    NBEPhoneNumberTypeUAN = 9,
+    // Used for 'Voice Mail Access Numbers'.
+    NBEPhoneNumberTypeVOICEMAIL = 10,
+    // A phone number is of type UNKNOWN when it does not fit any of the known
+    // patterns for a specific region.
+    NBEPhoneNumberTypeUNKNOWN = -1
+} NBEPhoneNumberType;
+
+
+typedef enum {
+    NBEMatchTypeNOT_A_NUMBER = 0,
+    NBEMatchTypeNO_MATCH = 1,
+    NBEMatchTypeSHORT_NSN_MATCH = 2,
+    NBEMatchTypeNSN_MATCH = 3,
+    NBEMatchTypeEXACT_MATCH = 4
+} NBEMatchType;
+
+
+typedef enum {
+    NBEValidationResultIS_POSSIBLE = 0,
+    NBEValidationResultINVALID_COUNTRY_CODE = 1,
+    NBEValidationResultTOO_SHORT = 2,
+    NBEValidationResultTOO_LONG = 3
+} NBEValidationResult;
+
+
+typedef enum {
+    NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN = 1,
+    NBECountryCodeSourceFROM_NUMBER_WITH_IDD = 5,
+    NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN = 10,
+    NBECountryCodeSourceFROM_DEFAULT_COUNTRY = 20
+} NBECountryCodeSource;
+
+
+@interface NSArray (NBAdditions)
+
+- (id)safeObjectAtIndex:(NSUInteger)index;
+
+@end
+
+
+@implementation NSArray (NBAdditions)
+
+- (id)safeObjectAtIndex:(NSUInteger)index
+{
+    @synchronized(self)
+    {
+        if(index >= [self count]) return nil;
+        
+        id res = [self objectAtIndex:index];
+        
+        if (res == nil || (NSNull*)res == [NSNull null])
+            return nil;
+        
+        return res;
+    }
+}
+
+@end
+
+#endif
diff --git a/libPhoneNumber/NBPhoneNumberDesc.h b/libPhoneNumber/NBPhoneNumberDesc.h
new file mode 100644
index 0000000..288727c
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumberDesc.h
@@ -0,0 +1,19 @@
+//
+//  NBPhoneNumberDesc.h
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import <Foundation/Foundation.h>
+
+@interface NBPhoneNumberDesc : NSObject
+
+// from phonemetadata.pb.js
+/* 2 */ @property (nonatomic, strong, readwrite) NSString *nationalNumberPattern;
+/* 3 */ @property (nonatomic, strong, readwrite) NSString *possibleNumberPattern;
+/* 6 */ @property (nonatomic, strong, readwrite) NSString *exampleNumber;
+
+- (id)initWithData:(id)data;
+
+@end
diff --git a/libPhoneNumber/NBPhoneNumberDesc.m b/libPhoneNumber/NBPhoneNumberDesc.m
new file mode 100644
index 0000000..f698103
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumberDesc.m
@@ -0,0 +1,90 @@
+//
+//  NBPhoneNumberDesc.m
+//  libPhoneNumber
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import "NBPhoneNumberDesc.h"
+#import "NBPhoneNumberDefines.h"
+
+@implementation NBPhoneNumberDesc
+
+@synthesize nationalNumberPattern, possibleNumberPattern, exampleNumber;
+
+
+- (id)initWithData:(id)data
+{
+    self = [self init];
+    
+    if (self && data != nil && [data isKindOfClass:[NSArray class]])
+    {
+        /* 2 */ self.nationalNumberPattern = [data safeObjectAtIndex:2];
+        /* 3 */ self.possibleNumberPattern = [data safeObjectAtIndex:3];
+        /* 6 */ self.exampleNumber = [data safeObjectAtIndex:6];
+    }
+    
+    return self;
+}
+
+
+- (id)init
+{
+    self = [super init];
+    
+    if (self)
+    {
+    }
+    
+    return self;
+}
+
+
+- (id)initWithCoder:(NSCoder*)coder
+{
+    if (self = [super init])
+    {
+        self.nationalNumberPattern = [coder decodeObjectForKey:@"nationalNumberPattern"];
+        self.possibleNumberPattern = [coder decodeObjectForKey:@"possibleNumberPattern"];
+        self.exampleNumber = [coder decodeObjectForKey:@"exampleNumber"];
+    }
+    return self;
+}
+
+
+- (void)encodeWithCoder:(NSCoder*)coder
+{
+    [coder encodeObject:self.nationalNumberPattern forKey:@"nationalNumberPattern"];
+    [coder encodeObject:self.possibleNumberPattern forKey:@"possibleNumberPattern"];
+    [coder encodeObject:self.exampleNumber forKey:@"exampleNumber"];
+}
+
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"nationalNumberPattern[%@] possibleNumberPattern[%@] exampleNumber[%@]", self.nationalNumberPattern, self.possibleNumberPattern, self.exampleNumber];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+	NBPhoneNumberDesc *phoneDescCopy = [[NBPhoneNumberDesc allocWithZone:zone] init];
+    
+    phoneDescCopy.nationalNumberPattern = [self.nationalNumberPattern copy];
+    phoneDescCopy.possibleNumberPattern = [self.possibleNumberPattern copy];
+    phoneDescCopy.exampleNumber = [self.exampleNumber copy];
+    
+	return phoneDescCopy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    if ([object isKindOfClass:[NBPhoneNumberDesc class]] == NO)
+        return NO;
+    
+    NBPhoneNumberDesc *other = object;
+    return [self.nationalNumberPattern isEqual:other.nationalNumberPattern] &&
+        [self.possibleNumberPattern isEqual:other.possibleNumberPattern] &&
+        [self.exampleNumber isEqual:other.exampleNumber];
+}
+
+@end
diff --git a/libPhoneNumber/NBPhoneNumberMetadata.plist b/libPhoneNumber/NBPhoneNumberMetadata.plist
new file mode 100644
index 0000000..8cd2d03
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumberMetadata.plist
Binary files differ
diff --git a/libPhoneNumber/NBPhoneNumberUtil.h b/libPhoneNumber/NBPhoneNumberUtil.h
new file mode 100644
index 0000000..e9e13ec
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumberUtil.h
@@ -0,0 +1,108 @@
+//
+//  NBPhoneNumberUtil.h
+//  Band
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import <Foundation/Foundation.h>
+#import "NBPhoneNumberDefines.h"
+
+@class NBPhoneMetaData, NBPhoneNumber;
+
+@interface NBPhoneNumberUtil : NSObject
+
++ (NBPhoneNumberUtil*)sharedInstance;
++ (NBPhoneNumberUtil*)sharedInstanceForTest;
+
+// regular expressions
+- (NSArray*)matchesByRegex:(NSString*)sourceString regex:(NSString*)pattern;
+- (NSArray*)matchedStringByRegex:(NSString*)sourceString regex:(NSString*)pattern;
+- (NSString*)replaceStringByRegex:(NSString*)sourceString regex:(NSString*)pattern withTemplate:(NSString*)templateString;
+- (NSInteger)stringPositionByRegex:(NSString*)sourceString regex:(NSString*)pattern;
+
+
++ (NSString*)stringByTrimming:(NSString*)aString;
+
+//- (NSString*)numbersOnly:(NSString*)phoneNumber;
+- (NSArray*)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber;
+- (NSString*)countryCodeFromRegionCode:(NSString*)regionCode;
+
+
+// libPhoneNumber Util functions
+- (NSString*)convertAlphaCharactersInNumber:(NSString*)number;
+
+- (NSString*)normalizePhoneNumber:(NSString*)phoneNumber;
+- (NSString*)normalizeDigitsOnly:(NSString*)number;
+
+- (BOOL)isNumberGeographical:(NBPhoneNumber*)phoneNumber;
+
+- (NSString*)extractPossibleNumber:(NSString*)phoneNumber;
+- (NSNumber*)extractCountryCode:(NSString*)fullNumber nationalNumber:(NSString**)nationalNumber;
+
+- (NSString*)getNddPrefixForRegion:(NSString*)regionCode stripNonDigits:(BOOL)stripNonDigits;
+- (NSString*)getNationalSignificantNumber:(NBPhoneNumber*)phoneNumber;
+
+- (NBEPhoneNumberType)getNumberType:(NBPhoneNumber*)phoneNumber;
+
+- (NSNumber*)getCountryCodeForRegion:(NSString*)regionCode;
+
+- (NSString*)getRegionCodeForCountryCode:(NSNumber*)countryCallingCode;
+- (NSArray*)getRegionCodesForCountryCode:(NSNumber*)countryCallingCode;
+- (NSString*)getRegionCodeForNumber:(NBPhoneNumber*)phoneNumber;
+
+- (NBPhoneNumber*)getExampleNumber:(NSString*)regionCode error:(NSError**)error;
+- (NBPhoneNumber*)getExampleNumberForType:(NSString*)regionCode type:(NBEPhoneNumberType)type error:(NSError**)error;
+- (NBPhoneNumber*)getExampleNumberForNonGeoEntity:(NSNumber*)countryCallingCode error:(NSError**)error;
+
+- (NBPhoneMetaData*)getMetadataForNonGeographicalRegion:(NSNumber*)countryCallingCode;
+- (NBPhoneMetaData*)getMetadataForRegion:(NSString*)regionCode;
+
+- (BOOL)canBeInternationallyDialled:(NBPhoneNumber*)number error:(NSError**)error;
+
+- (BOOL)truncateTooLongNumber:(NBPhoneNumber*)number error:(NSError**)error;
+
+- (BOOL)isValidNumber:(NBPhoneNumber*)number;
+- (BOOL)isViablePhoneNumber:(NSString*)phoneNumber;
+- (BOOL)isAlphaNumber:(NSString*)number;
+- (BOOL)isValidNumberForRegion:(NBPhoneNumber*)number regionCode:(NSString*)regionCode;
+- (BOOL)isNANPACountry:(NSString*)regionCode;
+- (BOOL)isLeadingZeroPossible:(NSNumber*)countryCallingCode;
+
+- (NBEValidationResult)isPossibleNumberWithReason:(NBPhoneNumber*)number error:(NSError**)error;
+
+- (BOOL)isPossibleNumber:(NBPhoneNumber*)number error:(NSError**)error;
+- (BOOL)isPossibleNumberString:(NSString*)number regionDialingFrom:(NSString*)regionDialingFrom error:(NSError**)error;
+
+- (NBEMatchType)isNumberMatch:(id)firstNumberIn second:(id)secondNumberIn error:(NSError**)error;
+
+- (NSUInteger)getLengthOfGeographicalAreaCode:(NBPhoneNumber*)phoneNumber error:(NSError**)error;
+- (NSUInteger)getLengthOfNationalDestinationCode:(NBPhoneNumber*)phoneNumber error:(NSError**)error;
+
+- (BOOL)maybeStripNationalPrefixAndCarrierCode:(NSString**)numberStr metadata:(NBPhoneMetaData*)metadata carrierCode:(NSString**)carrierCode error:(NSError**)error;
+- (NBECountryCodeSource)maybeStripInternationalPrefixAndNormalize:(NSString**)numberStr possibleIddPrefix:(NSString*)possibleIddPrefix error:(NSError**)error;
+- (NSNumber*)maybeExtractCountryCode:(NSString*)number metadata:(NBPhoneMetaData*)defaultRegionMetadata
+                   nationalNumber:(NSString**)nationalNumber keepRawInput:(BOOL)keepRawInput phoneNumber:(NBPhoneNumber**)phoneNumber error:(NSError**)error;
+
+- (NBPhoneNumber*)parse:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion error:(NSError**)error;
+- (NBPhoneNumber*)parseAndKeepRawInput:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion error:(NSError**)error;
+- (NBPhoneNumber*)parseWithPhoneCarrierRegion:(NSString*)numberToParse error:(NSError**)error;
+
+- (NSString*)format:(NBPhoneNumber*)phoneNumber numberFormat:(NBEPhoneNumberFormat)numberFormat error:(NSError**)error;
+- (NSString*)formatByPattern:(NBPhoneNumber*)number numberFormat:(NBEPhoneNumberFormat)numberFormat userDefinedFormats:(NSArray*)userDefinedFormats error:(NSError**)error;
+- (NSString*)formatNumberForMobileDialing:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom withFormatting:(BOOL)withFormatting error:(NSError**)error;
+- (NSString*)formatOutOfCountryCallingNumber:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error;
+- (NSString*)formatOutOfCountryKeepingAlphaChars:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error;
+- (NSString*)formatNationalNumberWithCarrierCode:(NBPhoneNumber*)number carrierCode:(NSString*)carrierCode error:(NSError**)error;
+- (NSString*)formatInOriginalFormat:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error;
+- (NSString*)formatNationalNumberWithPreferredCarrierCode:(NBPhoneNumber*)number fallbackCarrierCode:(NSString*)fallbackCarrierCode error:(NSError**)error;
+
+- (BOOL)formattingRuleHasFirstGroupOnly:(NSString*)nationalPrefixFormattingRule;
+
+@property (nonatomic, readonly) NSString *VALID_PUNCTUATION;
+@property (nonatomic, readonly) NSString *VALID_DIGITS_STRING;
+@property (nonatomic, readonly) NSString *PLUS_CHARS_;
+@property (nonatomic, readonly) NSString *REGION_CODE_FOR_NON_GEO_ENTITY;
+@property (nonatomic, readonly) NSDictionary *DIGIT_MAPPINGS;
+
+@end
diff --git a/libPhoneNumber/NBPhoneNumberUtil.m b/libPhoneNumber/NBPhoneNumberUtil.m
new file mode 100644
index 0000000..bfb95c9
--- /dev/null
+++ b/libPhoneNumber/NBPhoneNumberUtil.m
@@ -0,0 +1,4305 @@
+//
+//  NBPhoneNumberUtil.m
+//  Band
+//
+//  Created by NHN Corp. Last Edited by BAND dev team (band_dev@nhn.com)
+//
+
+#import "NBPhoneNumberUtil.h"
+#import "NBPhoneNumber.h"
+#import "NBNumberFormat.h"
+#import "NBPhoneNumberDesc.h"
+#import "NBPhoneMetaData.h"
+#import "math.h"
+
+#import <CoreTelephony/CTTelephonyNetworkInfo.h>
+#import <CoreTelephony/CTCarrier.h>
+
+
+#pragma mark - Static Int variables -
+const static NSUInteger NANPA_COUNTRY_CODE_ = 1;
+const static NSUInteger MIN_LENGTH_FOR_NSN_ = 2;
+const static NSUInteger MAX_LENGTH_FOR_NSN_ = 16;
+const static NSUInteger MAX_LENGTH_COUNTRY_CODE_ = 3;
+const static NSUInteger MAX_INPUT_STRING_LENGTH_ = 250;
+
+
+#pragma mark - Static String variables -
+NSString *INVALID_COUNTRY_CODE_STR = @"Invalid country calling code";
+NSString *NOT_A_NUMBER_STR = @"The string supplied did not seem to be a phone number";
+NSString *TOO_SHORT_AFTER_IDD_STR = @"Phone number too short after IDD";
+NSString *TOO_SHORT_NSN_STR = @"The string supplied is too short to be a phone number";
+NSString *TOO_LONG_STR = @"The string supplied is too long to be a phone number";
+
+NSString *UNKNOWN_REGION_ = @"ZZ";
+NSString *COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_ = @"3";
+NSString *PLUS_SIGN = @"+";
+NSString *STAR_SIGN_ = @"*";
+NSString *RFC3966_EXTN_PREFIX_ = @";ext=";
+NSString *RFC3966_PREFIX_ = @"tel:";
+NSString *RFC3966_PHONE_CONTEXT_ = @";phone-context=";
+NSString *RFC3966_ISDN_SUBADDRESS_ = @";isub=";
+NSString *DEFAULT_EXTN_PREFIX_ = @" ext. ";
+NSString *VALID_ALPHA_ = @"A-Za-z";
+
+#pragma mark - Static regular expression strings -
+NSString *NON_DIGITS_PATTERN_ = @"\\D+";
+NSString *CC_PATTERN_ = @"\\$CC";
+NSString *FIRST_GROUP_PATTERN_ = @"(\\$\\d)";
+NSString *FIRST_GROUP_ONLY_PREFIX_PATTERN_ = @"^\\(?\\$1\\)?";
+NSString *NP_PATTERN_ = @"\\$NP";
+NSString *FG_PATTERN_ = @"\\$FG";
+NSString *VALID_ALPHA_PHONE_PATTERN_STRING = @"(?:.*?[A-Za-z]){3}.*";
+NSString *UNIQUE_INTERNATIONAL_PREFIX_ = @"[\\d]+(?:[~\\u2053\\u223C\\uFF5E][\\d]+)?";
+
+
+#pragma mark - NBPhoneNumberUtil interface -
+@interface NBPhoneNumberUtil ()
+
+/*
+ Terminologies
+ - Country Number (CN)  = Country code for i18n calling
+ - Country Code   (CC) : ISO country codes (2 chars)
+ Ref. site (countrycode.org)
+ */
+@property (nonatomic, readonly) NSDictionary *coreMetaData;
+@property (nonatomic, readonly) NSRegularExpression *PLUS_CHARS_PATTERN, *CAPTURING_DIGIT_PATTERN, *VALID_ALPHA_PHONE_PATTERN_;
+@property (nonatomic, readonly) NSString *LEADING_PLUS_CHARS_PATTERN_, *EXTN_PATTERN_, *SEPARATOR_PATTERN_, *VALID_PHONE_NUMBER_PATTERN_, *VALID_START_CHAR_PATTERN_, *UNWANTED_END_CHAR_PATTERN_, *SECOND_NUMBER_START_PATTERN_;
+
+@property (nonatomic, readonly) NSDictionary *ALPHA_MAPPINGS_, *ALL_NORMALIZATION_MAPPINGS_, *DIALLABLE_CHAR_MAPPINGS_, *ALL_PLUS_NUMBER_GROUPING_SYMBOLS_;
+
+@property (nonatomic, strong, readwrite) NSMutableDictionary *mapCCode2CN;
+@property (nonatomic, strong, readwrite) NSMutableDictionary *mapCN2CCode;
+
+@property (nonatomic, strong, readwrite) NSMutableDictionary *i18nNumberFormat;
+@property (nonatomic, strong, readwrite) NSMutableDictionary *i18nPhoneNumberDesc;
+@property (nonatomic, strong, readwrite) NSMutableDictionary *i18nPhoneMetadata;
+
+@end
+
+
+@implementation NBPhoneNumberUtil
+
++ (NBPhoneNumberUtil*)sharedInstance
+{
+    static NBPhoneNumberUtil *sharedOnceInstance = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{ sharedOnceInstance = [[self alloc] init]; });
+    return sharedOnceInstance;
+}
+
+
++ (NBPhoneNumberUtil*)sharedInstanceForTest
+{
+    static NBPhoneNumberUtil *sharedOnceInstanceForTest = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{ sharedOnceInstanceForTest = [[self alloc] initForTest]; });
+    return sharedOnceInstanceForTest;
+}
+
+
++ (NSString*)stringByTrimming:(NSString*)aString
+{
+    NSString *aRes = @"";
+    NSArray *newlines = [aString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
+    for (NSString *line in newlines)
+    {
+        NSString *performedString = [line stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+        
+        if (performedString.length > 0)
+            aRes = [aRes stringByAppendingString:performedString];
+    }
+    
+    if (newlines.count <= 0)
+        return aString;
+    
+    return aRes;
+}
+
+
+#pragma mark - Regular expression Utilities -
+- (BOOL)hasValue:(NSString*)string
+{
+    if (string == nil || [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length <= 0)
+    {
+        return NO;
+    }
+    
+    return YES;
+}
+
+
+- (NSMutableArray*)componentsSeparatedByRegex:(NSString*)sourceString regex:(NSString*)pattern
+{
+    NSString *replacedString = [self replaceStringByRegex:sourceString regex:pattern withTemplate:@"<SEP>"];
+    NSMutableArray *resArray = [[replacedString componentsSeparatedByString:@"<SEP>"] mutableCopy];
+    [resArray removeObject:@""];
+    return resArray;
+}
+
+
+- (NSInteger)stringPositionByRegex:(NSString*)sourceString regex:(NSString*)pattern
+{
+    if (sourceString == nil || sourceString.length <= 0 || pattern == nil || pattern.length <= 0) {
+        return -1;
+    }
+    
+    NSError *error = nil;
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+    NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+    
+    NSInteger foundPosition = -1;
+    
+    if (matches.count > 0)
+    {
+        NSTextCheckingResult *match = [matches objectAtIndex:0];
+        return match.range.location;
+    }
+    
+    return foundPosition;
+}
+
+
+- (NSInteger)indexOfStringByString:(NSString*)sourceString target:(NSString*)targetString
+{
+    NSRange finded = [sourceString rangeOfString:targetString];
+    if (finded.location != NSNotFound)
+    {
+        return finded.location;
+    }
+    
+    return -1;
+}
+
+
+- (NSString*)replaceFirstStringByRegex:(NSString*)sourceString regex:(NSString*)pattern withTemplate:(NSString*)templateString
+{
+    NSString *replacementResult = [sourceString copy];
+    NSError *error = nil;
+    
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+    NSRange replaceRange = [currentPattern rangeOfFirstMatchInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+    
+    if (replaceRange.location != NSNotFound)
+    {
+        replacementResult = [currentPattern stringByReplacingMatchesInString:[sourceString mutableCopy] options:0
+                                                                       range:replaceRange
+                                                                withTemplate:templateString];
+    }
+    
+    return replacementResult;
+}
+
+
+- (NSString*)replaceStringByRegex:(NSString*)sourceString regex:(NSString*)pattern withTemplate:(NSString*)templateString
+{
+    NSString *replacementResult = [sourceString copy];
+    NSError *error = nil;
+    
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+    NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+    
+    if ([matches count] == 1)
+    {
+        NSRange replaceRange = [currentPattern rangeOfFirstMatchInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+        
+        if (replaceRange.location != NSNotFound)
+        {
+            replacementResult = [currentPattern stringByReplacingMatchesInString:[sourceString mutableCopy] options:0
+                                                                           range:replaceRange
+                                                                    withTemplate:templateString];
+        }
+        return replacementResult;
+    }
+    
+    if ([matches count] > 1)
+    {
+        replacementResult = [currentPattern stringByReplacingMatchesInString:[replacementResult mutableCopy] options:0
+                                                                       range:NSMakeRange(0, sourceString.length) withTemplate:templateString];
+        return replacementResult;
+    }
+    
+    return replacementResult;
+}
+
+
+- (NSTextCheckingResult*)matcheFirstByRegex:(NSString*)sourceString regex:(NSString*)pattern
+{
+    NSError *error = nil;
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+    NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+    if ([matches count] > 0)
+        return [matches objectAtIndex:0];
+    return nil;
+}
+
+
+- (NSArray*)matchesByRegex:(NSString*)sourceString regex:(NSString*)pattern
+{
+    NSError *error = nil;
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+    NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+    return matches;
+}
+
+
+- (NSArray*)matchedStringByRegex:(NSString*)sourceString regex:(NSString*)pattern
+{
+    NSArray *matches = [self matchesByRegex:sourceString regex:pattern];
+    NSMutableArray *matchString = [[NSMutableArray alloc] init];
+    
+    for (NSTextCheckingResult *match in matches)
+    {
+        NSString *curString = [sourceString substringWithRange:match.range];
+        [matchString addObject:curString];
+    }
+    
+    return matchString;
+}
+
+
+- (BOOL)isStartingStringByRegex:(NSString*)sourceString regex:(NSString*)pattern
+{
+    NSError *error = nil;
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
+    NSArray *matches = [currentPattern matchesInString:sourceString options:0 range:NSMakeRange(0, sourceString.length)];
+    
+    for (NSTextCheckingResult *match in matches)
+    {
+        if (match.range.location == 0)
+        {
+            return YES;
+        }
+    }
+    
+    return NO;
+}
+
+
+- (NSString*)stringByReplacingOccurrencesString:(NSString *)sourceString withMap:(NSDictionary *)dicMap removeNonMatches:(BOOL)bRemove
+{
+    NSMutableString *targetString = [[NSMutableString alloc] initWithString:@""];
+    
+    for(NSUInteger i=0; i<sourceString.length; i++)
+    {
+        unichar oneChar = [sourceString characterAtIndex:i];
+        NSString *keyString = [NSString stringWithCharacters:&oneChar length:1];
+        NSString *mappedValue = [dicMap objectForKey:keyString];
+        if (mappedValue != nil)
+        {
+            [targetString appendString:mappedValue];
+        }
+        else
+        {
+            if (bRemove == NO)
+            {
+                [targetString appendString:keyString];
+            }
+        }
+    }
+    
+    return targetString;
+}
+
+
+- (BOOL)isNaN:(NSString*)sourceString
+{
+    NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
+    NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:sourceString];
+    BOOL hasNumberOnly = [alphaNums isSupersetOfSet:inStringSet];
+    
+    return !hasNumberOnly;
+}
+
+/*
+ - (NSString*)numbersOnly:(NSString*)phoneNumber
+ {
+ NSMutableString *strippedString = [NSMutableString stringWithCapacity:phoneNumber.length];
+ 
+ NSScanner *scanner = [NSScanner scannerWithString:phoneNumber];
+ NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
+ 
+ while ([scanner isAtEnd] == NO) {
+ NSString *buffer;
+ if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) {
+ [strippedString appendString:buffer];
+ 
+ } else {
+ [scanner setScanLocation:([scanner scanLocation] + 1)];
+ }
+ }
+ 
+ return strippedString;
+ }
+ */
+
+
+- (NSString*)getNationalSignificantNumber:(NBPhoneNumber*)phoneNumber
+{
+    if (phoneNumber.italianLeadingZero)
+    {
+        return [NSString stringWithFormat:@"0%@", phoneNumber.nationalNumber];
+    }
+    
+    return [NSString stringWithFormat:@"%@", phoneNumber.nationalNumber];
+}
+
+
+- (NSArray*)regionCodeFromCountryCode:(NSNumber *)countryCodeNumber
+{
+    if (self.mapCN2CCode == nil || [self.mapCN2CCode count] <= 0)
+    {
+        return nil;
+    }
+    
+    id res = [self.mapCN2CCode objectForKey:[NSString stringWithFormat:@"%@", countryCodeNumber]];
+    
+    if (res && [res isKindOfClass:[NSArray class]] && [((NSArray*)res) count] > 0)
+    {
+        return res;
+    }
+    
+    return nil;
+}
+
+
+- (NSString*)countryCodeFromRegionCode:(NSString*)regionCode
+{
+    if (self.mapCCode2CN == nil || [self.mapCCode2CN count] <= 0)
+    {
+        return nil;
+    }
+    
+    id res = [self.mapCCode2CN objectForKey:regionCode];
+    
+    if (res)
+    {
+        return res;
+    }
+    
+    return nil;
+}
+
+
+#pragma mark - Initializations -
+- (id)init
+{
+    self = [super init];
+    if (self)
+    {
+        [self initRegularExpressionSet];
+        [self initNormalizationMappings];
+        
+        NSDictionary *resData = [self loadMetadata:@"NBPhoneNumberMetadata"];
+        _coreMetaData = [resData objectForKey:@"countryToMetadata"];
+        _mapCN2CCode = [resData objectForKey:@"countryCodeToRegionCodeMap"];
+        
+        [self initCC2CN];
+    }
+    
+    return self;
+}
+
+
+- (id)initForTest
+{
+    self = [super init];
+    if (self)
+    {
+        [self initRegularExpressionSet];
+        [self initNormalizationMappings];
+        
+        NSDictionary *resData = [self loadMetadata:@"NBPhoneNumberMetadataForTesting"];
+        _coreMetaData = [resData objectForKey:@"countryToMetadata"];
+        _mapCN2CCode = [resData objectForKey:@"countryCodeToRegionCodeMap"];
+        
+        [self initCC2CN];
+    }
+    
+    return self;
+}
+
+
+- (NSDictionary*)loadMetadata:(NSString*)name
+{
+    NSDictionary *unarchiveData = nil;
+    
+    @try {
+        NSString *filePath = [[NSBundle mainBundle] pathForResource:name ofType:@"plist"];
+        NSData *fileData = [NSData dataWithContentsOfFile:filePath];
+        unarchiveData = [NSKeyedUnarchiver unarchiveObjectWithData:fileData];
+    }
+    @catch (NSException *exception) {
+        return unarchiveData;
+    }
+    
+    return unarchiveData;
+}
+
+/*
+ - (NSDictionary*)generateMetadata:(id)metaClass
+ {
+ NSMutableDictionary *resMedata = [[NSMutableDictionary alloc] init];
+ NSDictionary *srcMedata = nil;
+ 
+ if ([metaClass isKindOfClass:[NBPhoneNumberMetadataForTesting class]])
+ {
+ srcMedata = ((NBPhoneNumberMetadataForTesting*)metaClass).metadata;
+ }
+ else if ([metaClass isKindOfClass:[NBPhoneNumberMetadata class]])
+ {
+ srcMedata = ((NBPhoneNumberMetadata*)metaClass).metadata;
+ }
+ else
+ {
+ return resMedata;
+ }
+ 
+ NSDictionary *countryCodeToRegionCodeMap = [srcMedata objectForKey:@"countryCodeToRegionCodeMap"];
+ NSDictionary *countryToMetadata = [srcMedata objectForKey:@"countryToMetadata"];
+ NSLog(@"- countryCodeToRegionCodeMap count [%d]", [countryCodeToRegionCodeMap count]);
+ NSLog(@"- countryToMetadata          count [%d]", [countryToMetadata count]);
+ 
+ NSMutableDictionary *genetatedMetaData = [[NSMutableDictionary alloc] init];
+ 
+ for (id key in [countryToMetadata allKeys])
+ {
+ id metaData = [countryToMetadata objectForKey:key];
+ 
+ NBPhoneMetaData *newMetaData = [[NBPhoneMetaData alloc] init];
+ [newMetaData buildData:metaData];
+ 
+ [genetatedMetaData setObject:newMetaData forKey:key];
+ }
+ 
+ [resMedata setObject:countryCodeToRegionCodeMap forKey:@"countryCodeToRegionCodeMap"];
+ [resMedata setObject:genetatedMetaData forKey:@"countryToMetadata"];
+ 
+ return resMedata;
+ }
+ */
+
+
+- (void)initRegularExpressionSet
+{
+    _VALID_PUNCTUATION = @"-x‐-―−ー--/ ­​⁠ ()()[].\\[\\]/~⁓∼~";
+    _VALID_DIGITS_STRING = @"0-90-9٠-٩۰-۹";
+    _PLUS_CHARS_ = @"++";
+    _REGION_CODE_FOR_NON_GEO_ENTITY = @"001";
+    
+    NSString *EXTN_PATTERNS_FOR_PARSING_ = @"(?:;ext=([0-90-9٠-٩۰-۹]{1,7})|[  \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xxX##~~]|int|anexo|int)[:\\..]?[  \\t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)$";
+    
+    NSError *error = nil;
+    
+    _PLUS_CHARS_PATTERN =
+    [NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"[%@]+", _PLUS_CHARS_] options:0 error:&error];
+    
+    _LEADING_PLUS_CHARS_PATTERN_ = [NSString stringWithFormat:@"^[%@]+", _PLUS_CHARS_];
+    
+    _CAPTURING_DIGIT_PATTERN =
+    [NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"([%@])", _VALID_DIGITS_STRING] options:0 error:&error];
+    
+    _VALID_START_CHAR_PATTERN_ = [NSString stringWithFormat:@"[%@%@]", _PLUS_CHARS_, _VALID_DIGITS_STRING];
+    
+    _SECOND_NUMBER_START_PATTERN_ = @"[\\\\\\/] *x";
+    
+    _VALID_ALPHA_PHONE_PATTERN_ = [NSRegularExpression regularExpressionWithPattern:VALID_ALPHA_PHONE_PATTERN_STRING options:0 error:&error];
+    
+    _UNWANTED_END_CHAR_PATTERN_ = [NSString stringWithFormat:@"[^%@%@#]+$", _VALID_DIGITS_STRING, VALID_ALPHA_];
+    
+    _EXTN_PATTERN_ = [NSString stringWithFormat:@"(?:%@)$", EXTN_PATTERNS_FOR_PARSING_];
+    
+    
+    _SEPARATOR_PATTERN_ = [NSString stringWithFormat:@"[%@]+", _VALID_PUNCTUATION];
+    
+    _VALID_PHONE_NUMBER_PATTERN_ = @"^[0-90-9٠-٩۰-۹]{2}$|^[++]*(?:[-x‐-―−ー--/  ­​⁠ ()()[].\\[\\]/~⁓∼~*]*[0-90-9٠-٩۰-۹]){3,}[-x‐-―−ー--/  ­​⁠ ()()[].\\[\\]/~⁓∼~*A-Za-z0-90-9٠-٩۰-۹]*(?:;ext=([0-90-9٠-٩۰-۹]{1,7})|[  \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xx##~~]|int|anexo|int)[:\\..]?[  \\t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)?$";
+}
+
+
+- (void)dealloc
+{
+    [self clearCC2CN];
+    [self clearCN2CC];
+}
+
+
+- (void)clearCC2CN
+{
+    if (self.mapCCode2CN != nil)
+    {
+        [self.mapCCode2CN removeAllObjects];
+        self.mapCCode2CN = nil;
+    }
+}
+
+
+- (void)clearCN2CC
+{
+    if (self.mapCN2CCode != nil)
+    {
+        [self.mapCN2CCode removeAllObjects];
+        self.mapCN2CCode = nil;
+    }
+}
+
+
+- (void)initNormalizationMappings
+{
+    _DIGIT_MAPPINGS = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                       @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9",
+                       // Fullwidth digit 0 to 9
+                       @"0", @"\uFF10", @"1", @"\uFF11", @"2", @"\uFF12", @"3", @"\uFF13", @"4", @"\uFF14", @"5", @"\uFF15", @"6", @"\uFF16", @"7", @"\uFF17", @"8", @"\uFF18", @"9", @"\uFF19",
+                       // Arabic-indic digit 0 to 9
+                       @"0", @"\u0660", @"1", @"\u0661", @"2", @"\u0662", @"3", @"\u0663", @"4", @"\u0664", @"5", @"\u0665", @"6", @"\u0666", @"7", @"\u0667", @"8", @"\u0668", @"9", @"\u0669",
+                       // Eastern-Arabic digit 0 to 9
+                       @"0", @"\u06F0", @"1", @"\u06F1",  @"2", @"\u06F2", @"3", @"\u06F3", @"4", @"\u06F4", @"5", @"\u06F5", @"6", @"\u06F6", @"7", @"\u06F7", @"8", @"\u06F8", @"9", @"\u06F9", nil];
+    
+    _DIALLABLE_CHAR_MAPPINGS_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                 @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9",
+                                 @"+", @"+", @"*", @"*", nil];
+    
+    _ALPHA_MAPPINGS_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                        @"2", @"A", @"2", @"B", @"2", @"C", @"3", @"D", @"3", @"E", @"3", @"F", @"4", @"G", @"4", @"H", @"4", @"I", @"5", @"J",
+                        @"5", @"K", @"5", @"L", @"6", @"M", @"6", @"N", @"6", @"O", @"7", @"P", @"7", @"Q", @"7", @"R", @"7", @"S", @"8", @"T",
+                        @"8", @"U", @"8", @"V", @"9", @"W", @"9", @"X", @"9", @"Y", @"9", @"Z", nil];
+    
+    _ALL_NORMALIZATION_MAPPINGS_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                    @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9",
+                                    // Fullwidth digit 0 to 9
+                                    @"0", @"\uFF10", @"1", @"\uFF11", @"2", @"\uFF12", @"3", @"\uFF13", @"4", @"\uFF14", @"5", @"\uFF15", @"6", @"\uFF16", @"7", @"\uFF17", @"8", @"\uFF18", @"9", @"\uFF19",
+                                    // Arabic-indic digit 0 to 9
+                                    @"0", @"\u0660", @"1", @"\u0661", @"2", @"\u0662", @"3", @"\u0663", @"4", @"\u0664", @"5", @"\u0665", @"6", @"\u0666", @"7", @"\u0667", @"8", @"\u0668", @"9", @"\u0669",
+                                    // Eastern-Arabic digit 0 to 9
+                                    @"0", @"\u06F0", @"1", @"\u06F1",  @"2", @"\u06F2", @"3", @"\u06F3", @"4", @"\u06F4", @"5", @"\u06F5", @"6", @"\u06F6", @"7", @"\u06F7", @"8", @"\u06F8", @"9", @"\u06F9",
+                                    @"2", @"A", @"2", @"B", @"2", @"C", @"3", @"D", @"3", @"E", @"3", @"F", @"4", @"G", @"4", @"H", @"4", @"I", @"5", @"J",
+                                    @"5", @"K", @"5", @"L", @"6", @"M", @"6", @"N", @"6", @"O", @"7", @"P", @"7", @"Q", @"7", @"R", @"7", @"S", @"8", @"T",
+                                    @"8", @"U", @"8", @"V", @"9", @"W", @"9", @"X", @"9", @"Y", @"9", @"Z", nil];
+    
+    _ALL_PLUS_NUMBER_GROUPING_SYMBOLS_ = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                          @"0", @"0", @"1", @"1", @"2", @"2", @"3", @"3", @"4", @"4", @"5", @"5", @"6", @"6", @"7", @"7", @"8", @"8", @"9", @"9",
+                                          @"A", @"A", @"B", @"B", @"C", @"C", @"D", @"D", @"E", @"E", @"F", @"F", @"G", @"G", @"H", @"H", @"I", @"I", @"J", @"J",
+                                          @"K", @"K", @"L", @"L", @"M", @"M", @"N", @"N", @"O", @"O", @"P", @"P", @"Q", @"Q", @"R", @"R", @"S", @"S", @"T", @"T",
+                                          @"U", @"U", @"V", @"V", @"W", @"W", @"X", @"X", @"Y", @"Y", @"Z", @"Z", @"A", @"a", @"B", @"b", @"C", @"c", @"D", @"d",
+                                          @"E", @"e", @"F", @"f", @"G", @"g", @"H", @"h", @"I", @"i", @"J", @"j", @"K", @"k", @"L", @"l", @"M", @"m", @"N", @"n",
+                                          @"O", @"o", @"P", @"p", @"Q", @"q", @"R", @"r", @"S", @"s", @"T", @"t", @"U", @"u", @"V", @"v", @"W", @"w", @"X", @"x",
+                                          @"Y", @"y", @"Z", @"z", @"-", @"-", @"-", @"\uFF0D", @"-", @"\u2010", @"-", @"\u2011", @"-", @"\u2012", @"-", @"\u2013", @"-", @"\u2014", @"-", @"\u2015",
+                                          @"-", @"\u2212", @"/", @"/", @"/", @"\uFF0F", @" ", @" ", @" ", @"\u3000", @" ", @"\u2060", @".", @".", @".", @"\uFF0E", nil];
+    
+}
+
+
+- (void)initCC2CN
+{
+    [self clearCC2CN];
+    _mapCCode2CN = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                    @"1", @"US", @"1", @"AG", @"1", @"AI", @"1", @"AS", @"1", @"BB", @"1", @"BM", @"1", @"BS", @"1", @"CA", @"1", @"DM", @"1", @"DO",
+                    @"1", @"GD", @"1", @"GU", @"1", @"JM", @"1", @"KN", @"1", @"KY", @"1", @"LC", @"1", @"MP", @"1", @"MS", @"1", @"PR", @"1", @"SX",
+                    @"1", @"TC", @"1", @"TT", @"1", @"VC", @"1", @"VG", @"1", @"VI", @"7", @"RU", @"7", @"KZ",
+                    @"20", @"EG", @"27", @"ZA",
+                    @"30", @"GR", @"31", @"NL", @"32", @"BE", @"33", @"FR", @"34", @"ES", @"36", @"HU", @"39", @"IT",
+                    @"40", @"RO", @"41", @"CH", @"43", @"AT", @"44", @"GB", @"44", @"GG", @"44", @"IM", @"44", @"JE", @"45", @"DK", @"46", @"SE", @"47", @"NO", @"47", @"SJ", @"48", @"PL", @"49", @"DE",
+                    @"51", @"PE", @"52", @"MX", @"53", @"CU", @"54", @"AR", @"55", @"BR", @"56", @"CL", @"57", @"CO", @"58", @"VE",
+                    @"60", @"MY", @"61", @"AU", @"61", @"CC", @"61", @"CX", @"62", @"ID", @"63", @"PH", @"64", @"NZ", @"65", @"SG", @"66", @"TH",
+                    @"81", @"JP", @"82", @"KR", @"84", @"VN", @"86", @"CN",
+                    @"90", @"TR", @"91", @"IN", @"92", @"PK", @"93", @"AF", @"94", @"LK", @"95", @"MM", @"98", @"IR",
+                    @"211", @"SS", @"212", @"MA", @"212", @"EH", @"213", @"DZ", @"216", @"TN", @"218", @"LY",
+                    @"220", @"GM", @"221", @"SN", @"222", @"MR", @"223", @"ML", @"224", @"GN", @"225", @"CI", @"226", @"BF", @"227", @"NE", @"228", @"TG", @"229", @"BJ",
+                    @"230", @"MU", @"231", @"LR", @"232", @"SL", @"233", @"GH", @"234", @"NG", @"235", @"TD", @"236", @"CF", @"237", @"CM", @"238", @"CV", @"239", @"ST",
+                    @"240", @"GQ", @"241", @"GA", @"242", @"CG", @"243", @"CD", @"244", @"AO", @"245", @"GW", @"246", @"IO", @"247", @"AC", @"248", @"SC", @"249", @"SD",
+                    @"250", @"RW", @"251", @"ET", @"252", @"SO", @"253", @"DJ", @"254", @"KE", @"255", @"TZ", @"256", @"UG", @"257", @"BI", @"258", @"MZ",
+                    @"260", @"ZM", @"261", @"MG", @"262", @"RE", @"262", @"YT", @"263", @"ZW", @"264", @"NA", @"265", @"MW", @"266", @"LS", @"267", @"BW", @"268", @"SZ", @"269", @"KM",
+                    @"290", @"SH", @"291", @"ER", @"297", @"AW", @"298", @"FO", @"299", @"GL",
+                    @"350", @"GI", @"351", @"PT", @"352", @"LU", @"353", @"IE", @"354", @"IS", @"355", @"AL", @"356", @"MT", @"357", @"CY", @"358", @"FI",@"358", @"AX", @"359", @"BG",
+                    @"370", @"LT", @"371", @"LV", @"372", @"EE", @"373", @"MD", @"374", @"AM", @"375", @"BY", @"376", @"AD", @"377", @"MC", @"378", @"SM", @"379", @"VA",
+                    @"380", @"UA", @"381", @"RS", @"382", @"ME", @"385", @"HR", @"386", @"SI", @"387", @"BA", @"389", @"MK",
+                    @"420", @"CZ", @"421", @"SK", @"423", @"LI",
+                    @"500", @"FK", @"501", @"BZ", @"502", @"GT", @"503", @"SV", @"504", @"HN", @"505", @"NI", @"506", @"CR", @"507", @"PA", @"508", @"PM", @"509", @"HT",
+                    @"590", @"GP", @"590", @"BL", @"590", @"MF", @"591", @"BO", @"592", @"GY", @"593", @"EC", @"594", @"GF", @"595", @"PY", @"596", @"MQ", @"597", @"SR", @"598", @"UY", @"599", @"CW", @"599", @"BQ",
+                    @"670", @"TL", @"672", @"NF", @"673", @"BN", @"674", @"NR", @"675", @"PG", @"676", @"TO", @"677", @"SB", @"678", @"VU", @"679", @"FJ",
+                    @"680", @"PW", @"681", @"WF", @"682", @"CK", @"683", @"NU", @"685", @"WS", @"686", @"KI", @"687", @"NC", @"688", @"TV", @"689", @"PF",
+                    @"690", @"TK", @"691", @"FM", @"692", @"MH",
+                    @"800", @"001", @"808", @"001",
+                    @"850", @"KP", @"852", @"HK", @"853", @"MO", @"855", @"KH", @"856", @"LA",
+                    @"870", @"001", @"878", @"001",
+                    @"880", @"BD", @"881", @"001", @"882", @"001", @"883", @"001", @"886", @"TW", @"888", @"001",
+                    @"960", @"MV", @"961", @"LB", @"962", @"JO", @"963", @"SY", @"964", @"IQ", @"965", @"KW", @"966", @"SA", @"967", @"YE", @"968", @"OM",
+                    @"970", @"PS", @"971", @"AE", @"972", @"IL", @"973", @"BH", @"974", @"QA", @"975", @"BT", @"976", @"MN", @"977", @"NP", @"979", @"001",
+                    @"992", @"TJ", @"993", @"TM", @"994", @"AZ", @"995", @"GE", @"996", @"KG", @"998", @"UZ",
+                    nil];
+}
+
+/*
+ - (void)initCN2CC
+ {
+ [self clearCN2CC];
+ _mapCN2CCode = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ @[@"US", @"AG", @"AI", @"AS", @"BB", @"BM", @"BS", @"CA", @"DM", @"DO", @"GD", @"GU", @"JM", @"KN", @"KY", @"LC", @"MP", @"MS", @"PR", @"SX", @"TC", @"TT", @"VC", @"VG", @"VI"], @"1", @[@"RU", @"KZ"], @"7",
+ @[@"EG"], @"20", @[@"ZA"], @"27",
+ @[@"GR"], @"30", @[@"NL"], @"31", @[@"BE"], @"32", @[@"FR"], @"33", @[@"ES"], @"34", @[@"HU"], @"36", @[@"IT"], @"39",
+ @[@"RO"], @"40", @[@"CH"], @"41", @[@"AT"], @"43", @[@"GB", @"GG", @"IM", @"JE"], @"44", @[@"DK"], @"45", @[@"SE"], @"46", @[@"NO", @"SJ"], @"47", @[@"PL"], @"48", @[@"DE"], @"49",
+ @[@"PE"], @"51", @[@"MX"], @"52", @[@"CU"], @"53", @[@"AR"], @"54", @[@"BR"], @"55", @[@"CL"], @"56", @[@"CO"], @"57", @[@"VE"], @"58",
+ @[@"MY"], @"60", @[@"AU", @"CC", @"CX"], @"61", @[@"ID"], @"62", @[@"PH"], @"63", @[@"NZ"], @"64", @[@"SG"], @"65", @[@"TH"], @"66",
+ @[@"JP"], @"81", @[@"KR"], @"82", @[@"VN"], @"84", @[@"CN"], @"86",
+ @[@"TR"], @"90", @[@"IN"], @"91", @[@"PK"], @"92", @[@"AF"], @"93", @[@"LK"], @"94", @[@"MM"], @"95", @[@"IR"], @"98",
+ @[@"SS"], @"211", @[@"MA", @"EH"], @"212", @[@"DZ"], @"213", @[@"TN"], @"216", @[@"LY"], @"218",
+ @[@"GM"], @"220", @[@"SN"], @"221", @[@"MR"], @"222", @[@"ML"], @"223", @[@"GN"], @"224", @[@"CI"], @"225", @[@"BF"], @"226", @[@"NE"], @"227", @[@"TG"], @"228", @[@"BJ"], @"229",
+ @[@"MU"], @"230", @[@"LR"], @"231", @[@"SL"], @"232", @[@"GH"], @"233", @[@"NG"], @"234", @[@"TD"], @"235", @[@"CF"], @"236", @[@"CM"], @"237", @[@"CV"], @"238", @[@"ST"], @"239",
+ @[@"GQ"], @"240", @[@"GA"], @"241", @[@"CG"], @"242", @[@"CD"], @"243", @[@"AO"], @"244", @[@"GW"], @"245", @[@"IO"], @"246", @[@"AC"], @"247", @[@"SC"], @"248", @[@"SD"], @"249",
+ @[@"RW"], @"250", @[@"ET"], @"251", @[@"SO"], @"252", @[@"DJ"], @"253", @[@"KE"], @"254", @[@"TZ"], @"255", @[@"UG"], @"256", @[@"BI"], @"257", @[@"MZ"], @"258",
+ @[@"ZM"], @"260", @[@"MG"], @"261", @[@"RE", @"YT"], @"262", @[@"ZW"], @"263", @[@"NA"], @"264", @[@"MW"], @"265", @[@"LS"], @"266", @[@"BW"], @"267", @[@"SZ"], @"268", @[@"KM"], @"269",
+ @[@"SH"], @"290", @[@"ER"], @"291", @[@"AW"], @"297", @[@"FO"], @"298", @[@"GL"], @"299",
+ @[@"GI"], @"350", @[@"PT"], @"351", @[@"LU"], @"352", @[@"IE"], @"353", @[@"IS"], @"354", @[@"AL"], @"355", @[@"MT"], @"356", @[@"CY"], @"357", @[@"FI", @"AX"], @"358", @[@"BG"], @"359",
+ @[@"LT"], @"370", @[@"LV"], @"371", @[@"EE"], @"372", @[@"MD"], @"373", @[@"AM"], @"374", @[@"BY"], @"375", @[@"AD"], @"376", @[@"MC"], @"377", @[@"SM"], @"378", @[@"VA"], @"379",
+ @[@"UA"], @"380", @[@"RS"], @"381", @[@"ME"], @"382", @[@"HR"], @"385", @[@"SI"], @"386", @[@"BA"], @"387", @[@"MK"], @"389",
+ @[@"CZ"], @"420", @[@"SK"], @"421", @[@"LI"], @"423",
+ @[@"FK"], @"500", @[@"BZ"], @"501", @[@"GT"], @"502", @[@"SV"], @"503", @[@"HN"], @"504", @[@"NI"], @"505", @[@"CR"], @"506", @[@"PA"], @"507", @[@"PM"], @"508", @[@"HT"], @"509",
+ @[@"GP", @"BL", @"MF"], @"590", @[@"BO"], @"591", @[@"GY"], @"592", @[@"EC"], @"593", @[@"GF"], @"594", @[@"PY"], @"595", @[@"MQ"], @"596", @[@"SR"], @"597", @[@"UY"], @"598", @[@"CW", @"BQ"], @"599",
+ @[@"TL"], @"670", @[@"NF"], @"672", @[@"BN"], @"673", @[@"NR"], @"674", @[@"PG"], @"675", @[@"TO"], @"676", @[@"SB"], @"677", @[@"VU"], @"678", @[@"FJ"], @"679",
+ @[@"PW"], @"680", @[@"WF"], @"681", @[@"CK"], @"682", @[@"NU"], @"683", @[@"WS"], @"685", @[@"KI"], @"686", @[@"NC"], @"687", @[@"TV"], @"688", @[@"PF"], @"689",
+ @[@"TK"], @"690", @[@"FM"], @"691", @[@"MH"], @"692",
+ @[@"001"], @"800", @[@"001"], @"808",
+ @[@"KP"], @"850", @[@"HK"], @"852", @[@"MO"], @"853", @[@"KH"], @"855", @[@"LA"], @"856",
+ @[@"001"], @"870", @[@"001"], @"878",
+ @[@"BD"], @"880", @[@"001"], @"881", @[@"001"], @"882", @[@"001"], @"883", @[@"TW"], @"886", @[@"001"], @"888",
+ @[@"MV"], @"960", @[@"LB"], @"961", @[@"JO"], @"962", @[@"SY"], @"963", @[@"IQ"], @"964", @[@"KW"], @"965", @[@"SA"], @"966", @[@"YE"], @"967", @[@"OM"], @"968",
+ @[@"PS"], @"970", @[@"AE"], @"971", @[@"IL"], @"972", @[@"BH"], @"973", @[@"QA"], @"974", @[@"BT"], @"975", @[@"MN"], @"976", @[@"NP"], @"977", @[@"001"], @"979",
+ @[@"TJ"], @"992", @[@"TM"], @"993", @[@"AZ"], @"994", @[@"GE"], @"995", @[@"KG"], @"996", @[@"UZ"], @"998", nil];
+ }
+ */
+
+
+#pragma mark - Metadata manager (phonenumberutil.js) functions -
+/**
+ * Attempts to extract a possible number from the string passed in. This
+ * currently strips all leading characters that cannot be used to start a phone
+ * number. Characters that can be used to start a phone number are defined in
+ * the VALID_START_CHAR_PATTERN. If none of these characters are found in the
+ * number passed in, an empty string is returned. This function also attempts to
+ * strip off any alternative extensions or endings if two or more are present,
+ * such as in the case of: (530) 583-6985 x302/x2303. The second extension here
+ * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985
+ * x2303. We remove the second extension so that the first number is parsed
+ * correctly.
+ *
+ * @param {string} number the string that might contain a phone number.
+ * @return {string} the number, stripped of any non-phone-number prefix (such as
+ *     'Tel:') or an empty string if no character used to start phone numbers
+ *     (such as + or any digit) is found in the number.
+ */
+- (NSString*)extractPossibleNumber:(NSString*)number
+{
+    NSString *possibleNumber = @"";
+    NSInteger start = [self stringPositionByRegex:number regex:self.VALID_START_CHAR_PATTERN_];
+    
+    if (start >= 0)
+    {
+        possibleNumber = [number substringFromIndex:start];
+        // Remove trailing non-alpha non-numerical characters.
+        possibleNumber = [self replaceStringByRegex:possibleNumber regex:self.UNWANTED_END_CHAR_PATTERN_ withTemplate:@""];
+        
+        // Check for extra numbers at the end.
+        NSInteger secondNumberStart = [self stringPositionByRegex:number regex:self.SECOND_NUMBER_START_PATTERN_];
+        if (secondNumberStart >= 0)
+        {
+            possibleNumber = [possibleNumber substringWithRange:NSMakeRange(0, secondNumberStart - 1)];
+        }
+    }
+    else
+    {
+        possibleNumber = @"";
+    }
+    
+    return possibleNumber;
+    
+    /*
+     NSString *possibleNumber = @"";
+     NSRegularExpression *currentPattern = self.VALID_START_CHAR_PATTERN_;
+     int sourceLength = phoneNumber.length;
+     
+     NSArray *matches = [currentPattern matchesInString:phoneNumber options:0 range:NSMakeRange(0, sourceLength)];
+     if (matches && [matches count] > 0)
+     {
+     NSRange rangeOfFirstMatch = ((NSTextCheckingResult*)[matches objectAtIndex:0]).range;
+     possibleNumber = [phoneNumber substringFromIndex:rangeOfFirstMatch.location];
+     
+     // Remove trailing non-alpha non-numerical characters.
+     currentPattern = self.UNWANTED_END_CHAR_PATTERN_;
+     possibleNumber = [currentPattern stringByReplacingMatchesInString:possibleNumber options:0
+     range:NSMakeRange(0, [possibleNumber length]) withTemplate:@""];
+     // Check for extra numbers at the end.
+     currentPattern = self.SECOND_NUMBER_START_PATTERN_;
+     matches = [currentPattern matchesInString:possibleNumber options:0
+     range:NSMakeRange(0, [possibleNumber length])];
+     if (matches && [matches count] > 0)
+     {
+     NSRange rangeOfSecondMatch = ((NSTextCheckingResult*)[matches objectAtIndex:0]).range;
+     possibleNumber = [possibleNumber substringWithRange:NSMakeRange(0, rangeOfSecondMatch.location)];
+     }
+     }
+     
+     return possibleNumber;
+     */
+}
+
+
+/**
+ * Checks to see if the string of characters could possibly be a phone number at
+ * all. At the moment, checks to see that the string begins with at least 2
+ * digits, ignoring any punctuation commonly found in phone numbers. This method
+ * does not require the number to be normalized in advance - but does assume
+ * that leading non-number symbols have been removed, such as by the method
+ * extractPossibleNumber.
+ *
+ * @param {string} number string to be checked for viability as a phone number.
+ * @return {boolean} NO if the number could be a phone number of some sort,
+ *     otherwise NO.
+ */
+- (BOOL)isViablePhoneNumber:(NSString*)phoneNumber
+{
+    if (phoneNumber.length < MIN_LENGTH_FOR_NSN_)
+    {
+        return NO;
+    }
+    
+    return [self matchesEntirely:self.VALID_PHONE_NUMBER_PATTERN_ string:phoneNumber];
+}
+
+
+/**
+ * Normalizes a string of characters representing a phone number. This performs
+ * the following conversions:
+ *   Punctuation is stripped.
+ *   For ALPHA/VANITY numbers:
+ *   Letters are converted to their numeric representation on a telephone
+ *       keypad. The keypad used here is the one defined in ITU Recommendation
+ *       E.161. This is only done if there are 3 or more letters in the number,
+ *       to lessen the risk that such letters are typos.
+ *   For other numbers:
+ *   Wide-ascii digits are converted to normal ASCII (European) digits.
+ *   Arabic-Indic numerals are converted to European numerals.
+ *   Spurious alpha characters are stripped.
+ *
+ * @param {string} number a string of characters representing a phone number.
+ * @return {string} the normalized string version of the phone number.
+ */
+- (NSString*)normalizePhoneNumber:(NSString*)number
+{
+    if ([self matchesEntirely:VALID_ALPHA_PHONE_PATTERN_STRING string:number])
+    {
+        return [self normalizeHelper:number normalizationReplacements:self.ALL_NORMALIZATION_MAPPINGS_ removeNonMatches:true];
+    }
+    else
+    {
+        return [self normalizeDigitsOnly:number];
+    }
+    
+    return nil;
+}
+
+
+/**
+ * Normalizes a string of characters representing a phone number. This is a
+ * wrapper for normalize(String number) but does in-place normalization of the
+ * StringBuffer provided.
+ *
+ * @param {!goog.string.StringBuffer} number a StringBuffer of characters
+ *     representing a phone number that will be normalized in place.
+ * @private
+ */
+
+- (void)normalizeSB:(NSString**)number
+{
+    if (number == NULL)
+    {
+        return;
+    }
+    
+    (*number) = [self normalizePhoneNumber:(*number)];
+}
+
+
+/**
+ * Normalizes a string of characters representing a phone number. This converts
+ * wide-ascii and arabic-indic numerals to European numerals, and strips
+ * punctuation and alpha characters.
+ *
+ * @param {string} number a string of characters representing a phone number.
+ * @return {string} the normalized string version of the phone number.
+ */
+- (NSString*)normalizeDigitsOnly:(NSString*)number
+{
+    return [self stringByReplacingOccurrencesString:number
+                                            withMap:self.DIGIT_MAPPINGS removeNonMatches:YES];
+}
+
+
+/**
+ * Converts all alpha characters in a number to their respective digits on a
+ * keypad, but retains existing formatting. Also converts wide-ascii digits to
+ * normal ascii digits, and converts Arabic-Indic numerals to European numerals.
+ *
+ * @param {string} number a string of characters representing a phone number.
+ * @return {string} the normalized string version of the phone number.
+ */
+- (NSString*)convertAlphaCharactersInNumber:(NSString*)number
+{
+    return [self stringByReplacingOccurrencesString:number
+                                            withMap:self.ALL_NORMALIZATION_MAPPINGS_ removeNonMatches:NO];
+}
+
+
+/**
+ * Gets the length of the geographical area code from the
+ * {@code national_number} field of the PhoneNumber object passed in, so that
+ * clients could use it to split a national significant number into geographical
+ * area code and subscriber number. It works in such a way that the resultant
+ * subscriber number should be diallable, at least on some devices. An example
+ * of how this could be used:
+ *
+ * <pre>
+ * var phoneUtil = getInstance();
+ * var number = phoneUtil.parse('16502530000', 'US');
+ * var nationalSignificantNumber =
+ *     phoneUtil.getNationalSignificantNumber(number);
+ * var areaCode;
+ * var subscriberNumber;
+ *
+ * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
+ * if (areaCodeLength > 0) {
+ *   areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
+ *   subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
+ * } else {
+ *   areaCode = '';
+ *   subscriberNumber = nationalSignificantNumber;
+ * }
+ * </pre>
+ *
+ * N.B.: area code is a very ambiguous concept, so the I18N team generally
+ * recommends against using it for most purposes, but recommends using the more
+ * general {@code national_number} instead. Read the following carefully before
+ * deciding to use this method:
+ * <ul>
+ *  <li> geographical area codes change over time, and this method honors those
+ *    changes; therefore, it doesn't guarantee the stability of the result it
+ *    produces.
+ *  <li> subscriber numbers may not be diallable from all devices (notably
+ *    mobile devices, which typically requires the full national_number to be
+ *    dialled in most regions).
+ *  <li> most non-geographical numbers have no area codes, including numbers
+ *    from non-geographical entities.
+ *  <li> some geographical numbers have no area codes.
+ * </ul>
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
+ *     which clients want to know the length of the area code.
+ * @return {number} the length of area code of the PhoneNumber object passed in.
+ */
+- (NSUInteger)getLengthOfGeographicalAreaCode:(NBPhoneNumber*)phoneNumber error:(NSError **)error
+{
+    NSUInteger res = 0;
+    @try {
+        res = [self getLengthOfGeographicalAreaCode:phoneNumber];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+        {
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+        }
+    }
+    return res;
+}
+
+
+- (NSUInteger)getLengthOfGeographicalAreaCode:(NBPhoneNumber*)phoneNumber
+{
+    NSString *regionCode = [self getRegionCodeForNumber:phoneNumber];
+    NBPhoneMetaData *metadata = [self getMetadataForRegion:regionCode];
+    
+    if (metadata == nil)
+    {
+        return 0;
+    }
+    // If a country doesn't use a national prefix, and this number doesn't have
+    // an Italian leading zero, we assume it is a closed dialling plan with no
+    // area codes.
+    if (metadata.nationalPrefix == nil && phoneNumber.italianLeadingZero == NO)
+    {
+        return 0;
+    }
+    
+    if ([self isNumberGeographical:phoneNumber] == NO)
+    {
+        return 0;
+    }
+    
+    return [self getLengthOfNationalDestinationCode:phoneNumber];
+}
+
+
+/**
+ * Gets the length of the national destination code (NDC) from the PhoneNumber
+ * object passed in, so that clients could use it to split a national
+ * significant number into NDC and subscriber number. The NDC of a phone number
+ * is normally the first group of digit(s) right after the country calling code
+ * when the number is formatted in the international format, if there is a
+ * subscriber number part that follows. An example of how this could be used:
+ *
+ * <pre>
+ * var phoneUtil = getInstance();
+ * var number = phoneUtil.parse('18002530000', 'US');
+ * var nationalSignificantNumber =
+ *     phoneUtil.getNationalSignificantNumber(number);
+ * var nationalDestinationCode;
+ * var subscriberNumber;
+ *
+ * var nationalDestinationCodeLength =
+ *     phoneUtil.getLengthOfNationalDestinationCode(number);
+ * if (nationalDestinationCodeLength > 0) {
+ *   nationalDestinationCode =
+ *       nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
+ *   subscriberNumber =
+ *       nationalSignificantNumber.substring(nationalDestinationCodeLength);
+ * } else {
+ *   nationalDestinationCode = '';
+ *   subscriberNumber = nationalSignificantNumber;
+ * }
+ * </pre>
+ *
+ * Refer to the unittests to see the difference between this function and
+ * {@link #getLengthOfGeographicalAreaCode}.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
+ *     which clients want to know the length of the NDC.
+ * @return {number} the length of NDC of the PhoneNumber object passed in.
+ */
+- (NSUInteger)getLengthOfNationalDestinationCode:(NBPhoneNumber*)phoneNumber error:(NSError **)error
+{
+    NSUInteger res = 0;
+    
+    @try {
+        res = [self getLengthOfNationalDestinationCode:phoneNumber];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+        {
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+        }
+    }
+    
+    return res;
+}
+
+
+- (NSUInteger)getLengthOfNationalDestinationCode:(NBPhoneNumber*)phoneNumber
+{
+    NBPhoneNumber *copiedProto = nil;
+    if ([self hasValue:phoneNumber.extension])
+    {
+        copiedProto = [phoneNumber copy];
+        copiedProto.extension = nil;
+    }
+    else
+    {
+        copiedProto = phoneNumber;
+    }
+    
+    NSString *nationalSignificantNumber = [self format:copiedProto numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
+    NSMutableArray *numberGroups = [[self componentsSeparatedByRegex:nationalSignificantNumber regex:NON_DIGITS_PATTERN_] mutableCopy];
+    
+    // The pattern will start with '+COUNTRY_CODE ' so the first group will always
+    // be the empty string (before the + symbol) and the second group will be the
+    // country calling code. The third group will be area code if it is not the
+    // last group.
+    // NOTE: On IE the first group that is supposed to be the empty string does
+    // not appear in the array of number groups... so make the result on non-IE
+    // browsers to be that of IE.
+    if ([numberGroups count] > 0 && ((NSString*)[numberGroups objectAtIndex:0]).length <= 0)
+    {
+        [numberGroups removeObjectAtIndex:0];
+    }
+    
+    if ([numberGroups count] <= 2)
+    {
+        return 0;
+    }
+    
+    NSArray *regionCodes = [self regionCodeFromCountryCode:phoneNumber.countryCode];
+    BOOL isExists = NO;
+    
+    for (NSString *regCode in regionCodes)
+    {
+        if ([regCode isEqualToString:@"AR"])
+        {
+            isExists = YES;
+            break;
+        }
+    }
+    
+    if (isExists && [self getNumberType:phoneNumber] == NBEPhoneNumberTypeMOBILE)
+    {
+        // Argentinian mobile numbers, when formatted in the international format,
+        // are in the form of +54 9 NDC XXXX.... As a result, we take the length of
+        // the third group (NDC) and add 1 for the digit 9, which also forms part of
+        // the national significant number.
+        //
+        // TODO: Investigate the possibility of better modeling the metadata to make
+        // it easier to obtain the NDC.
+        return ((NSString*)[numberGroups objectAtIndex:2]).length + 1;
+    }
+    
+    return ((NSString*)[numberGroups objectAtIndex:1]).length;
+}
+
+
+/**
+ * Normalizes a string of characters representing a phone number by replacing
+ * all characters found in the accompanying map with the values therein, and
+ * stripping all other characters if removeNonMatches is NO.
+ *
+ * @param {string} number a string of characters representing a phone number.
+ * @param {!Object.<string, string>} normalizationReplacements a mapping of
+ *     characters to what they should be replaced by in the normalized version
+ *     of the phone number.
+ * @param {boolean} removeNonMatches indicates whether characters that are not
+ *     able to be replaced should be stripped from the number. If this is NO,
+ *     they will be left unchanged in the number.
+ * @return {string} the normalized string version of the phone number.
+ * @private
+ */
+- (NSString*)normalizeHelper:(NSString*)sourceString normalizationReplacements:(NSDictionary*)normalizationReplacements
+            removeNonMatches:(BOOL)removeNonMatches
+{
+    NSMutableString *normalizedNumber = [[NSMutableString alloc] init];
+    unichar character = 0;
+    NSString *newDigit = @"";
+    NSUInteger numberLength = sourceString.length;
+    
+    for (NSUInteger i = 0; i<numberLength; ++i)
+    {
+        character = [sourceString characterAtIndex:i];
+        newDigit = [normalizationReplacements objectForKey:[[NSString stringWithFormat: @"%C", character] uppercaseString]];
+        if (newDigit != nil)
+        {
+            [normalizedNumber appendString:newDigit];
+        }
+        else if (removeNonMatches == NO)
+        {
+            [normalizedNumber appendString:[NSString stringWithFormat: @"%C", character]];
+        }
+        // If neither of the above are NO, we remove this character.
+        
+        //NSLog(@"[%@]", normalizedNumber);
+    }
+    
+    return normalizedNumber;
+}
+
+
+/**
+ * Helper function to check if the national prefix formatting rule has the first
+ * group only, i.e., does not start with the national prefix.
+ *
+ * @param {string} nationalPrefixFormattingRule The formatting rule for the
+ *     national prefix.
+ * @return {boolean} NO if the national prefix formatting rule has the first
+ *     group only.
+ */
+- (BOOL)formattingRuleHasFirstGroupOnly:(NSString*)nationalPrefixFormattingRule
+{
+    BOOL hasFound = NO;
+    if ([self stringPositionByRegex:nationalPrefixFormattingRule regex:FIRST_GROUP_ONLY_PREFIX_PATTERN_] >= 0)
+    {
+        hasFound = YES;
+    }
+    
+    return (([nationalPrefixFormattingRule length] == 0) || hasFound);
+}
+
+
+/**
+ * Tests whether a phone number has a geographical association. It checks if
+ * the number is associated to a certain region in the country where it belongs
+ * to. Note that this doesn't verify if the number is actually in use.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} phoneNumber The phone number to test.
+ * @return {boolean} NO if the phone number has a geographical association.
+ * @private
+ */
+- (BOOL)isNumberGeographical:(NBPhoneNumber*)phoneNumber
+{
+    NBEPhoneNumberType numberType = [self getNumberType:phoneNumber];
+    // TODO: Include mobile phone numbers from countries like Indonesia, which
+    // has some mobile numbers that are geographical.
+    return numberType == NBEPhoneNumberTypeFIXED_LINE || numberType == NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE;
+}
+
+
+/**
+ * Helper function to check region code is not unknown or nil.
+ *
+ * @param {?string} regionCode the ISO 3166-1 two-letter region code.
+ * @return {boolean} NO if region code is valid.
+ * @private
+ */
+- (BOOL)isValidRegionCode:(NSString*)regionCode
+{
+    // In Java we check whether the regionCode is contained in supportedRegions
+    // that is built out of all the values of countryCallingCodeToRegionCodeMap
+    // (countryCodeToRegionCodeMap in JS) minus REGION_CODE_FOR_NON_GEO_ENTITY.
+    // In JS we check whether the regionCode is contained in the keys of
+    // countryToMetadata but since for non-geographical country calling codes
+    // (e.g. +800) we use the country calling codes instead of the region code as
+    // key in the map we have to make sure regionCode is not a number to prevent
+    // returning NO for non-geographical country calling codes.
+    return [self hasValue:regionCode] && [self isNaN:regionCode] && [self getMetadataForRegion:regionCode.uppercaseString] != nil;
+}
+
+
+/**
+ * Helper function to check the country calling code is valid.
+ *
+ * @param {number} countryCallingCode the country calling code.
+ * @return {boolean} NO if country calling code code is valid.
+ * @private
+ */
+- (BOOL)hasValidCountryCallingCode:(NSNumber *)countryCallingCode
+{
+    id res = [self regionCodeFromCountryCode:countryCallingCode];
+    if (res != nil)
+    {
+        return YES;
+    }
+    
+    return NO;
+}
+
+
+/**
+ * Formats a phone number in the specified format using default rules. Note that
+ * this does not promise to produce a phone number that the user can dial from
+ * where they are - although we do format in either 'national' or
+ * 'international' format depending on what the client asks for, we do not
+ * currently support a more abbreviated format, such as for users in the same
+ * 'area' who could potentially dial the number without area code. Note that if
+ * the phone number has a country calling code of 0 or an otherwise invalid
+ * country calling code, we cannot work out which formatting rules to apply so
+ * we return the national significant number with no formatting applied.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
+ *     formatted.
+ * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
+ *     phone number should be formatted into.
+ * @return {string} the formatted phone number.
+ */
+- (NSString*)format:(NBPhoneNumber*)phoneNumber numberFormat:(NBEPhoneNumberFormat)numberFormat error:(NSError**)error;
+{
+    NSString *res = nil;
+    @try {
+        res = [self format:phoneNumber numberFormat:numberFormat];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (NSString*)format:(NBPhoneNumber*)phoneNumber numberFormat:(NBEPhoneNumberFormat)numberFormat
+{
+    if ([phoneNumber.nationalNumber isEqualToNumber:@0] && [self hasValue:phoneNumber.rawInput])
+    {
+        // Unparseable numbers that kept their raw input just use that.
+        // This is the only case where a number can be formatted as E164 without a
+        // leading '+' symbol (but the original number wasn't parseable anyway).
+        // TODO: Consider removing the 'if' above so that unparseable strings
+        // without raw input format to the empty string instead of "+00"
+        /** @type {string} */
+        NSString *rawInput = phoneNumber.rawInput;
+        if ([self hasValue:rawInput]) {
+            return rawInput;
+        }
+    }
+    
+    NSNumber *countryCallingCode = phoneNumber.countryCode;
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:phoneNumber];
+    
+    if (numberFormat == NBEPhoneNumberFormatE164)
+    {
+        // Early exit for E164 case (even if the country calling code is invalid)
+        // since no formatting of the national number needs to be applied.
+        // Extensions are not formatted.
+        return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:NBEPhoneNumberFormatE164
+                                formattedNationalNumber:nationalSignificantNumber formattedExtension:@""];
+    }
+    
+    if ([self hasValidCountryCallingCode:countryCallingCode] == NO)
+    {
+        return nationalSignificantNumber;
+    }
+    
+    // Note getRegionCodeForCountryCode() is used because formatting information
+    // for regions which share a country calling code is contained by only one
+    // region for performance reasons. For example, for NANPA regions it will be
+    // contained in the metadata for US.
+    NSArray *regionCodeArray = [self regionCodeFromCountryCode:countryCallingCode];
+    NSString *regionCode = [regionCodeArray objectAtIndex:0];
+    
+    // Metadata cannot be nil because the country calling code is valid (which
+    // means that the region code cannot be ZZ and must be one of our supported
+    // region codes).
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
+    NSString *formattedExtension = [self maybeGetFormattedExtension:phoneNumber metadata:metadata numberFormat:numberFormat];
+    NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber metadata:metadata phoneNumberFormat:numberFormat carrierCode:nil];
+    
+    return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:numberFormat
+                            formattedNationalNumber:formattedNationalNumber formattedExtension:formattedExtension];
+}
+
+
+/**
+ * Formats a phone number in the specified format using client-defined
+ * formatting rules. Note that if the phone number has a country calling code of
+ * zero or an otherwise invalid country calling code, we cannot work out things
+ * like whether there should be a national prefix applied, or how to format
+ * extensions, so we return the national significant number with no formatting
+ * applied.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone  number to be
+ *     formatted.
+ * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
+ *     phone number should be formatted into.
+ * @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting
+ *     rules specified by clients.
+ * @return {string} the formatted phone number.
+ */
+- (NSString*)formatByPattern:(NBPhoneNumber*)number numberFormat:(NBEPhoneNumberFormat)numberFormat userDefinedFormats:(NSArray*)userDefinedFormats error:(NSError**)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatByPattern:number numberFormat:numberFormat userDefinedFormats:userDefinedFormats];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NSString*)formatByPattern:(NBPhoneNumber*)number numberFormat:(NBEPhoneNumberFormat)numberFormat userDefinedFormats:(NSArray*)userDefinedFormats
+{
+    NSNumber *countryCallingCode = number.countryCode;
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number];
+    
+    if ([self hasValidCountryCallingCode:countryCallingCode] == NO)
+    {
+        return nationalSignificantNumber;
+    }
+    
+    // Note getRegionCodeForCountryCode() is used because formatting information
+    // for regions which share a country calling code is contained by only one
+    // region for performance reasons. For example, for NANPA regions it will be
+    // contained in the metadata for US.
+    NSArray *regionCodes = [self regionCodeFromCountryCode:countryCallingCode];
+    NSString *regionCode = nil;
+    if (regionCodes != nil && regionCodes.count > 0)
+    {
+        regionCode = [regionCodes objectAtIndex:0];
+    }
+    
+    // Metadata cannot be nil because the country calling code is valid
+    /** @type {i18n.phonenumbers.PhoneMetadata} */
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
+    
+    NSString *formattedNumber = @"";
+    NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:userDefinedFormats nationalNumber:nationalSignificantNumber];
+    if (formattingPattern == nil)
+    {
+        // If no pattern above is matched, we format the number as a whole.
+        formattedNumber = nationalSignificantNumber;
+    }
+    else
+    {
+        // Before we do a replacement of the national prefix pattern $NP with the
+        // national prefix, we need to copy the rule so that subsequent replacements
+        // for different numbers have the appropriate national prefix.
+        NBNumberFormat *numFormatCopy = [formattingPattern copy];
+        NSString *nationalPrefixFormattingRule = formattingPattern.nationalPrefixFormattingRule;
+        
+        if (nationalPrefixFormattingRule.length > 0)
+        {
+            NSString *nationalPrefix = metadata.nationalPrefix;
+            if (nationalPrefix.length > 0)
+            {
+                // Replace $NP with national prefix and $FG with the first group ($1).
+                nationalPrefixFormattingRule = [self replaceStringByRegex:nationalPrefixFormattingRule regex:NP_PATTERN_ withTemplate:nationalPrefix];
+                nationalPrefixFormattingRule = [self replaceStringByRegex:nationalPrefixFormattingRule regex:FG_PATTERN_ withTemplate:@"\\$1"];
+                numFormatCopy.nationalPrefixFormattingRule = nationalPrefixFormattingRule;
+            }
+            else
+            {
+                // We don't want to have a rule for how to format the national prefix if
+                // there isn't one.
+                numFormatCopy.nationalPrefixFormattingRule = @"";
+            }
+        }
+        
+        formattedNumber = [self formatNsnUsingPattern:nationalSignificantNumber
+                                    formattingPattern:numFormatCopy numberFormat:numberFormat carrierCode:nil];
+    }
+    
+    NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadata numberFormat:numberFormat];
+    
+    //NSLog(@"!@#  prefixNumberWithCountryCallingCode called [%@]", formattedExtension);
+    return [self prefixNumberWithCountryCallingCode:countryCallingCode
+                                  phoneNumberFormat:numberFormat
+                            formattedNationalNumber:formattedNumber
+                                 formattedExtension:formattedExtension];
+}
+
+
+/**
+ * Formats a phone number in national format for dialing using the carrier as
+ * specified in the {@code carrierCode}. The {@code carrierCode} will always be
+ * used regardless of whether the phone number already has a preferred domestic
+ * carrier code stored. If {@code carrierCode} contains an empty string, returns
+ * the number in national format without any carrier code.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
+ *     formatted.
+ * @param {string} carrierCode the carrier selection code to be used.
+ * @return {string} the formatted phone number in national format for dialing
+ *     using the carrier as specified in the {@code carrierCode}.
+ */
+- (NSString*)formatNationalNumberWithCarrierCode:(NBPhoneNumber*)number carrierCode:(NSString*)carrierCode error:(NSError **)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatNationalNumberWithCarrierCode:number carrierCode:carrierCode];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NSString*)formatNationalNumberWithCarrierCode:(NBPhoneNumber*)number carrierCode:(NSString*)carrierCode
+{
+    NSNumber *countryCallingCode = number.countryCode;
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number];
+    if ([self hasValidCountryCallingCode:countryCallingCode] == NO)
+    {
+        return nationalSignificantNumber;
+    }
+    
+    // Note getRegionCodeForCountryCode() is used because formatting information
+    // for regions which share a country calling code is contained by only one
+    // region for performance reasons. For example, for NANPA regions it will be
+    // contained in the metadata for US.
+    NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode];
+    // Metadata cannot be nil because the country calling code is valid.
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
+    NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadata numberFormat:NBEPhoneNumberFormatNATIONAL];
+    NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber metadata:metadata phoneNumberFormat:NBEPhoneNumberFormatNATIONAL carrierCode:carrierCode];
+    return [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:NBEPhoneNumberFormatNATIONAL formattedNationalNumber:formattedNationalNumber formattedExtension:formattedExtension];
+}
+
+
+/**
+ * @param {number} countryCallingCode
+ * @param {?string} regionCode
+ * @return {i18n.phonenumbers.PhoneMetadata}
+ * @private
+ */
+- (NBPhoneMetaData*)getMetadataForRegionOrCallingCode:(NSNumber*)countryCallingCode regionCode:(NSString*)regionCode
+{
+    return [_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:regionCode] ?
+    [self getMetadataForNonGeographicalRegion:countryCallingCode] : [self getMetadataForRegion:regionCode];
+}
+
+
+/**
+ * Formats a phone number in national format for dialing using the carrier as
+ * specified in the preferred_domestic_carrier_code field of the PhoneNumber
+ * object passed in. If that is missing, use the {@code fallbackCarrierCode}
+ * passed in instead. If there is no {@code preferred_domestic_carrier_code},
+ * and the {@code fallbackCarrierCode} contains an empty string, return the
+ * number in national format without any carrier code.
+ *
+ * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier
+ * code passed in should take precedence over the number's
+ * {@code preferred_domestic_carrier_code} when formatting.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
+ *     formatted.
+ * @param {string} fallbackCarrierCode the carrier selection code to be used, if
+ *     none is found in the phone number itself.
+ * @return {string} the formatted phone number in national format for dialing
+ *     using the number's preferred_domestic_carrier_code, or the
+ *     {@code fallbackCarrierCode} passed in if none is found.
+ */
+- (NSString*)formatNationalNumberWithPreferredCarrierCode:(NBPhoneNumber*)number
+                                      fallbackCarrierCode:(NSString*)fallbackCarrierCode error:(NSError **)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatNationalNumberWithCarrierCode:number carrierCode:fallbackCarrierCode];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    
+    return res;
+}
+
+
+- (NSString*)formatNationalNumberWithPreferredCarrierCode:(NBPhoneNumber*)number fallbackCarrierCode:(NSString*)fallbackCarrierCode
+{
+    NSString *domesticCarrierCode = number.preferredDomesticCarrierCode != nil ? number.preferredDomesticCarrierCode : fallbackCarrierCode;
+    return [self formatNationalNumberWithCarrierCode:number carrierCode:domesticCarrierCode];
+}
+
+
+/**
+ * Returns a number formatted in such a way that it can be dialed from a mobile
+ * phone in a specific region. If the number cannot be reached from the region
+ * (e.g. some countries block toll-free numbers from being called outside of the
+ * country), the method returns an empty string.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
+ *     formatted.
+ * @param {string} regionCallingFrom the region where the call is being placed.
+ * @param {boolean} withFormatting whether the number should be returned with
+ *     formatting symbols, such as spaces and dashes.
+ * @return {string} the formatted phone number.
+ */
+- (NSString*)formatNumberForMobileDialing:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom withFormatting:(BOOL)withFormatting error:(NSError**)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatNumberForMobileDialing:number regionCallingFrom:regionCallingFrom withFormatting:withFormatting];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NSString*)formatNumberForMobileDialing:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom withFormatting:(BOOL)withFormatting
+{
+    NSNumber *countryCallingCode = number.countryCode;
+    if ([self hasValidCountryCallingCode:countryCallingCode] == NO)
+    {
+        return [self hasValue:number.rawInput] ? number.rawInput : @"";
+    }
+    
+    NSString *formattedNumber = @"";
+    // Clear the extension, as that part cannot normally be dialed together with
+    // the main number.
+    NBPhoneNumber *numberNoExt = [number copy];
+    numberNoExt.extension = @"";
+    
+    NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode];
+    if ([regionCallingFrom isEqualToString:regionCode])
+    {
+        NBEPhoneNumberType numberType = [self getNumberType:numberNoExt];
+        BOOL isFixedLineOrMobile = (numberType == NBEPhoneNumberTypeFIXED_LINE) || (numberType == NBEPhoneNumberTypeMOBILE) || (numberType == NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE);
+        // Carrier codes may be needed in some countries. We handle this here.
+        if ([regionCode isEqualToString:@"CO"] && numberType == NBEPhoneNumberTypeFIXED_LINE)
+        {
+            formattedNumber = [self formatNationalNumberWithCarrierCode:numberNoExt
+                                                            carrierCode:COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_];
+        }
+        else if ([regionCode isEqualToString:@"BR"] && isFixedLineOrMobile)
+        {
+            formattedNumber = [self hasValue:numberNoExt.preferredDomesticCarrierCode] ?
+            [self formatNationalNumberWithPreferredCarrierCode:numberNoExt fallbackCarrierCode:@""] : @"";
+            // Brazilian fixed line and mobile numbers need to be dialed with a
+            // carrier code when called within Brazil. Without that, most of the
+            // carriers won't connect the call. Because of that, we return an
+            // empty string here.
+        }
+        else
+        {
+            // For NANPA countries, non-geographical countries, and Mexican fixed
+            // line and mobile numbers, we output international format for numbersi
+            // that can be dialed internationally as that always works.
+            if (([countryCallingCode isEqualToNumber:@(NANPA_COUNTRY_CODE_)] ||
+                 [regionCode isEqualToString:_REGION_CODE_FOR_NON_GEO_ENTITY] ||
+                 // MX fixed line and mobile numbers should always be formatted in
+                 // international format, even when dialed within MX. For national
+                 // format to work, a carrier code needs to be used, and the correct
+                 // carrier code depends on if the caller and callee are from the
+                 // same local area. It is trickier to get that to work correctly than
+                 // using international format, which is tested to work fine on all
+                 // carriers.
+                 ([regionCode isEqualToString:@"MX"] && isFixedLineOrMobile)) && [self canBeInternationallyDialled:numberNoExt])
+            {
+                formattedNumber = [self format:numberNoExt numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
+            }
+            else
+            {
+                formattedNumber = [self format:numberNoExt numberFormat:NBEPhoneNumberFormatNATIONAL];
+            }
+        }
+    }
+    else if ([self canBeInternationallyDialled:numberNoExt])
+    {
+        return withFormatting ? [self format:numberNoExt numberFormat:NBEPhoneNumberFormatINTERNATIONAL] :
+        [self format:numberNoExt numberFormat:NBEPhoneNumberFormatE164];
+    }
+    
+    return withFormatting ?
+    formattedNumber : [self normalizeHelper:formattedNumber normalizationReplacements:self.DIALLABLE_CHAR_MAPPINGS_ removeNonMatches:YES];
+}
+
+
+/**
+ * Formats a phone number for out-of-country dialing purposes. If no
+ * regionCallingFrom is supplied, we format the number in its INTERNATIONAL
+ * format. If the country calling code is the same as that of the region where
+ * the number is from, then NATIONAL formatting will be applied.
+ *
+ * <p>If the number itself has a country calling code of zero or an otherwise
+ * invalid country calling code, then we return the number with no formatting
+ * applied.
+ *
+ * <p>Note this function takes care of the case for calling inside of NANPA and
+ * between Russia and Kazakhstan (who share the same country calling code). In
+ * those cases, no international prefix is used. For regions which have multiple
+ * international prefixes, the number in its INTERNATIONAL format will be
+ * returned instead.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
+ *     formatted.
+ * @param {string} regionCallingFrom the region where the call is being placed.
+ * @return {string} the formatted phone number.
+ */
+- (NSString*)formatOutOfCountryCallingNumber:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError**)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    
+    return res;
+}
+
+- (NSString*)formatOutOfCountryCallingNumber:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom
+{
+    if ([self isValidRegionCode:regionCallingFrom] == NO)
+    {
+        return [self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
+    }
+    
+    NSNumber *countryCallingCode = number.countryCode;
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number];
+    if ([self hasValidCountryCallingCode:countryCallingCode] == NO)
+    {
+        return nationalSignificantNumber;
+    }
+    
+    if ([countryCallingCode isEqualToNumber: @(NANPA_COUNTRY_CODE_)])
+    {
+        if ([self isNANPACountry:regionCallingFrom])
+        {
+            // For NANPA regions, return the national format for these regions but
+            // prefix it with the country calling code.
+            return [NSString stringWithFormat:@"%@ %@", countryCallingCode, [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL]];
+        }
+    }
+    else if ([countryCallingCode isEqualToNumber: [self getCountryCodeForValidRegion:regionCallingFrom]])
+    {
+        // If regions share a country calling code, the country calling code need
+        // not be dialled. This also applies when dialling within a region, so this
+        // if clause covers both these cases. Technically this is the case for
+        // dialling from La Reunion to other overseas departments of France (French
+        // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover
+        // this edge case for now and for those cases return the version including
+        // country calling code. Details here:
+        // http://www.petitfute.com/voyage/225-info-pratiques-reunion
+        return [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL];
+    }
+    // Metadata cannot be nil because we checked 'isValidRegionCode()' above.
+    NBPhoneMetaData *metadataForRegionCallingFrom = [self getMetadataForRegion:regionCallingFrom];
+    NSString *internationalPrefix = metadataForRegionCallingFrom.internationalPrefix;
+    
+    // For regions that have multiple international prefixes, the international
+    // format of the number is returned, unless there is a preferred international
+    // prefix.
+    NSString *internationalPrefixForFormatting = @"";
+    if ([self matchesEntirely:UNIQUE_INTERNATIONAL_PREFIX_ string:internationalPrefix])
+    {
+        internationalPrefixForFormatting = internationalPrefix;
+    }
+    else if ([self hasValue:metadataForRegionCallingFrom.preferredInternationalPrefix])
+    {
+        internationalPrefixForFormatting = metadataForRegionCallingFrom.preferredInternationalPrefix;
+    }
+    
+    NSString *regionCode = [self getRegionCodeForCountryCode:countryCallingCode];
+    // Metadata cannot be nil because the country calling code is valid.
+    NBPhoneMetaData *metadataForRegion = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:regionCode];
+    NSString *formattedNationalNumber = [self formatNsn:nationalSignificantNumber metadata:metadataForRegion
+                                      phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL carrierCode:nil];
+    NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadataForRegion numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
+    
+    NSString *hasLenth = [NSString stringWithFormat:@"%@ %@ %@%@", internationalPrefixForFormatting, countryCallingCode, formattedNationalNumber, formattedExtension];
+    NSString *hasNotLength = [self prefixNumberWithCountryCallingCode:countryCallingCode phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL
+                                              formattedNationalNumber:formattedNationalNumber formattedExtension:formattedExtension];
+    
+    return internationalPrefixForFormatting.length > 0 ? hasLenth:hasNotLength;
+}
+
+
+/**
+ * A helper function that is used by format and formatByPattern.
+ *
+ * @param {number} countryCallingCode the country calling code.
+ * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
+ *     phone number should be formatted into.
+ * @param {string} formattedNationalNumber
+ * @param {string} formattedExtension
+ * @return {string} the formatted phone number.
+ * @private
+ */
+- (NSString*)prefixNumberWithCountryCallingCode:(NSNumber*)countryCallingCode phoneNumberFormat:(NBEPhoneNumberFormat)numberFormat
+                        formattedNationalNumber:(NSString*)formattedNationalNumber
+                             formattedExtension:(NSString*)formattedExtension
+{
+    switch (numberFormat)
+    {
+        case NBEPhoneNumberFormatE164:
+            return [NSString stringWithFormat:@"+%@%@%@", countryCallingCode, formattedNationalNumber, formattedExtension];
+        case NBEPhoneNumberFormatINTERNATIONAL:
+            return [NSString stringWithFormat:@"+%@ %@%@", countryCallingCode, formattedNationalNumber, formattedExtension];
+        case NBEPhoneNumberFormatRFC3966:
+            return [NSString stringWithFormat:@"%@+%@-%@%@", RFC3966_PREFIX_, countryCallingCode, formattedNationalNumber, formattedExtension];
+        case NBEPhoneNumberFormatNATIONAL:
+        default:
+            return [NSString stringWithFormat:@"%@%@", formattedNationalNumber, formattedExtension];
+    }
+}
+
+
+/**
+ * Formats a phone number using the original phone number format that the number
+ * is parsed from. The original format is embedded in the country_code_source
+ * field of the PhoneNumber object passed in. If such information is missing,
+ * the number will be formatted into the NATIONAL format by default. When the
+ * number contains a leading zero and this is unexpected for this country, or we
+ * don't have a formatting pattern for the number, the method returns the raw
+ * input when it is available.
+ *
+ * Note this method guarantees no digit will be inserted, removed or modified as
+ * a result of formatting.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to
+ *     be formatted in its original number format.
+ * @param {string} regionCallingFrom the region whose IDD needs to be prefixed
+ *     if the original number has one.
+ * @return {string} the formatted phone number in its original number format.
+ */
+- (NSString*)formatInOriginalFormat:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError **)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatInOriginalFormat:number regionCallingFrom:regionCallingFrom];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    
+    return res;
+}
+
+
+- (NSString*)formatInOriginalFormat:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom
+{
+    if ([self hasValue:number.rawInput] && ([self hasUnexpectedItalianLeadingZero:number] || [self hasFormattingPatternForNumber:number] == NO))
+    {
+        // We check if we have the formatting pattern because without that, we might
+        // format the number as a group without national prefix.
+        return number.rawInput;
+    }
+    
+    if (number.countryCodeSource == nil)
+    {
+        return [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL];
+    }
+    
+    NSString *formattedNumber = @"";
+    
+    switch ([number.countryCodeSource intValue])
+    {
+        case NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN:
+            formattedNumber = [self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
+            break;
+        case NBECountryCodeSourceFROM_NUMBER_WITH_IDD:
+            formattedNumber = [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom];
+            break;
+        case NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN:
+            formattedNumber = [[self format:number numberFormat:NBEPhoneNumberFormatINTERNATIONAL] substringFromIndex:1];
+            break;
+        case NBECountryCodeSourceFROM_DEFAULT_COUNTRY:
+            // Fall-through to default case.
+        default:
+        {
+            NSString *regionCode = [self getRegionCodeForCountryCode:number.countryCode];
+            // We strip non-digits from the NDD here, and from the raw input later,
+            // so that we can compare them easily.
+            NSString *nationalPrefix = [self getNddPrefixForRegion:regionCode stripNonDigits:YES];
+            NSString *nationalFormat = [self format:number numberFormat:NBEPhoneNumberFormatNATIONAL];
+            if (nationalPrefix == nil || nationalPrefix.length == 0)
+            {
+                // If the region doesn't have a national prefix at all, we can safely
+                // return the national format without worrying about a national prefix
+                // being added.
+                formattedNumber = nationalFormat;
+                break;
+            }
+            // Otherwise, we check if the original number was entered with a national
+            // prefix.
+            if ([self rawInputContainsNationalPrefix:number.rawInput nationalPrefix:nationalPrefix regionCode:regionCode])
+            {
+                // If so, we can safely return the national format.
+                formattedNumber = nationalFormat;
+                break;
+            }
+            // Metadata cannot be nil here because getNddPrefixForRegion() (above)
+            // returns nil if there is no metadata for the region.
+            NBPhoneMetaData *metadata = [self getMetadataForRegion:regionCode];
+            NSString *nationalNumber = [self getNationalSignificantNumber:number];
+            NBNumberFormat *formatRule = [self chooseFormattingPatternForNumber:metadata.numberFormats nationalNumber:nationalNumber];
+            // The format rule could still be nil here if the national number was 0
+            // and there was no raw input (this should not be possible for numbers
+            // generated by the phonenumber library as they would also not have a
+            // country calling code and we would have exited earlier).
+            if (formatRule == nil)
+            {
+                formattedNumber = nationalFormat;
+                break;
+            }
+            // When the format we apply to this number doesn't contain national
+            // prefix, we can just return the national format.
+            // TODO: Refactor the code below with the code in
+            // isNationalPrefixPresentIfRequired.
+            NSString *candidateNationalPrefixRule = formatRule.nationalPrefixFormattingRule;
+            // We assume that the first-group symbol will never be _before_ the
+            // national prefix.
+            NSRange firstGroupRange = [candidateNationalPrefixRule rangeOfString:@"$1"];
+            if (firstGroupRange.location == NSNotFound)
+            {
+                formattedNumber = nationalFormat;
+                break;
+            }
+            
+            if (firstGroupRange.location <= 0)
+            {
+                formattedNumber = nationalFormat;
+                break;
+            }
+            candidateNationalPrefixRule = [candidateNationalPrefixRule substringWithRange:NSMakeRange(0, firstGroupRange.location)];
+            candidateNationalPrefixRule = [self normalizeDigitsOnly:candidateNationalPrefixRule];
+            if (candidateNationalPrefixRule.length == 0)
+            {
+                // National prefix not used when formatting this number.
+                formattedNumber = nationalFormat;
+                break;
+            }
+            // Otherwise, we need to remove the national prefix from our output.
+            NBNumberFormat *numFormatCopy = [formatRule copy];
+            numFormatCopy.nationalPrefixFormattingRule = nil;
+            formattedNumber = [self formatByPattern:number numberFormat:NBEPhoneNumberFormatNATIONAL userDefinedFormats:@[numFormatCopy]];
+            break;
+        }
+    }
+    
+    NSString *rawInput = number.rawInput;
+    // If no digit is inserted/removed/modified as a result of our formatting, we
+    // return the formatted phone number; otherwise we return the raw input the
+    // user entered.
+    if (formattedNumber != nil && rawInput.length > 0)
+    {
+        NSString *normalizedFormattedNumber = [self normalizeHelper:formattedNumber normalizationReplacements:_DIALLABLE_CHAR_MAPPINGS_ removeNonMatches:YES];
+        /** @type {string} */
+        NSString *normalizedRawInput =[self normalizeHelper:rawInput normalizationReplacements:_DIALLABLE_CHAR_MAPPINGS_ removeNonMatches:YES];
+        
+        if ([normalizedFormattedNumber isEqualToString:normalizedRawInput] == NO)
+        {
+            formattedNumber = rawInput;
+        }
+    }
+    return formattedNumber;
+}
+
+
+/**
+ * Check if rawInput, which is assumed to be in the national format, has a
+ * national prefix. The national prefix is assumed to be in digits-only form.
+ * @param {string} rawInput
+ * @param {string} nationalPrefix
+ * @param {string} regionCode
+ * @return {boolean}
+ * @private
+ */
+- (BOOL)rawInputContainsNationalPrefix:(NSString*)rawInput nationalPrefix:(NSString*)nationalPrefix regionCode:(NSString*)regionCode
+{
+    NSString *normalizedNationalNumber = [self normalizeDigitsOnly:rawInput];
+    if ([self isStartingStringByRegex:normalizedNationalNumber regex:nationalPrefix])
+    {
+        @try {
+            // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the
+            // national prefix when written without it (e.g. 0777123) if we just do
+            // prefix matching. To tackle that, we check the validity of the number if
+            // the assumed national prefix is removed (777123 won't be valid in
+            // Japan).
+            NSString *subString = [normalizedNationalNumber substringFromIndex:nationalPrefix.length];
+            return [self isValidNumber:[self parse:subString defaultRegion:regionCode]];
+        }
+        @catch (NSException *ex) {
+            return NO;
+        }
+    }
+    return NO;
+}
+
+
+/**
+ * Returns NO if a number is from a region whose national significant number
+ * couldn't contain a leading zero, but has the italian_leading_zero field set
+ * to NO.
+ * @param {i18n.phonenumbers.PhoneNumber} number
+ * @return {boolean}
+ * @private
+ */
+- (BOOL)hasUnexpectedItalianLeadingZero:(NBPhoneNumber*)number
+{
+    return number.italianLeadingZero && [self isLeadingZeroPossible:number.countryCode] == NO;
+}
+
+
+/**
+ * @param {i18n.phonenumbers.PhoneNumber} number
+ * @return {boolean}
+ * @private
+ */
+- (BOOL)hasFormattingPatternForNumber:(NBPhoneNumber*)number
+{
+    NSNumber *countryCallingCode = number.countryCode;
+    NSString *phoneNumberRegion = [self getRegionCodeForCountryCode:countryCallingCode];
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCallingCode regionCode:phoneNumberRegion];
+    
+    if (metadata == nil)
+    {
+        return NO;
+    }
+    
+    NSString *nationalNumber = [self getNationalSignificantNumber:number];
+    NBNumberFormat *formatRule = [self chooseFormattingPatternForNumber:metadata.numberFormats nationalNumber:nationalNumber];
+    return formatRule != nil;
+}
+
+
+/**
+ * Formats a phone number for out-of-country dialing purposes.
+ *
+ * Note that in this version, if the number was entered originally using alpha
+ * characters and this version of the number is stored in raw_input, this
+ * representation of the number will be used rather than the digit
+ * representation. Grouping information, as specified by characters such as '-'
+ * and ' ', will be retained.
+ *
+ * <p><b>Caveats:</b></p>
+ * <ul>
+ * <li>This will not produce good results if the country calling code is both
+ * present in the raw input _and_ is the start of the national number. This is
+ * not a problem in the regions which typically use alpha numbers.
+ * <li>This will also not produce good results if the raw input has any grouping
+ * information within the first three digits of the national number, and if the
+ * function needs to strip preceding digits/words in the raw input before these
+ * digits. Normally people group the first three digits together so this is not
+ * a huge problem - and will be fixed if it proves to be so.
+ * </ul>
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to
+ *     be formatted.
+ * @param {string} regionCallingFrom the region where the call is being placed.
+ * @return {string} the formatted phone number.
+ */
+- (NSString*)formatOutOfCountryKeepingAlphaChars:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom error:(NSError **)error
+{
+    NSString *res = nil;
+    @try {
+        res = [self formatOutOfCountryKeepingAlphaChars:number regionCallingFrom:regionCallingFrom];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NSString*)formatOutOfCountryKeepingAlphaChars:(NBPhoneNumber*)number regionCallingFrom:(NSString*)regionCallingFrom
+{
+    NSString *rawInput = number.rawInput;
+    // If there is no raw input, then we can't keep alpha characters because there
+    // aren't any. In this case, we return formatOutOfCountryCallingNumber.
+    if (rawInput == nil || rawInput.length == 0)
+    {
+        return [self formatOutOfCountryCallingNumber:number regionCallingFrom:regionCallingFrom];
+    }
+    
+    NSNumber *countryCode = number.countryCode;
+    if ([self hasValidCountryCallingCode:countryCode] == NO)
+    {
+        return rawInput;
+    }
+    // Strip any prefix such as country calling code, IDD, that was present. We do
+    // this by comparing the number in raw_input with the parsed number. To do
+    // this, first we normalize punctuation. We retain number grouping symbols
+    // such as ' ' only.
+    rawInput = [self normalizeHelper:rawInput normalizationReplacements:_ALL_PLUS_NUMBER_GROUPING_SYMBOLS_ removeNonMatches:NO];
+    //NSLog(@"---- formatOutOfCountryKeepingAlphaChars normalizeHelper rawInput [%@]", rawInput);
+    // Now we trim everything before the first three digits in the parsed number.
+    // We choose three because all valid alpha numbers have 3 digits at the start
+    // - if it does not, then we don't trim anything at all. Similarly, if the
+    // national number was less than three digits, we don't trim anything at all.
+    NSString *nationalNumber = [self getNationalSignificantNumber:number];
+    if (nationalNumber.length > 3)
+    {
+        NSInteger firstNationalNumberDigit = [self indexOfStringByString:rawInput target:[nationalNumber substringWithRange:NSMakeRange(0, 3)]];
+        if (firstNationalNumberDigit != -1)
+        {
+            rawInput = [rawInput substringFromIndex:firstNationalNumberDigit];
+        }
+    }
+    
+    NBPhoneMetaData *metadataForRegionCallingFrom = [self getMetadataForRegion:regionCallingFrom];
+    if ([countryCode isEqualToNumber: @(NANPA_COUNTRY_CODE_)])
+    {
+        if ([self isNANPACountry:regionCallingFrom])
+        {
+            return [NSString stringWithFormat:@"%@ %@", countryCode, rawInput];
+        }
+    }
+    else if (metadataForRegionCallingFrom != nil && [countryCode isEqualToNumber: [self getCountryCodeForValidRegion:regionCallingFrom]])
+    {
+        NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:metadataForRegionCallingFrom.numberFormats
+                                                                    nationalNumber:nationalNumber];
+        if (formattingPattern == nil)
+        {
+            // If no pattern above is matched, we format the original input.
+            return rawInput;
+        }
+        
+        NBNumberFormat *newFormat = [formattingPattern copy];
+        // The first group is the first group of digits that the user wrote
+        // together.
+        newFormat.pattern = @"(\\d+)(.*)";
+        // Here we just concatenate them back together after the national prefix
+        // has been fixed.
+        newFormat.format = @"$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 [self formatNsnUsingPattern:rawInput formattingPattern:newFormat numberFormat:NBEPhoneNumberFormatNATIONAL carrierCode:nil];
+    }
+    
+    NSString *internationalPrefixForFormatting = @"";
+    // If an unsupported region-calling-from is entered, or a country with
+    // multiple international prefixes, the international format of the number is
+    // returned, unless there is a preferred international prefix.
+    if (metadataForRegionCallingFrom != nil)
+    {
+        NSString *internationalPrefix = metadataForRegionCallingFrom.internationalPrefix;
+        internationalPrefixForFormatting =
+        [self matchesEntirely:UNIQUE_INTERNATIONAL_PREFIX_ string:internationalPrefix] ? internationalPrefix : metadataForRegionCallingFrom.preferredInternationalPrefix;
+    }
+    
+    NSString *regionCode = [self getRegionCodeForCountryCode:countryCode];
+    // Metadata cannot be nil because the country calling code is valid.
+    NBPhoneMetaData *metadataForRegion = [self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode];
+    NSString *formattedExtension = [self maybeGetFormattedExtension:number metadata:metadataForRegion numberFormat:NBEPhoneNumberFormatINTERNATIONAL];
+    if (internationalPrefixForFormatting.length > 0)
+    {
+        return [NSString stringWithFormat:@"%@ %@ %@%@", internationalPrefixForFormatting, countryCode, rawInput, formattedExtension];
+    }
+    else
+    {
+        // Invalid region entered as country-calling-from (so no metadata was found
+        // for it) or the region chosen has multiple international dialling
+        // prefixes.
+        return [self prefixNumberWithCountryCallingCode:countryCode phoneNumberFormat:NBEPhoneNumberFormatINTERNATIONAL formattedNationalNumber:rawInput formattedExtension:formattedExtension];
+    }
+}
+
+
+/**
+ * Note in some regions, the national number can be written in two completely
+ * different ways depending on whether it forms part of the NATIONAL format or
+ * INTERNATIONAL format. The numberFormat parameter here is used to specify
+ * which format to use for those cases. If a carrierCode is specified, this will
+ * be inserted into the formatted string to replace $CC.
+ *
+ * @param {string} number a string of characters representing a phone number.
+ * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
+ *     region that we think this number is from.
+ * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
+ *     phone number should be formatted into.
+ * @param {string=} opt_carrierCode
+ * @return {string} the formatted phone number.
+ * @private
+ */
+- (NSString*)formatNsn:(NSString*)phoneNumber metadata:(NBPhoneMetaData*)metadata phoneNumberFormat:(NBEPhoneNumberFormat)numberFormat carrierCode:(NSString*)opt_carrierCode
+{
+    NSMutableArray *intlNumberFormats = metadata.intlNumberFormats;
+    // When the intlNumberFormats exists, we use that to format national number
+    // for the INTERNATIONAL format instead of using the numberDesc.numberFormats.
+    NSArray *availableFormats = ([intlNumberFormats count] <= 0 || numberFormat == NBEPhoneNumberFormatNATIONAL) ? metadata.numberFormats : intlNumberFormats;
+    NBNumberFormat *formattingPattern = [self chooseFormattingPatternForNumber:availableFormats nationalNumber:phoneNumber];
+    
+    if (formattingPattern == nil)
+    {
+        return phoneNumber;
+    }
+    
+    return [self formatNsnUsingPattern:phoneNumber formattingPattern:formattingPattern numberFormat:numberFormat carrierCode:opt_carrierCode];
+}
+
+
+/**
+ * @param {Array.<i18n.phonenumbers.NumberFormat>} availableFormats the
+ *     available formats the phone number could be formatted into.
+ * @param {string} nationalNumber a string of characters representing a phone
+ *     number.
+ * @return {i18n.phonenumbers.NumberFormat}
+ * @private
+ */
+- (NBNumberFormat*)chooseFormattingPatternForNumber:(NSArray*)availableFormats nationalNumber:(NSString*)nationalNumber
+{
+    for (NBNumberFormat *numFormat in availableFormats)
+    {
+        NSUInteger size = [numFormat.leadingDigitsPatterns count];
+        // We always use the last leading_digits_pattern, as it is the most detailed.
+        if (size == 0 || [self stringPositionByRegex:nationalNumber regex:[numFormat.leadingDigitsPatterns lastObject]] == 0)
+        {
+            if ([self matchesEntirely:numFormat.pattern string:nationalNumber])
+            {
+                return numFormat;
+            }
+        }
+    }
+    
+    return nil;
+}
+
+
+/**
+ * Note that carrierCode is optional - if nil or an empty string, no carrier
+ * code replacement will take place.
+ *
+ * @param {string} nationalNumber a string of characters representing a phone
+ *     number.
+ * @param {i18n.phonenumbers.NumberFormat} formattingPattern the formatting rule
+ *     the phone number should be formatted into.
+ * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
+ *     phone number should be formatted into.
+ * @param {string=} opt_carrierCode
+ * @return {string} the formatted phone number.
+ * @private
+ */
+- (NSString*)formatNsnUsingPattern:(NSString*)nationalNumber formattingPattern:(NBNumberFormat*)formattingPattern numberFormat:(NBEPhoneNumberFormat)numberFormat carrierCode:(NSString*)opt_carrierCode
+{
+    NSString *numberFormatRule = formattingPattern.format;
+    NSString *domesticCarrierCodeFormattingRule = formattingPattern.domesticCarrierCodeFormattingRule;
+    NSString *formattedNationalNumber = @"";
+    
+    if (numberFormat == NBEPhoneNumberFormatNATIONAL && [self hasValue:opt_carrierCode] && domesticCarrierCodeFormattingRule.length > 0)
+    {
+        // Replace the $CC in the formatting rule with the desired carrier code.
+        NSString *carrierCodeFormattingRule = [self replaceStringByRegex:domesticCarrierCodeFormattingRule regex:CC_PATTERN_ withTemplate:opt_carrierCode];
+        // Now replace the $FG in the formatting rule with the first group and
+        // the carrier code combined in the appropriate way.
+        numberFormatRule = [self replaceFirstStringByRegex:numberFormatRule regex:FIRST_GROUP_PATTERN_
+                                              withTemplate:carrierCodeFormattingRule];
+        formattedNationalNumber = [self replaceStringByRegex:nationalNumber regex:formattingPattern.pattern withTemplate:numberFormatRule];
+    }
+    else
+    {
+        // Use the national prefix formatting rule instead.
+        NSString *nationalPrefixFormattingRule = formattingPattern.nationalPrefixFormattingRule;
+        if (numberFormat == NBEPhoneNumberFormatNATIONAL && [self hasValue:nationalPrefixFormattingRule])
+        {
+            NSString *replacePattern = [self replaceFirstStringByRegex:numberFormatRule regex:FIRST_GROUP_PATTERN_ withTemplate:nationalPrefixFormattingRule];
+            formattedNationalNumber = [self replaceStringByRegex:nationalNumber regex:formattingPattern.pattern withTemplate:replacePattern];
+        }
+        else
+        {
+            formattedNationalNumber = [self replaceStringByRegex:nationalNumber regex:formattingPattern.pattern withTemplate:numberFormatRule];
+        }
+    }
+    
+    if (numberFormat == NBEPhoneNumberFormatRFC3966)
+    {
+        // Strip any leading punctuation.
+        formattedNationalNumber = [self replaceStringByRegex:formattedNationalNumber regex:[NSString stringWithFormat:@"^%@", self.SEPARATOR_PATTERN_] withTemplate:@""];
+        
+        // Replace the rest with a dash between each number group.
+        formattedNationalNumber = [self replaceStringByRegex:formattedNationalNumber regex:self.SEPARATOR_PATTERN_ withTemplate:@"-"];
+    }
+    return formattedNationalNumber;
+}
+
+
+/**
+ * Gets a valid number for the specified region.
+ *
+ * @param {string} regionCode the region for which an example number is needed.
+ * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the
+ *     specified region. Returns nil when the metadata does not contain such
+ *     information, or the region 001 is passed in. For 001 (representing non-
+ *     geographical numbers), call {@link #getExampleNumberForNonGeoEntity}
+ *     instead.
+ */
+- (NBPhoneNumber*)getExampleNumber:(NSString*)regionCode error:(NSError *__autoreleasing *)error
+{
+    NBPhoneNumber *res = nil;
+    @try {
+        res = [self getExampleNumber:regionCode];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NBPhoneNumber*)getExampleNumber:(NSString*)regionCode
+{
+    return [self getExampleNumberForType:regionCode type:NBEPhoneNumberTypeFIXED_LINE];
+}
+
+
+/**
+ * Gets a valid number for the specified region and number type.
+ *
+ * @param {string} regionCode the region for which an example number is needed.
+ * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is
+ *     needed.
+ * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified
+ *     region and type. Returns nil when the metadata does not contain such
+ *     information or if an invalid region or region 001 was entered.
+ *     For 001 (representing non-geographical numbers), call
+ *     {@link #getExampleNumberForNonGeoEntity} instead.
+ */
+- (NBPhoneNumber*)getExampleNumberForType:(NSString*)regionCode type:(NBEPhoneNumberType)type error:(NSError *__autoreleasing *)error
+{
+    NBPhoneNumber *res = nil;
+    @try {
+        res = [self getExampleNumberForType:regionCode type:type];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NBPhoneNumber*)getExampleNumberForType:(NSString*)regionCode type:(NBEPhoneNumberType)type
+{
+    // Check the region code is valid.
+    if ([self isValidRegionCode:regionCode] == NO)
+    {
+        return nil;
+    }
+    
+    NBPhoneNumberDesc *desc = [self getNumberDescByType:[self getMetadataForRegion:regionCode] type:type];
+    
+    @try {
+        if ([self hasValue:desc.exampleNumber ])
+        {
+            return [self parse:desc.exampleNumber defaultRegion:regionCode];
+        }
+    }
+    @catch (NSException *e)
+    {
+    }
+    
+    return nil;
+}
+
+
+/**
+ * Gets a valid number for the specified country calling code for a
+ * non-geographical entity.
+ *
+ * @param {number} countryCallingCode the country calling code for a
+ *     non-geographical entity.
+ * @return {i18n.phonenumbers.PhoneNumber} a valid number for the
+ *     non-geographical entity. Returns nil when the metadata does not contain
+ *     such information, or the country calling code passed in does not belong
+ *     to a non-geographical entity.
+ */
+- (NBPhoneNumber*)getExampleNumberForNonGeoEntity:(NSNumber*)countryCallingCode error:(NSError *__autoreleasing *)error
+{
+    NBPhoneNumber *res = nil;
+    @try {
+        res = [self getExampleNumberForNonGeoEntity:countryCallingCode];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (NBPhoneNumber*)getExampleNumberForNonGeoEntity:(NSNumber*)countryCallingCode
+{
+    NBPhoneMetaData *metadata = [self getMetadataForNonGeographicalRegion:countryCallingCode];
+    
+    if (metadata != nil)
+    {
+        NBPhoneNumberDesc *desc = metadata.generalDesc;
+        @try {
+            if ([self hasValue:desc.exampleNumber])
+            {
+                NSString *callCode = [NSString stringWithFormat:@"+%@%@", countryCallingCode, desc.exampleNumber];
+                return [self parse:callCode defaultRegion:UNKNOWN_REGION_];
+            }
+        }
+        @catch (NSException *e) {
+        }
+    }
+    return nil;
+}
+
+
+/**
+ * Gets the formatted extension of a phone number, if the phone number had an
+ * extension specified. If not, it returns an empty string.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have
+ *     an extension.
+ * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
+ *     region that we think this number is from.
+ * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
+ *     phone number should be formatted into.
+ * @return {string} the formatted extension if any.
+ * @private
+ */
+- (NSString*)maybeGetFormattedExtension:(NBPhoneNumber*)number metadata:(NBPhoneMetaData*)metadata numberFormat:(NBEPhoneNumberFormat)numberFormat
+{
+    if ([self hasValue:number.extension] == NO)
+    {
+        return @"";
+    }
+    else
+    {
+        if (numberFormat == NBEPhoneNumberFormatRFC3966)
+        {
+            return [NSString stringWithFormat:@"%@%@", RFC3966_EXTN_PREFIX_, number.extension];
+        }
+        else
+        {
+            if ([self hasValue:metadata.preferredExtnPrefix])
+            {
+                return [NSString stringWithFormat:@"%@%@", metadata.preferredExtnPrefix, number.extension];
+            }
+            else
+            {
+                return [NSString stringWithFormat:@"%@%@", DEFAULT_EXTN_PREFIX_, number.extension];
+            }
+        }
+    }
+}
+
+
+/**
+ * @param {i18n.phonenumbers.PhoneMetadata} metadata
+ * @param {i18n.phonenumbers.PhoneNumberType} type
+ * @return {i18n.phonenumbers.PhoneNumberDesc}
+ * @private
+ */
+- (NBPhoneNumberDesc*)getNumberDescByType:(NBPhoneMetaData*)metadata type:(NBEPhoneNumberType)type
+{
+    switch (type)
+    {
+        case NBEPhoneNumberTypePREMIUM_RATE:
+            return metadata.premiumRate;
+        case NBEPhoneNumberTypeTOLL_FREE:
+            return metadata.tollFree;
+        case NBEPhoneNumberTypeMOBILE:
+            if (metadata.mobile == nil) return metadata.generalDesc;
+            return metadata.mobile;
+        case NBEPhoneNumberTypeFIXED_LINE:
+        case NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE:
+            if (metadata.fixedLine == nil) return metadata.generalDesc;
+            return metadata.fixedLine;
+        case NBEPhoneNumberTypeSHARED_COST:
+            return metadata.sharedCost;
+        case NBEPhoneNumberTypeVOIP:
+            return metadata.voip;
+        case NBEPhoneNumberTypePERSONAL_NUMBER:
+            return metadata.personalNumber;
+        case NBEPhoneNumberTypePAGER:
+            return metadata.pager;
+        case NBEPhoneNumberTypeUAN:
+            return metadata.uan;
+        case NBEPhoneNumberTypeVOICEMAIL:
+            return metadata.voicemail;
+        default:
+            return metadata.generalDesc;
+    }
+}
+
+/**
+ * Gets the type of a phone number.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
+ *     to know the type.
+ * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number.
+ */
+- (NBEPhoneNumberType)getNumberType:(NBPhoneNumber*)phoneNumber
+{
+    NSString *regionCode = [self getRegionCodeForNumber:phoneNumber];
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:phoneNumber.countryCode regionCode:regionCode];
+    if (metadata == nil)
+    {
+        return NBEPhoneNumberTypeUNKNOWN;
+    }
+    
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:phoneNumber];
+    return [self getNumberTypeHelper:nationalSignificantNumber metadata:metadata];
+}
+
+
+/**
+ * @param {string} nationalNumber
+ * @param {i18n.phonenumbers.PhoneMetadata} metadata
+ * @return {i18n.phonenumbers.PhoneNumberType}
+ * @private
+ */
+- (NBEPhoneNumberType)getNumberTypeHelper:(NSString*)nationalNumber metadata:(NBPhoneMetaData*)metadata
+{
+    NBPhoneNumberDesc *generalNumberDesc = metadata.generalDesc;
+    
+    //NSLog(@"getNumberTypeHelper - UNKNOWN 1");
+    if ([self hasValue:generalNumberDesc.nationalNumberPattern] == NO ||
+        [self isNumberMatchingDesc:nationalNumber numberDesc:generalNumberDesc] == NO)
+    {
+        //NSLog(@"getNumberTypeHelper - UNKNOWN 2");
+        return NBEPhoneNumberTypeUNKNOWN;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - PREMIUM_RATE 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.premiumRate])
+    {
+        //NSLog(@"getNumberTypeHelper - PREMIUM_RATE 2");
+        return NBEPhoneNumberTypePREMIUM_RATE;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - TOLL_FREE 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.tollFree])
+    {
+        //NSLog(@"getNumberTypeHelper - TOLL_FREE 2");
+        return NBEPhoneNumberTypeTOLL_FREE;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - SHARED_COST 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.sharedCost])
+    {
+        //NSLog(@"getNumberTypeHelper - SHARED_COST 2");
+        return NBEPhoneNumberTypeSHARED_COST;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - VOIP 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.voip])
+    {
+        //NSLog(@"getNumberTypeHelper - VOIP 2");
+        return NBEPhoneNumberTypeVOIP;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - PERSONAL_NUMBER 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.personalNumber])
+    {
+        //NSLog(@"getNumberTypeHelper - PERSONAL_NUMBER 2");
+        return NBEPhoneNumberTypePERSONAL_NUMBER;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - PAGER 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.pager])
+    {
+        //NSLog(@"getNumberTypeHelper - PAGER 2");
+        return NBEPhoneNumberTypePAGER;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - UAN 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.uan])
+    {
+        //NSLog(@"getNumberTypeHelper - UAN 2");
+        return NBEPhoneNumberTypeUAN;
+    }
+    
+    //NSLog(@"getNumberTypeHelper - VOICEMAIL 1");
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.voicemail])
+    {
+        //NSLog(@"getNumberTypeHelper - VOICEMAIL 2");
+        return NBEPhoneNumberTypeVOICEMAIL;
+    }
+    
+    if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.fixedLine])
+    {
+        if (metadata.sameMobileAndFixedLinePattern)
+        {
+            //NSLog(@"getNumberTypeHelper - FIXED_LINE_OR_MOBILE");
+            return NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE;
+        }
+        else if ([self isNumberMatchingDesc:nationalNumber numberDesc:metadata.mobile])
+        {
+            //NSLog(@"getNumberTypeHelper - FIXED_LINE_OR_MOBILE");
+            return NBEPhoneNumberTypeFIXED_LINE_OR_MOBILE;
+        }
+        //NSLog(@"getNumberTypeHelper - FIXED_LINE");
+        return NBEPhoneNumberTypeFIXED_LINE;
+    }
+    
+    // Otherwise, test to see if the number is mobile. Only do this if certain
+    // that the patterns for mobile and fixed line aren't the same.
+    if ([metadata sameMobileAndFixedLinePattern] == NO && [self isNumberMatchingDesc:nationalNumber numberDesc:metadata.mobile])
+    {
+        return NBEPhoneNumberTypeMOBILE;
+    }
+    
+    return NBEPhoneNumberTypeUNKNOWN;
+}
+
+
+/**
+ * Returns the metadata for the given region code or {@code nil} if the region
+ * code is invalid or unknown.
+ *
+ * @param {?string} regionCode
+ * @return {i18n.phonenumbers.PhoneMetadata}
+ */
+- (NBPhoneMetaData*)getMetadataForRegion:(NSString*)regionCode
+{
+    if ([self hasValue:regionCode] == NO)
+    {
+        return nil;
+    }
+    
+    regionCode = [regionCode uppercaseString];
+    
+    NBPhoneMetaData *metadata = [self.coreMetaData objectForKey:regionCode];
+    
+    return metadata;
+}
+
+
+/**
+ * @param {number} countryCallingCode
+ * @return {i18n.phonenumbers.PhoneMetadata}
+ */
+- (NBPhoneMetaData*)getMetadataForNonGeographicalRegion:(NSNumber*)countryCallingCode
+{
+    NSString *countryCallingCodeStr = [NSString stringWithFormat:@"%@", countryCallingCode];
+    return [self getMetadataForRegion:countryCallingCodeStr];
+}
+
+
+/**
+ * @param {string} nationalNumber
+ * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc
+ * @return {boolean}
+ * @private
+ */
+- (BOOL)isNumberMatchingDesc:(NSString*)nationalNumber numberDesc:(NBPhoneNumberDesc*)numberDesc
+{
+    if (numberDesc == nil)
+        return NO;
+    
+    if ([self hasValue:numberDesc.possibleNumberPattern] == NO || [numberDesc.possibleNumberPattern isEqual:@"NA"])
+        return [self matchesEntirely:numberDesc.nationalNumberPattern string:nationalNumber];
+    
+    if ([self hasValue:numberDesc.nationalNumberPattern] == NO || [numberDesc.nationalNumberPattern isEqual:@"NA"])
+        return [self matchesEntirely:numberDesc.possibleNumberPattern string:nationalNumber];
+    
+    return [self matchesEntirely:numberDesc.possibleNumberPattern string:nationalNumber] &&
+    [self matchesEntirely:numberDesc.nationalNumberPattern string:nationalNumber];
+}
+
+
+/**
+ * Tests whether a phone number matches a valid pattern. Note this doesn't
+ * verify the number is actually in use, which is impossible to tell by just
+ * looking at a number itself.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
+ *     to validate.
+ * @return {boolean} a boolean that indicates whether the number is of a valid
+ *     pattern.
+ */
+- (BOOL)isValidNumber:(NBPhoneNumber*)number
+{
+    NSString *regionCode = [self getRegionCodeForNumber:number];
+    return [self isValidNumberForRegion:number regionCode:regionCode];
+}
+
+
+/**
+ * Tests whether a phone number is valid for a certain region. Note this doesn't
+ * verify the number is actually in use, which is impossible to tell by just
+ * looking at a number itself. If the country calling code is not the same as
+ * the country calling code for the region, this immediately exits with NO.
+ * After this, the specific number pattern rules for the region are examined.
+ * This is useful for determining for example whether a particular number is
+ * valid for Canada, rather than just a valid NANPA number.
+ * Warning: In most cases, you want to use {@link #isValidNumber} instead. For
+ * example, this method will mark numbers from British Crown dependencies such
+ * as the Isle of Man as invalid for the region "GB" (United Kingdom), since it
+ * has its own region code, "IM", which may be undesirable.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
+ *     to validate.
+ * @param {?string} regionCode the region that we want to validate the phone
+ *     number for.
+ * @return {boolean} a boolean that indicates whether the number is of a valid
+ *     pattern.
+ */
+- (BOOL)isValidNumberForRegion:(NBPhoneNumber*)number regionCode:(NSString*)regionCode
+{
+    NSNumber *countryCode = number.countryCode;
+
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode];
+    if (metadata == nil ||
+        ([_REGION_CODE_FOR_NON_GEO_ENTITY isEqualToString:regionCode] == NO &&
+         ![countryCode isEqualToNumber: [self 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 NO;
+    }
+    
+    NBPhoneNumberDesc *generalNumDesc = metadata.generalDesc;
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number];
+    
+    // For regions where we don't have metadata for PhoneNumberDesc, we treat any
+    // number passed in as a valid number if its national significant number is
+    // between the minimum and maximum lengths defined by ITU for a national
+    // significant number.
+    if ([self hasValue:generalNumDesc.nationalNumberPattern] == NO)
+    {
+        NSUInteger numberLength = nationalSignificantNumber.length;
+        return numberLength > MIN_LENGTH_FOR_NSN_ && numberLength <= MAX_LENGTH_FOR_NSN_;
+    }
+    
+    return [self getNumberTypeHelper:nationalSignificantNumber metadata:metadata] != NBEPhoneNumberTypeUNKNOWN;
+}
+
+
+/**
+ * Returns the region where a phone number is from. This could be used for
+ * geocoding at the region level.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone number whose origin
+ *     we want to know.
+ * @return {?string} the region where the phone number is from, or nil
+ *     if no region matches this calling code.
+ */
+- (NSString*)getRegionCodeForNumber:(NBPhoneNumber*)phoneNumber
+{
+    if (phoneNumber == nil)
+    {
+        return nil;
+    }
+    
+    NSArray *regionCodes = [self regionCodeFromCountryCode:phoneNumber.countryCode];
+    if (regionCodes == nil || [regionCodes count] <= 0)
+    {
+        return nil;
+    }
+    
+    if ([regionCodes count] == 1)
+    {
+        return [regionCodes objectAtIndex:0];
+    }
+    else
+    {
+        return [self getRegionCodeForNumberFromRegionList:phoneNumber regionCodes:regionCodes];
+    }
+}
+
+
+/**
+ * @param {i18n.phonenumbers.PhoneNumber} number
+ * @param {Array.<string>} regionCodes
+ * @return {?string}
+ * @private
+ 
+ */
+- (NSString*)getRegionCodeForNumberFromRegionList:(NBPhoneNumber*)phoneNumber regionCodes:(NSArray*)regionCodes
+{
+    NSString *nationalNumber = [self getNationalSignificantNumber:phoneNumber];
+    NSUInteger regionCodesCount = [regionCodes count];
+    
+    for (NSUInteger i = 0; i<regionCodesCount; i++)
+    {
+        NSString *regionCode = [regionCodes objectAtIndex:i];
+        NBPhoneMetaData *metadata = [self getMetadataForRegion:regionCode];
+        
+        if ([self hasValue:metadata.leadingDigits])
+        {
+            if ([self stringPositionByRegex:nationalNumber regex:metadata.leadingDigits] == 0)
+            {
+                return regionCode;
+            }
+        }
+        else if ([self getNumberTypeHelper:nationalNumber metadata:metadata] != NBEPhoneNumberTypeUNKNOWN)
+        {
+            return regionCode;
+        }
+    }
+    
+    return nil;
+}
+
+
+/**
+ * Returns the region code that matches the specific country calling code. In
+ * the case of no region code being found, ZZ will be returned. In the case of
+ * multiple regions, the one designated in the metadata as the 'main' region for
+ * this calling code will be returned.
+ *
+ * @param {number} countryCallingCode the country calling code.
+ * @return {string}
+ */
+- (NSString*)getRegionCodeForCountryCode:(NSNumber*)countryCallingCode
+{
+    NSArray *regionCodes = [self regionCodeFromCountryCode:countryCallingCode];
+    return regionCodes == nil ? UNKNOWN_REGION_ : [regionCodes objectAtIndex:0];
+}
+
+
+/**
+ * Returns a list with the region codes that match the specific country calling
+ * code. For non-geographical country calling codes, the region code 001 is
+ * returned. Also, in the case of no region code being found, an empty list is
+ * returned.
+ *
+ * @param {number} countryCallingCode the country calling code.
+ * @return {Array.<string>}
+ */
+- (NSArray*)getRegionCodesForCountryCode:(NSNumber*)countryCallingCode
+{
+    NSArray *regionCodes = [self regionCodeFromCountryCode:countryCallingCode];
+    return regionCodes == nil ? nil : regionCodes;
+}
+
+
+/**
+ * Returns the country calling code for a specific region. For example, this
+ * would be 1 for the United States, and 64 for New Zealand.
+ *
+ * @param {?string} regionCode the region that we want to get the country
+ *     calling code for.
+ * @return {number} the country calling code for the region denoted by
+ *     regionCode.
+ */
+- (NSNumber*)getCountryCodeForRegion:(NSString*)regionCode
+{
+    if ([self isValidRegionCode:regionCode] == NO)
+    {
+        return @0;
+    }
+    
+    NSError *error = nil;
+    NSNumber *res = [self getCountryCodeForValidRegion:regionCode error:&error];
+    if (error != nil)
+        return @0;
+    return res;
+}
+
+
+/**
+ * Returns the country calling code for a specific region. For example, this
+ * would be 1 for the United States, and 64 for New Zealand. Assumes the region
+ * is already valid.
+ *
+ * @param {?string} regionCode the region that we want to get the country
+ *     calling code for.
+ * @return {number} the country calling code for the region denoted by
+ *     regionCode.
+ * @throws {string} if the region is invalid
+ * @private
+ */
+- (NSNumber *)getCountryCodeForValidRegion:(NSString*)regionCode error:(NSError**)error
+{
+    NSNumber * res = nil;
+    @try {
+        res = [self getCountryCodeForValidRegion:regionCode];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (NSNumber *)getCountryCodeForValidRegion:(NSString*)regionCode
+{
+    NBPhoneMetaData *metadata = [self getMetadataForRegion:regionCode];
+    if (metadata == nil)
+    {
+        NSException* metaException = [NSException exceptionWithName:@"INVALID_REGION_CODE"
+                                                             reason:[NSString stringWithFormat:@"Invalid region code:%@", regionCode]
+                                                           userInfo:nil];
+        @throw metaException;
+    }
+    return metadata.countryCode;
+}
+
+
+/**
+ * Returns the national dialling prefix for a specific region. For example, this
+ * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits
+ * to NO to strip symbols like '~' (which indicates a wait for a dialling
+ * tone) from the prefix returned. If no national prefix is present, we return
+ * nil.
+ *
+ * <p>Warning: Do not use this method for do-your-own formatting - for some
+ * regions, the national dialling prefix is used only for certain types of
+ * numbers. Use the library's formatting functions to prefix the national prefix
+ * when required.
+ *
+ * @param {?string} regionCode the region that we want to get the dialling
+ *     prefix for.
+ * @param {boolean} stripNonDigits NO to strip non-digits from the national
+ *     dialling prefix.
+ * @return {?string} the dialling prefix for the region denoted by
+ *     regionCode.
+ */
+- (NSString*)getNddPrefixForRegion:(NSString*)regionCode stripNonDigits:(BOOL)stripNonDigits
+{
+    NBPhoneMetaData *metadata = [self getMetadataForRegion:regionCode];
+    if (metadata == nil)
+    {
+        return nil;
+    }
+    
+    NSString *nationalPrefix = metadata.nationalPrefix;
+    // If no national prefix was found, we return nil.
+    if (nationalPrefix.length == 0)
+    {
+        return nil;
+    }
+    
+    if (stripNonDigits)
+    {
+        // Note: if any other non-numeric symbols are ever used in national
+        // prefixes, these would have to be removed here as well.
+        nationalPrefix = [nationalPrefix stringByReplacingOccurrencesOfString:@"~" withString:@""];
+    }
+    return nationalPrefix;
+}
+
+
+/**
+ * Checks if this is a region under the North American Numbering Plan
+ * Administration (NANPA).
+ *
+ * @param {?string} regionCode the ISO 3166-1 two-letter region code.
+ * @return {boolean} NO if regionCode is one of the regions under NANPA.
+ */
+- (BOOL)isNANPACountry:(NSString*)regionCode
+{
+    BOOL isExists = NO;
+    
+    NSArray *res = [self regionCodeFromCountryCode:@(NANPA_COUNTRY_CODE_)];
+    for (NSString *inRegionCode in res)
+    {
+        if ([inRegionCode isEqualToString:regionCode.uppercaseString])
+        {
+            isExists = YES;
+        }
+    }
+    
+    return regionCode != nil && isExists;
+}
+
+
+/**
+ * Checks whether countryCode represents the country calling code from a region
+ * whose national significant number could contain a leading zero. An example of
+ * such a region is Italy. Returns NO if no metadata for the country is
+ * found.
+ *
+ * @param {number} countryCallingCode the country calling code.
+ * @return {boolean}
+ */
+- (BOOL)isLeadingZeroPossible:(NSNumber*)countryCallingCode
+{
+    NBPhoneMetaData *mainMetadataForCallingCode = [self getMetadataForRegionOrCallingCode:countryCallingCode
+                                                                               regionCode:[self getRegionCodeForCountryCode:countryCallingCode]];
+    
+    return mainMetadataForCallingCode != nil && mainMetadataForCallingCode.leadingZeroPossible;
+}
+
+
+/**
+ * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT.
+ * A valid vanity number will start with at least 3 digits and will have three
+ * or more alpha characters. This does not do region-specific checks - to work
+ * out if this number is actually valid for a region, it should be parsed and
+ * methods such as {@link #isPossibleNumberWithReason} and
+ * {@link #isValidNumber} should be used.
+ *
+ * @param {string} number the number that needs to be checked.
+ * @return {boolean} NO if the number is a valid vanity number.
+ */
+- (BOOL)isAlphaNumber:(NSString*)number
+{
+    if ([self isViablePhoneNumber:number] == NO)
+    {
+        // Number is too short, or doesn't match the basic phone number pattern.
+        return NO;
+    }
+    
+    /** @type {!goog.string.StringBuffer} */
+    NSString *strippedNumber = [number copy];
+    [self maybeStripExtension:&strippedNumber];
+    
+    return [self matchesEntirely:VALID_ALPHA_PHONE_PATTERN_STRING string:strippedNumber];
+}
+
+
+/**
+ * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of
+ * returning the reason for failure, this method returns a boolean value.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
+ *     checked.
+ * @return {boolean} NO if the number is possible.
+ */
+- (BOOL)isPossibleNumber:(NBPhoneNumber*)number error:(NSError**)error
+{
+    BOOL res = NO;
+    @try {
+        res = [self isPossibleNumber:number];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (BOOL)isPossibleNumber:(NBPhoneNumber*)number
+{
+    return [self isPossibleNumberWithReason:number] == NBEValidationResultIS_POSSIBLE;
+}
+
+
+/**
+ * Helper method to check a number against a particular pattern and determine
+ * whether it matches, or is too short or too long. Currently, if a number
+ * pattern suggests that numbers of length 7 and 10 are possible, and a number
+ * in between these possible lengths is entered, such as of length 8, this will
+ * return TOO_LONG.
+ *
+ * @param {string} numberPattern
+ * @param {string} number
+ * @return {ValidationResult}
+ * @private
+ */
+- (NBEValidationResult)testNumberLengthAgainstPattern:(NSString*)numberPattern number:(NSString*)number
+{
+    if ([self matchesEntirely:numberPattern string:number])
+    {
+        return NBEValidationResultIS_POSSIBLE;
+    }
+    
+    if ([self stringPositionByRegex:number regex:numberPattern] == 0)
+    {
+        return NBEValidationResultTOO_LONG;
+    }
+    else
+    {
+        return NBEValidationResultTOO_SHORT;
+    }
+}
+
+
+/**
+ * Check whether a phone number is a possible number. It provides a more lenient
+ * check than {@link #isValidNumber} in the following sense:
+ * <ol>
+ * <li>It only checks the length of phone numbers. In particular, it doesn't
+ * check starting digits of the number.
+ * <li>It doesn't attempt to figure out the type of the number, but uses general
+ * rules which applies to all types of phone numbers in a region. Therefore, it
+ * is much faster than isValidNumber.
+ * <li>For fixed line numbers, many regions have the concept of area code, which
+ * together with subscriber number constitute the national significant number.
+ * It is sometimes okay to dial the subscriber number only when dialing in the
+ * same area. This function will return NO if the subscriber-number-only
+ * version is passed in. On the other hand, because isValidNumber validates
+ * using information on both starting digits (for fixed line numbers, that would
+ * most likely be area codes) and length (obviously includes the length of area
+ * codes for fixed line numbers), it will return NO for the
+ * subscriber-number-only version.
+ * </ol>
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
+ *     checked.
+ * @return {ValidationResult} a
+ *     ValidationResult object which indicates whether the number is possible.
+ */
+- (NBEValidationResult)isPossibleNumberWithReason:(NBPhoneNumber*)number error:(NSError *__autoreleasing *)error
+{
+    NBEValidationResult res = -1;
+    @try {
+        res = [self isPossibleNumberWithReason:number];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    
+    return res;
+}
+
+
+- (NBEValidationResult)isPossibleNumberWithReason:(NBPhoneNumber*)number
+{
+    NSString *nationalNumber = [self getNationalSignificantNumber:number];
+    NSNumber *countryCode = number.countryCode;
+    // Note: For Russian Fed and NANPA numbers, we just use the rules from the
+    // default region (US or Russia) since the getRegionCodeForNumber will not
+    // work if the number is possible but not valid. This would need to be
+    // revisited if the possible number pattern ever differed between various
+    // regions within those plans.
+    if ([self hasValidCountryCallingCode:countryCode] == NO)
+    {
+        return NBEValidationResultINVALID_COUNTRY_CODE;
+    }
+    
+    NSString *regionCode = [self getRegionCodeForCountryCode:countryCode];
+    // Metadata cannot be nil because the country calling code is valid.
+    NBPhoneMetaData *metadata = [self getMetadataForRegionOrCallingCode:countryCode regionCode:regionCode];
+    NBPhoneNumberDesc *generalNumDesc = metadata.generalDesc;
+    
+    // Handling case of numbers with no metadata.
+    if ([self hasValue:generalNumDesc.nationalNumberPattern] == NO)
+    {
+        NSUInteger numberLength = nationalNumber.length;
+        
+        if (numberLength < MIN_LENGTH_FOR_NSN_)
+        {
+            return NBEValidationResultTOO_SHORT;
+        }
+        else if (numberLength > MAX_LENGTH_FOR_NSN_)
+        {
+            return NBEValidationResultTOO_LONG;
+        }
+        else
+        {
+            return NBEValidationResultIS_POSSIBLE;
+        }
+    }
+    
+    NSString *possibleNumberPattern = generalNumDesc.possibleNumberPattern;
+    return [self testNumberLengthAgainstPattern:possibleNumberPattern number:nationalNumber];
+}
+
+
+/**
+ * Check whether a phone number is a possible number given a number in the form
+ * of a string, and the region where the number could be dialed from. It
+ * provides a more lenient check than {@link #isValidNumber}. See
+ * {@link #isPossibleNumber} for details.
+ *
+ * <p>This method first parses the number, then invokes
+ * {@link #isPossibleNumber} with the resultant PhoneNumber object.
+ *
+ * @param {string} number the number that needs to be checked, in the form of a
+ *     string.
+ * @param {string} regionDialingFrom the region that we are expecting the number
+ *     to be dialed from.
+ *     Note this is different from the region where the number belongs.
+ *     For example, the number +1 650 253 0000 is a number that belongs to US.
+ *     When written in this form, it can be dialed from any region. When it is
+ *     written as 00 1 650 253 0000, it can be dialed from any region which uses
+ *     an international dialling prefix of 00. When it is written as
+ *     650 253 0000, it can only be dialed from within the US, and when written
+ *     as 253 0000, it can only be dialed from within a smaller area in the US
+ *     (Mountain View, CA, to be more specific).
+ * @return {boolean} NO if the number is possible.
+ */
+- (BOOL)isPossibleNumberString:(NSString*)number regionDialingFrom:(NSString*)regionDialingFrom error:(NSError**)error
+{
+    BOOL res = NO;
+    @try {
+        res = [self isPossibleNumberString:number regionDialingFrom:regionDialingFrom];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (BOOL)isPossibleNumberString:(NSString*)number regionDialingFrom:(NSString*)regionDialingFrom
+{
+    @try {
+        return [self isPossibleNumber:[self parse:number defaultRegion:regionDialingFrom]];
+    }
+    @catch (NSException *e) {
+        return NO;
+    }
+}
+
+
+/**
+ * Attempts to extract a valid number from a phone number that is too long to be
+ * valid, and resets the PhoneNumber object passed in to that valid version. If
+ * no valid number could be extracted, the PhoneNumber object passed in will not
+ * be modified.
+ * @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which
+ *     contains a number that is too long to be valid.
+ * @return {boolean} NO if a valid phone number can be successfully extracted.
+ */
+- (BOOL)truncateTooLongNumber:(NBPhoneNumber*)number error:(NSError**)error
+{
+    BOOL res = NO;
+    @try {
+        res = [self truncateTooLongNumber:number];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (BOOL)truncateTooLongNumber:(NBPhoneNumber*)number
+{
+    if ([self isValidNumber:number])
+    {
+        return YES;
+    }
+
+    NBPhoneNumber *numberCopy = [number copy];
+    NSNumber *nationalNumber = number.nationalNumber;
+    do {
+        nationalNumber = [NSNumber numberWithLongLong:(long long)floor(nationalNumber.unsignedLongLongValue / 10)];
+        numberCopy.nationalNumber = [nationalNumber copy];
+        if ([nationalNumber isEqualToNumber:@0] || [self isPossibleNumberWithReason:numberCopy] == NBEValidationResultTOO_SHORT) {
+            return NO;
+        }
+    }
+    while ([self isValidNumber:numberCopy] == NO);
+    
+    number.nationalNumber = nationalNumber;
+    return YES;
+}
+
+
+/**
+ * Extracts country calling code from fullNumber, returns it and places the
+ * remaining number in nationalNumber. It assumes that the leading plus sign or
+ * IDD has already been removed. Returns 0 if fullNumber doesn't start with a
+ * valid country calling code, and leaves nationalNumber unmodified.
+ *
+ * @param {!goog.string.StringBuffer} fullNumber
+ * @param {!goog.string.StringBuffer} nationalNumber
+ * @return {number}
+ */
+- (NSNumber*)extractCountryCode:(NSString*)fullNumber nationalNumber:(NSString**)nationalNumber
+{
+    if ((fullNumber.length == 0) || ([[fullNumber substringToIndex:1] isEqualToString:@"0"]))
+    {
+        // Country codes do not begin with a '0'.
+        return @0;
+    }
+    
+    NSUInteger numberLength = fullNumber.length;
+    
+    for (NSUInteger i = 1; i <= MAX_LENGTH_COUNTRY_CODE_ && i <= numberLength; ++i)
+    {
+        NSString *subNumber = [fullNumber substringWithRange:NSMakeRange(0, i)];
+        NSNumber *potentialCountryCode = [NSNumber numberWithInteger:[subNumber integerValue]];
+
+        NSArray *regionCodes = [self regionCodeFromCountryCode:potentialCountryCode];
+        if (regionCodes != nil && regionCodes.count > 0)
+        {
+            if (nationalNumber != NULL)
+            {
+                if ((*nationalNumber) == nil)
+                    (*nationalNumber) = [NSString stringWithFormat:@"%@", [fullNumber substringFromIndex:i]];
+                else
+                    (*nationalNumber) = [NSString stringWithFormat:@"%@%@", (*nationalNumber), [fullNumber substringFromIndex:i]];
+            }
+            return potentialCountryCode;
+        }
+    }
+    
+    return @0;
+}
+
+
+/**
+ * Tries to extract a country calling code from a number. This method will
+ * return zero if no country calling code is considered to be present. Country
+ * calling codes are extracted in the following ways:
+ * <ul>
+ * <li>by stripping the international dialing prefix of the region the person is
+ * dialing from, if this is present in the number, and looking at the next
+ * digits
+ * <li>by stripping the '+' sign if present and then looking at the next digits
+ * <li>by comparing the start of the number and the country calling code of the
+ * default region. If the number is not considered possible for the numbering
+ * plan of the default region initially, but starts with the country calling
+ * code of this region, validation will be reattempted after stripping this
+ * country calling code. If this number is considered a possible number, then
+ * the first digits will be considered the country calling code and removed as
+ * such.
+ * </ul>
+ *
+ * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but
+ * the country calling code supplied after this does not match that of any known
+ * region.
+ *
+ * @param {string} number non-normalized telephone number that we wish to
+ *     extract a country calling code from - may begin with '+'.
+ * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata
+ *     about the region this number may be from.
+ * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store
+ *     the national significant number in, in the case that a country calling
+ *     code was extracted. The number is appended to any existing contents. If
+ *     no country calling code was extracted, this will be left unchanged.
+ * @param {boolean} keepRawInput NO if the country_code_source and
+ *     preferred_carrier_code fields of phoneNumber should be populated.
+ * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object
+ *     where the country_code and country_code_source need to be populated.
+ *     Note the country_code is always populated, whereas country_code_source is
+ *     only populated when keepCountryCodeSource is NO.
+ * @return {number} the country calling code extracted or 0 if none could be
+ *     extracted.
+ * @throws {i18n.phonenumbers.Error}
+ */
+- (NSNumber*)maybeExtractCountryCode:(NSString*)number metadata:(NBPhoneMetaData*)defaultRegionMetadata
+                   nationalNumber:(NSString**)nationalNumber keepRawInput:(BOOL)keepRawInput
+                      phoneNumber:(NBPhoneNumber**)phoneNumber error:(NSError**)error
+{
+    if (nationalNumber == NULL || phoneNumber == NULL)
+    {
+        return @0;
+    }
+    
+    NSNumber *res = @0;
+    @try {
+        res = [self maybeExtractCountryCode:number metadata:defaultRegionMetadata
+                             nationalNumber:nationalNumber keepRawInput:keepRawInput phoneNumber:phoneNumber];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    
+    return res;
+}
+
+- (NSNumber*)maybeExtractCountryCode:(NSString*)number metadata:(NBPhoneMetaData*)defaultRegionMetadata
+                   nationalNumber:(NSString**)nationalNumber keepRawInput:(BOOL)keepRawInput
+                      phoneNumber:(NBPhoneNumber**)phoneNumber
+{
+    if (nationalNumber == NULL || phoneNumber == NULL || number.length <= 0)
+    {
+        return @0;
+    }
+    
+    NSString *fullNumber = [number copy];
+    // Set the default prefix to be something that will never match.
+    NSString *possibleCountryIddPrefix = @"";
+    if (defaultRegionMetadata != nil)
+    {
+        possibleCountryIddPrefix = defaultRegionMetadata.internationalPrefix;
+    }
+    
+    if (possibleCountryIddPrefix == nil)
+    {
+        possibleCountryIddPrefix = @"NonMatch";
+    }
+    
+    /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */
+    NBECountryCodeSource countryCodeSource = [self maybeStripInternationalPrefixAndNormalize:&fullNumber
+                                                                           possibleIddPrefix:possibleCountryIddPrefix];
+    
+    if (keepRawInput)
+    {
+        (*phoneNumber).countryCodeSource = [NSNumber numberWithInt:countryCodeSource];
+    }
+    
+    if (countryCodeSource != NBECountryCodeSourceFROM_DEFAULT_COUNTRY)
+    {
+        if (fullNumber.length <= MIN_LENGTH_FOR_NSN_)
+        {
+            @throw [NSException exceptionWithName:@"TOO_SHORT_AFTER_IDD"
+                                           reason:[NSString stringWithFormat:@"TOO_SHORT_AFTER_IDD:%@", fullNumber]
+                                         userInfo:nil];
+        }
+        
+        NSNumber *potentialCountryCode = [self extractCountryCode:fullNumber nationalNumber:nationalNumber];
+        
+        if (![potentialCountryCode isEqualToNumber:@0])
+        {
+            (*phoneNumber).countryCode = potentialCountryCode;
+            return potentialCountryCode;
+        }
+        
+        // If this fails, they must be using a strange country calling code that we
+        // don't recognize, or that doesn't exist.
+        @throw [NSException exceptionWithName:@"INVALID_COUNTRY_CODE"
+                                       reason:[NSString stringWithFormat:@"INVALID_COUNTRY_CODE:%@", potentialCountryCode]
+                                     userInfo:nil];
+    }
+    else if (defaultRegionMetadata != nil)
+    {
+        // Check to see if the number starts with the country calling code for the
+        // default region. If so, we remove the country calling code, and do some
+        // checks on the validity of the number before and after.
+        NSNumber *defaultCountryCode = defaultRegionMetadata.countryCode;
+        NSString *defaultCountryCodeString = [NSString stringWithFormat:@"%@", defaultCountryCode];
+        NSString *normalizedNumber = [fullNumber copy];
+        
+        if ([normalizedNumber hasPrefix:defaultCountryCodeString])
+        {
+            NSString *potentialNationalNumber = [normalizedNumber substringFromIndex:defaultCountryCodeString.length];
+            NBPhoneNumberDesc *generalDesc = defaultRegionMetadata.generalDesc;
+            
+            NSString *validNumberPattern = generalDesc.nationalNumberPattern;
+            // Passing null since we don't need the carrier code.
+            [self maybeStripNationalPrefixAndCarrierCode:&potentialNationalNumber metadata:defaultRegionMetadata carrierCode:nil];
+            
+            NSString *potentialNationalNumberStr = [potentialNationalNumber copy];
+            NSString *possibleNumberPattern = generalDesc.possibleNumberPattern;
+            // If the number was not valid before but is valid now, or if it was too
+            // long before, we consider the number with the country calling code
+            // stripped to be a better result and keep that instead.
+            if ((![self matchesEntirely:validNumberPattern string:fullNumber] &&
+                 [self matchesEntirely:validNumberPattern string:potentialNationalNumberStr]) ||
+                [self testNumberLengthAgainstPattern:possibleNumberPattern number:fullNumber] == NBEValidationResultTOO_LONG)
+            {
+                (*nationalNumber) = [(*nationalNumber) stringByAppendingString:potentialNationalNumberStr];
+                if (keepRawInput)
+                {
+                    (*phoneNumber).countryCodeSource = [NSNumber numberWithInt:NBECountryCodeSourceFROM_NUMBER_WITHOUT_PLUS_SIGN];
+                }
+                (*phoneNumber).countryCode = defaultCountryCode;
+                return defaultCountryCode;
+            }
+        }
+    }
+    // No country calling code present.
+    (*phoneNumber).countryCode = @0;
+    return @0;
+}
+
+
+/**
+ * Strips the IDD from the start of the number if present. Helper function used
+ * by maybeStripInternationalPrefixAndNormalize.
+ *
+ * @param {!RegExp} iddPattern the regular expression for the international
+ *     prefix.
+ * @param {!goog.string.StringBuffer} number the phone number that we wish to
+ *     strip any international dialing prefix from.
+ * @return {boolean} NO if an international prefix was present.
+ * @private
+ */
+- (BOOL)parsePrefixAsIdd:(NSString*)iddPattern sourceString:(NSString**)number
+{
+    if (number == NULL)
+    {
+        return NO;
+    }
+    
+    NSString *numberStr = [(*number) copy];
+    
+    if ([self stringPositionByRegex:numberStr regex:iddPattern] == 0)
+    {
+        NSTextCheckingResult *matched = [[self matchesByRegex:numberStr regex:iddPattern] objectAtIndex:0];
+        NSString *matchedString = [numberStr substringWithRange:matched.range];
+        NSUInteger matchEnd = matchedString.length;
+        NSString *remainString = [numberStr substringFromIndex:matchEnd];
+        
+        NSRegularExpression *currentPattern = self.CAPTURING_DIGIT_PATTERN;
+        NSArray *matchedGroups = [currentPattern matchesInString:remainString options:0 range:NSMakeRange(0, remainString.length)];
+        
+        if (matchedGroups && [matchedGroups count] > 0 && [matchedGroups objectAtIndex:0] != nil)
+        {
+            NSString *digitMatched = [remainString substringWithRange:((NSTextCheckingResult*)[matchedGroups objectAtIndex:0]).range];
+            if (digitMatched.length > 0)
+            {
+                NSString *normalizedGroup = [self normalizeDigitsOnly:digitMatched];
+                if ([normalizedGroup isEqualToString:@"0"]) {
+                    return NO;
+                }
+            }
+        }
+        
+        (*number) = [remainString copy];
+        return YES;
+    }
+    
+    return NO;
+}
+
+
+/**
+ * Strips any international prefix (such as +, 00, 011) present in the number
+ * provided, normalizes the resulting number, and indicates if an international
+ * prefix was present.
+ *
+ * @param {!goog.string.StringBuffer} number the non-normalized telephone number
+ *     that we wish to strip any international dialing prefix from.
+ * @param {string} possibleIddPrefix the international direct dialing prefix
+ *     from the region we think this number may be dialed in.
+ * @return {CountryCodeSource} the corresponding
+ *     CountryCodeSource if an international dialing prefix could be removed
+ *     from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if
+ *     the number did not seem to be in international format.
+ */
+- (NBECountryCodeSource)maybeStripInternationalPrefixAndNormalize:(NSString**)numberStr possibleIddPrefix:(NSString*)possibleIddPrefix error:(NSError**)error
+{
+    if (numberStr == NULL)
+    {
+        return 0;
+    }
+    
+    NBECountryCodeSource res = 0;
+    @try {
+        res = [self maybeStripInternationalPrefixAndNormalize:numberStr possibleIddPrefix:possibleIddPrefix];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (NBECountryCodeSource)maybeStripInternationalPrefixAndNormalize:(NSString**)numberStr possibleIddPrefix:(NSString*)possibleIddPrefix
+{
+    if (numberStr == NULL || (*numberStr).length == 0)
+    {
+        return NBECountryCodeSourceFROM_DEFAULT_COUNTRY;
+    }
+    
+    // Check to see if the number begins with one or more plus signs.
+    if ([self isStartingStringByRegex:(*numberStr) regex:self.LEADING_PLUS_CHARS_PATTERN_])
+    {
+        (*numberStr) = [self replaceStringByRegex:(*numberStr) regex:self.LEADING_PLUS_CHARS_PATTERN_ withTemplate:@""];
+        // Can now normalize the rest of the number since we've consumed the '+'
+        // sign at the start.
+        (*numberStr) = [self normalizePhoneNumber:(*numberStr)];
+        return NBECountryCodeSourceFROM_NUMBER_WITH_PLUS_SIGN;
+    }
+    
+    // Attempt to parse the first digits as an international prefix.
+    NSString *iddPattern = [possibleIddPrefix copy];
+    [self normalizeSB:numberStr];
+    
+    return [self parsePrefixAsIdd:iddPattern sourceString:numberStr] ? NBECountryCodeSourceFROM_NUMBER_WITH_IDD : NBECountryCodeSourceFROM_DEFAULT_COUNTRY;
+}
+
+
+/**
+ * Strips any national prefix (such as 0, 1) present in the number provided.
+ *
+ * @param {!goog.string.StringBuffer} number the normalized telephone number
+ *     that we wish to strip any national dialing prefix from.
+ * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
+ *     region that we think this number is from.
+ * @param {goog.string.StringBuffer} carrierCode a place to insert the carrier
+ *     code if one is extracted.
+ * @return {boolean} NO if a national prefix or carrier code (or both) could
+ *     be extracted.
+ */
+- (BOOL)maybeStripNationalPrefixAndCarrierCode:(NSString**)number metadata:(NBPhoneMetaData*)metadata carrierCode:(NSString**)carrierCode error:(NSError**)error
+{
+    if (number == NULL)
+    {
+        return NO;
+    }
+    
+    BOOL res = NO;
+    @try {
+        res = [self maybeStripNationalPrefixAndCarrierCode:number metadata:metadata carrierCode:carrierCode];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+
+- (BOOL)maybeStripNationalPrefixAndCarrierCode:(NSString**)number metadata:(NBPhoneMetaData*)metadata carrierCode:(NSString**)carrierCode
+{
+    if (number == NULL)
+    {
+        return NO;
+    }
+    
+    NSString *numberStr = [(*number) copy];
+    NSUInteger numberLength = numberStr.length;
+    NSString *possibleNationalPrefix = metadata.nationalPrefixForParsing;
+    
+    if (numberLength == 0 || [self hasValue:possibleNationalPrefix] == NO)
+    {
+        // Early return for numbers of zero length.
+        return NO;
+    }
+    
+    // Attempt to parse the first digits as a national prefix.
+    NSString *prefixPattern = [NSString stringWithFormat:@"^(?:%@)", possibleNationalPrefix];
+    NSError *error = nil;
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:prefixPattern
+                                                                                    options:0 error:&error];
+    
+    NSArray *prefixMatcher = [currentPattern matchesInString:numberStr options:0 range:NSMakeRange(0, numberLength)];
+    if (prefixMatcher && [prefixMatcher count] > 0)
+    {
+        NSString *nationalNumberRule = metadata.generalDesc.nationalNumberPattern;
+        NSTextCheckingResult *firstMatch = [prefixMatcher objectAtIndex:0];
+        NSString *firstMatchString = [numberStr substringWithRange:firstMatch.range];
+        
+        // prefixMatcher[numOfGroups] == null implies nothing was captured by the
+        // capturing groups in possibleNationalPrefix; therefore, no transformation
+        // is necessary, and we just remove the national prefix.
+        NSUInteger numOfGroups = firstMatch.numberOfRanges - 1;
+        NSString *transformRule = metadata.nationalPrefixTransformRule;
+        NSString *transformedNumber = @"";
+        NSRange firstRange = [firstMatch rangeAtIndex:numOfGroups];
+        NSString *firstMatchStringWithGroup = (firstRange.location != NSNotFound && firstRange.location < numberStr.length) ? [numberStr substringWithRange:firstRange] : nil;
+        BOOL noTransform = (transformRule == nil || transformRule.length == 0 || [self hasValue:firstMatchStringWithGroup] == NO);
+        
+        if (noTransform)
+        {
+            transformedNumber = [numberStr substringFromIndex:firstMatchString.length];
+        }
+        else
+        {
+            transformedNumber = [self replaceFirstStringByRegex:numberStr regex:prefixPattern withTemplate:transformRule];
+        }
+        // If the original number was viable, and the resultant number is not,
+        // we return.
+        if ([self hasValue:nationalNumberRule ] && [self matchesEntirely:nationalNumberRule string:numberStr] &&
+            [self matchesEntirely:nationalNumberRule string:transformedNumber] == NO)
+        {
+            return NO;
+        }
+        
+        if ((noTransform && numOfGroups > 0 && [self hasValue:firstMatchStringWithGroup]) || (!noTransform && numOfGroups > 1))
+        {
+            if (carrierCode != NULL && (*carrierCode) != nil)
+            {
+                (*carrierCode) = [(*carrierCode) stringByAppendingString:firstMatchStringWithGroup];
+            }
+        }
+        else if ((noTransform && numOfGroups > 0 && [self hasValue:firstMatchString]) || (!noTransform && numOfGroups > 1))
+        {
+            if (carrierCode != NULL && (*carrierCode) != nil)
+            {
+                (*carrierCode) = [(*carrierCode) stringByAppendingString:firstMatchString];
+            }
+        }
+        
+        (*number) = transformedNumber;
+        return YES;
+    }
+    return NO;
+}
+
+
+/**
+ * Strips any extension (as in, the part of the number dialled after the call is
+ * connected, usually indicated with extn, ext, x or similar) from the end of
+ * the number, and returns it.
+ *
+ * @param {!goog.string.StringBuffer} number the non-normalized telephone number
+ *     that we wish to strip the extension from.
+ * @return {string} the phone extension.
+ */
+- (NSString*)maybeStripExtension:(NSString**)number
+{
+    if (number == NULL)
+    {
+        return @"";
+    }
+    
+    NSString *numberStr = [(*number) copy];
+    NSInteger mStart = [self stringPositionByRegex:numberStr regex:self.EXTN_PATTERN_];
+    
+    // If we find a potential extension, and the number preceding this is a viable
+    // number, we assume it is an extension.
+    if (mStart >= 0 && [self isViablePhoneNumber:[numberStr substringWithRange:NSMakeRange(0, mStart)]])
+    {
+        // The numbers are captured into groups in the regular expression.
+        NSTextCheckingResult *firstMatch = [self matcheFirstByRegex:numberStr regex:self.EXTN_PATTERN_];
+        NSUInteger matchedGroupsLength = [firstMatch numberOfRanges];
+        for (NSUInteger i=1; i<matchedGroupsLength; i++)
+        {
+            NSRange curRange = [firstMatch rangeAtIndex:i];
+            if (curRange.location != NSNotFound && curRange.location < numberStr.length)
+            {
+                NSString *matchString = [(*number) substringWithRange:curRange];
+                // We go through the capturing groups until we find one that captured
+                // some digits. If none did, then we will return the empty string.
+                NSString *tokenedString = [numberStr substringWithRange:NSMakeRange(0, mStart)];
+                (*number) = @"";
+                (*number) = [(*number) stringByAppendingString:tokenedString];
+                
+                return matchString;
+            }
+        }
+    }
+    
+    return @"";
+}
+
+
+/**
+ * Checks to see that the region code used is valid, or if it is not valid, that
+ * the number to parse starts with a + symbol so that we can attempt to infer
+ * the region from the number.
+ * @param {string} numberToParse number that we are attempting to parse.
+ * @param {?string} defaultRegion region that we are expecting the number to be
+ *     from.
+ * @return {boolean} NO if it cannot use the region provided and the region
+ *     cannot be inferred.
+ * @private
+ */
+- (BOOL)checkRegionForParsing:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion
+{
+    // If the number is nil or empty, we can't infer the region.
+    return [self isValidRegionCode:defaultRegion] ||
+    (numberToParse != nil && numberToParse.length > 0 && [self isStartingStringByRegex:numberToParse regex:self.LEADING_PLUS_CHARS_PATTERN_]);
+}
+
+
+/**
+ * Parses a string and returns it in proto buffer format. This method will throw
+ * a {@link i18n.phonenumbers.Error} if the number is not considered to be a
+ * possible number. Note that validation of whether the number is actually a
+ * valid number for a particular region is not performed. This can be done
+ * separately with {@link #isValidNumber}.
+ *
+ * @param {?string} numberToParse number that we are attempting to parse. This
+ *     can contain formatting such as +, ( and -, as well as a phone number
+ *     extension. It can also be provided in RFC3966 format.
+ * @param {?string} defaultRegion region that we are expecting the number to be
+ *     from. This is only used if the number being parsed is not written in
+ *     international format. The country_code for the number in this case would
+ *     be stored as that of the default region supplied. If the number is
+ *     guaranteed to start with a '+' followed by the country calling code, then
+ *     'ZZ' or nil can be supplied.
+ * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
+ *     with the parsed number.
+ * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
+ *     viable phone number or if no default region was supplied and the number
+ *     is not in international format (does not start with +).
+ */
+- (NBPhoneNumber*)parse:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion
+{
+    return [self parseHelper:numberToParse defaultRegion:defaultRegion keepRawInput:NO checkRegion:YES];
+}
+
+
+- (NBPhoneNumber*)parse:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion error:(NSError**)error
+{
+    NBPhoneNumber *phoneNumber = nil;
+    
+    @try {
+        phoneNumber = [self parseHelper:numberToParse defaultRegion:defaultRegion keepRawInput:NO checkRegion:YES];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    
+    return phoneNumber;
+}
+
+/**
+ * Parses a string using the phone's carrier region (when available, ZZ otherwise).
+ * This uses the country the sim card in the phone is registered with.
+ * For example if you have an AT&T sim card but are in Europe, this will parse the
+ * number using +1 (AT&T is a US Carrier) as the default country code.
+ * This also works for CDMA phones which don't have a sim card.
+ */
+- (NBPhoneNumber*)parseWithPhoneCarrierRegion:(NSString*)numberToParse error:(NSError**)error
+{
+	NSString *(^ISOCountryCodeByCarrier)() = ^() {
+		CTTelephonyNetworkInfo *networkInfo = [[CTTelephonyNetworkInfo alloc] init];
+		CTCarrier *carrier = [networkInfo subscriberCellularProvider];
+		return [carrier isoCountryCode];
+	};
+	NSString *isoCode = ISOCountryCodeByCarrier();
+	
+	if (!isoCode) {
+		isoCode = @"ZZ";
+	}
+	
+	return [self parse:numberToParse defaultRegion:isoCode];
+}
+
+
+/**
+ * Parses a string and returns it in proto buffer format. This method differs
+ * from {@link #parse} in that it always populates the raw_input field of the
+ * protocol buffer with numberToParse as well as the country_code_source field.
+ *
+ * @param {string} numberToParse number that we are attempting to parse. This
+ *     can contain formatting such as +, ( and -, as well as a phone number
+ *     extension.
+ * @param {?string} defaultRegion region that we are expecting the number to be
+ *     from. This is only used if the number being parsed is not written in
+ *     international format. The country calling code for the number in this
+ *     case would be stored as that of the default region supplied.
+ * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
+ *     with the parsed number.
+ * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
+ *     viable phone number or if no default region was supplied.
+ */
+- (NBPhoneNumber*)parseAndKeepRawInput:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion error:(NSError**)error
+{
+    NBPhoneNumber *res = nil;
+    @try {
+        res = [self parseAndKeepRawInput:numberToParse defaultRegion:defaultRegion];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (NBPhoneNumber*)parseAndKeepRawInput:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion
+{
+    if ([self isValidRegionCode:defaultRegion] == NO)
+    {
+        if (numberToParse.length > 0 && [numberToParse hasPrefix:@"+"] == NO)
+        {
+            NSException* metaException = [NSException exceptionWithName:@"INVALID_COUNTRY_CODE"
+                                                                 reason:[NSString stringWithFormat:@"Invalid country code:%@", numberToParse]
+                                                               userInfo:nil];
+            @throw metaException;
+        }
+    }
+    return [self parseHelper:numberToParse defaultRegion:defaultRegion keepRawInput:YES checkRegion:YES];
+}
+
+
+/**
+ * Parses a string and returns it in proto buffer format. This method is the
+ * same as the public {@link #parse} method, with the exception that it allows
+ * the default region to be nil, for use by {@link #isNumberMatch}.
+ *
+ * @param {?string} numberToParse number that we are attempting to parse. This
+ *     can contain formatting such as +, ( and -, as well as a phone number
+ *     extension.
+ * @param {?string} defaultRegion region that we are expecting the number to be
+ *     from. This is only used if the number being parsed is not written in
+ *     international format. The country calling code for the number in this
+ *     case would be stored as that of the default region supplied.
+ * @param {boolean} keepRawInput whether to populate the raw_input field of the
+ *     phoneNumber with numberToParse.
+ * @param {boolean} checkRegion should be set to NO if it is permitted for
+ *     the default coregion to be nil or unknown ('ZZ').
+ * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
+ *     with the parsed number.
+ * @throws {i18n.phonenumbers.Error}
+ * @private
+ */
+- (NBPhoneNumber*)parseHelper:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion
+                 keepRawInput:(BOOL)keepRawInput checkRegion:(BOOL)checkRegion error:(NSError**)error
+{
+    NBPhoneNumber *res = nil;
+    @try {
+        res = [self parseHelper:numberToParse defaultRegion:defaultRegion keepRawInput:keepRawInput checkRegion:checkRegion];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (NBPhoneNumber*)parseHelper:(NSString*)numberToParse defaultRegion:(NSString*)defaultRegion
+                 keepRawInput:(BOOL)keepRawInput checkRegion:(BOOL)checkRegion
+{
+    if (numberToParse == nil)
+    {
+        @throw [NSException exceptionWithName:@"NOT_A_NUMBER" reason:[NSString stringWithFormat:@"NOT_A_NUMBER:%@", numberToParse] userInfo:nil];
+    }
+    else if (numberToParse.length > MAX_INPUT_STRING_LENGTH_)
+    {
+        @throw [NSException exceptionWithName:@"TOO_LONG" reason:[NSString stringWithFormat:@"TOO_LONG:%@", numberToParse] userInfo:nil];
+    }
+    
+    NSString *nationalNumber = @"";
+    [self buildNationalNumberForParsing:numberToParse nationalNumber:&nationalNumber];
+    
+    if ([self isViablePhoneNumber:nationalNumber] == NO)
+    {
+        @throw [NSException exceptionWithName:@"NOT_A_NUMBER" reason:[NSString stringWithFormat:@"NOT_A_NUMBER:%@", nationalNumber] userInfo:nil];
+    }
+    
+    // Check the region supplied is valid, or that the extracted number starts
+    // with some sort of + sign so the number's region can be determined.
+    if (checkRegion && [self checkRegionForParsing:nationalNumber defaultRegion:defaultRegion] == NO)
+    {
+        @throw [NSException exceptionWithName:@"INVALID_COUNTRY_CODE" reason:[NSString stringWithFormat:@"INVALID_COUNTRY_CODE:%@", defaultRegion] userInfo:nil];
+    }
+    
+    NBPhoneNumber *phoneNumber = [[NBPhoneNumber alloc] init];
+    if (keepRawInput)
+    {
+        phoneNumber.rawInput = [numberToParse copy];
+    }
+    // Attempt to parse extension first, since it doesn't require region-specific
+    // data and we want to have the non-normalised number here.
+    NSString *extension = [self maybeStripExtension:&nationalNumber];
+    if (extension.length > 0)
+    {
+        phoneNumber.extension = [extension copy];
+    }
+    
+    NBPhoneMetaData *regionMetadata = [self getMetadataForRegion:defaultRegion];
+    // Check to see if the number is given in international format so we know
+    // whether this number is from the default region or not.
+    NSString *normalizedNationalNumber = @"";
+    NSNumber *countryCode = @0;
+    NSString *nationalNumberStr = [nationalNumber copy];
+    @try {
+        countryCode = [self maybeExtractCountryCode:nationalNumberStr
+                                           metadata:regionMetadata
+                                     nationalNumber:&normalizedNationalNumber
+                                       keepRawInput:keepRawInput
+                                        phoneNumber:&phoneNumber];
+    }
+    @catch (NSException *e) {
+        if ([e.name isEqualToString:@"INVALID_COUNTRY_CODE"] && [self stringPositionByRegex:nationalNumberStr
+                                                                                      regex:self.LEADING_PLUS_CHARS_PATTERN_] >= 0)
+        {
+            // Strip the plus-char, and try again.
+            nationalNumberStr = [self replaceStringByRegex:nationalNumberStr regex:self.LEADING_PLUS_CHARS_PATTERN_ withTemplate:@""];
+            countryCode = [self maybeExtractCountryCode:nationalNumberStr
+                                               metadata:regionMetadata
+                                         nationalNumber:&normalizedNationalNumber
+                                           keepRawInput:keepRawInput
+                                            phoneNumber:&phoneNumber];
+            if ([countryCode isEqualToNumber:@0])
+            {
+                @throw [NSException exceptionWithName:e.name
+                                               reason:[NSString stringWithFormat:@"%@:%@", e.name, nationalNumberStr]
+                                             userInfo:nil];
+            }
+        }
+        else
+        {
+            @throw e;
+        }
+    }
+    
+    if (![countryCode isEqualToNumber:@0])
+    {
+        NSString *phoneNumberRegion = [self getRegionCodeForCountryCode:countryCode];
+        if (phoneNumberRegion != defaultRegion)
+        {
+            // Metadata cannot be nil because the country calling code is valid.
+            regionMetadata = [self getMetadataForRegionOrCallingCode:countryCode regionCode:phoneNumberRegion];
+        }
+    }
+    else
+    {
+        // If no extracted country calling code, use the region supplied instead.
+        // The national number is just the normalized version of the number we were
+        // given to parse.
+        [self normalizeSB:&nationalNumber];
+        normalizedNationalNumber = [normalizedNationalNumber stringByAppendingString:nationalNumber];
+        
+        if (defaultRegion != nil)
+        {
+            countryCode = regionMetadata.countryCode;
+            phoneNumber.countryCode = countryCode;
+        }
+        else if (keepRawInput)
+        {
+            [phoneNumber clearCountryCodeSource];
+        }
+    }
+    
+    if (normalizedNationalNumber.length < MIN_LENGTH_FOR_NSN_)
+    {
+        @throw [NSException exceptionWithName:@"TOO_SHORT_NSN"
+                                       reason:[NSString stringWithFormat:@"TOO_SHORT_NSN:%@", normalizedNationalNumber]
+                                     userInfo:nil];
+    }
+    
+    if (regionMetadata != nil)
+    {
+        NSString *carrierCode = @"";
+        [self maybeStripNationalPrefixAndCarrierCode:&normalizedNationalNumber metadata:regionMetadata carrierCode:&carrierCode];
+        
+        if (keepRawInput)
+        {
+            phoneNumber.PreferredDomesticCarrierCode = [carrierCode copy];
+        }
+    }
+    
+    NSString *normalizedNationalNumberStr = [normalizedNationalNumber copy];
+    
+    NSUInteger lengthOfNationalNumber = normalizedNationalNumberStr.length;
+    if (lengthOfNationalNumber < MIN_LENGTH_FOR_NSN_)
+    {
+        @throw [NSException exceptionWithName:@"TOO_SHORT_NSN"
+                                       reason:[NSString stringWithFormat:@"TOO_SHORT_NSN:%@", normalizedNationalNumberStr]
+                                     userInfo:nil];
+    }
+    
+    if (lengthOfNationalNumber > MAX_LENGTH_FOR_NSN_)
+    {
+        @throw [NSException exceptionWithName:@"TOO_LONG"
+                                       reason:[NSString stringWithFormat:@"TOO_LONG:%@", normalizedNationalNumberStr]
+                                     userInfo:nil];
+    }
+    
+    if ([normalizedNationalNumberStr hasPrefix:@"0"])
+    {
+        phoneNumber.italianLeadingZero = YES;
+    }
+    
+    phoneNumber.nationalNumber = [NSNumber numberWithLongLong:(UInt64)[normalizedNationalNumberStr longLongValue]];
+    return phoneNumber;
+}
+
+
+/**
+ * Converts numberToParse to a form that we can parse and write it to
+ * nationalNumber if it is written in RFC3966; otherwise extract a possible
+ * number out of it and write to nationalNumber.
+ *
+ * @param {?string} numberToParse number that we are attempting to parse. This
+ *     can contain formatting such as +, ( and -, as well as a phone number
+ *     extension.
+ * @param {!goog.string.StringBuffer} nationalNumber a string buffer for storing
+ *     the national significant number.
+ * @private
+ */
+- (void)buildNationalNumberForParsing:(NSString*)numberToParse nationalNumber:(NSString**)nationalNumber
+{
+    if (nationalNumber == NULL)
+        return;
+    
+    NSInteger indexOfPhoneContext = [self indexOfStringByString:numberToParse target:RFC3966_PHONE_CONTEXT_];
+    if (indexOfPhoneContext > 0)
+    {
+        NSUInteger phoneContextStart = indexOfPhoneContext + RFC3966_PHONE_CONTEXT_.length;
+        // If the phone context contains a phone number prefix, we need to capture
+        // it, whereas domains will be ignored.
+        if ([numberToParse characterAtIndex:phoneContextStart] == '+')
+        {
+            // Additional parameters might follow the phone context. If so, we will
+            // remove them here because the parameters after phone context are not
+            // important for parsing the phone number.
+            NSRange foundRange = [numberToParse rangeOfString:@";" options:NSLiteralSearch range:NSMakeRange(phoneContextStart, numberToParse.length - phoneContextStart)];
+            if (foundRange.location != NSNotFound)
+            {
+                NSRange subRange = NSMakeRange(phoneContextStart, foundRange.location - phoneContextStart);
+                (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[numberToParse substringWithRange:subRange]];
+            }
+            else
+            {
+                (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[numberToParse substringFromIndex:phoneContextStart]];
+            }
+        }
+        
+        // Now append everything between the "tel:" prefix and the phone-context.
+        // This should include the national number, an optional extension or
+        // isdn-subaddress component.
+        NSUInteger rfc3966Start = [self indexOfStringByString:numberToParse target:RFC3966_PREFIX_] + RFC3966_PREFIX_.length;
+        NSString *subString = [numberToParse substringWithRange:NSMakeRange(rfc3966Start, indexOfPhoneContext - rfc3966Start)];
+        (*nationalNumber) = [(*nationalNumber) stringByAppendingString:subString];
+    }
+    else
+    {
+        // Extract a possible number from the string passed in (this strips leading
+        // characters that could not be the start of a phone number.)
+        (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[self extractPossibleNumber:numberToParse]];
+    }
+    
+    // Delete the isdn-subaddress and everything after it if it is present.
+    // Note extension won't appear at the same time with isdn-subaddress
+    // according to paragraph 5.3 of the RFC3966 spec,
+    NSString *nationalNumberStr = [(*nationalNumber) copy];
+    NSInteger indexOfIsdn = [self indexOfStringByString:nationalNumberStr target:RFC3966_ISDN_SUBADDRESS_];
+    if (indexOfIsdn > 0)
+    {
+        (*nationalNumber) = @"";
+        (*nationalNumber) = [(*nationalNumber) stringByAppendingString:[nationalNumberStr substringWithRange:NSMakeRange(0, indexOfIsdn)]];
+    }
+    // If both phone context and isdn-subaddress are absent but other
+    // parameters are present, the parameters are left in nationalNumber. This
+    // is because we are concerned about deleting content from a potential
+    // number string when there is no strong evidence that the number is
+    // actually written in RFC3966.
+}
+
+
+/**
+ * Takes two phone numbers and compares them for equality.
+ *
+ * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero
+ * for Italian numbers and any extension present are the same. Returns NSN_MATCH
+ * if either or both has no region specified, and the NSNs and extensions are
+ * the same. Returns SHORT_NSN_MATCH if either or both has no region specified,
+ * or the region specified is the same, and one NSN could be a shorter version
+ * of the other number. This includes the case where one has an extension
+ * specified, and the other does not. Returns NO_MATCH otherwise. For example,
+ * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers
+ * +1 345 657 1234 and 345 657 are a NO_MATCH.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to
+ *     compare. If it is a string it can contain formatting, and can have
+ *     country calling code specified with + at the start.
+ * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to
+ *     compare. If it is a string it can contain formatting, and can have
+ *     country calling code specified with + at the start.
+ * @return {MatchType} NOT_A_NUMBER, NO_MATCH,
+ *     SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of
+ *     equality of the two numbers, described in the method definition.
+ */
+- (NBEMatchType)isNumberMatch:(id)firstNumberIn second:(id)secondNumberIn error:(NSError**)error
+{
+    NBEMatchType res = 0;
+    @try {
+        res = [self isNumberMatch:firstNumberIn second:secondNumberIn];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (NBEMatchType)isNumberMatch:(id)firstNumberIn second:(id)secondNumberIn
+{
+    
+    // If the input arguements are strings parse them to a proto buffer format.
+    // Else make copies of the phone numbers so that the numbers passed in are not
+    // edited.
+    /** @type {i18n.phonenumbers.PhoneNumber} */
+    NBPhoneNumber *firstNumber = nil, *secondNumber = nil;
+    if ([firstNumberIn isKindOfClass:[NSString class]])
+    {
+        // First see if the first number has an implicit country calling code, by
+        // attempting to parse it.
+        @try {
+            firstNumber = [self parse:firstNumberIn defaultRegion:UNKNOWN_REGION_];
+        }
+        @catch (NSException *e) {
+            if ([e.name isEqualToString:@"INVALID_COUNTRY_CODE"] == NO)
+            {
+                return NBEMatchTypeNOT_A_NUMBER;
+            }
+            // The first number has no country calling code. EXACT_MATCH is no longer
+            // possible. We parse it as if the region was the same as that for the
+            // second number, and if EXACT_MATCH is returned, we replace this with
+            // NSN_MATCH.
+            if ([secondNumberIn isKindOfClass:[NSString class]] == NO)
+            {
+                NSString *secondNumberRegion = [self getRegionCodeForCountryCode:((NBPhoneNumber*)secondNumberIn).countryCode];
+                if (secondNumberRegion != UNKNOWN_REGION_)
+                {
+                    @try {
+                        firstNumber = [self parse:firstNumberIn defaultRegion:secondNumberRegion];
+                    }
+                    @catch (NSException *e2) {
+                        return NBEMatchTypeNOT_A_NUMBER;
+                    }
+                    
+                    NBEMatchType match = [self isNumberMatch:firstNumber second:secondNumberIn];
+                    if (match == NBEMatchTypeEXACT_MATCH)
+                    {
+                        return NBEMatchTypeNSN_MATCH;
+                    }
+                    return match;
+                }
+            }
+            // If the second number is a string or doesn't have a valid country
+            // calling code, we parse the first number without country calling code.
+            @try {
+                firstNumber = [self parseHelper:firstNumberIn defaultRegion:nil keepRawInput:NO checkRegion:NO];
+            }
+            @catch (NSException *e2)  {
+                return NBEMatchTypeNOT_A_NUMBER;
+            }
+        }
+    }
+    else
+    {
+        firstNumber = [firstNumberIn copy];
+    }
+    
+    if ([secondNumberIn isKindOfClass:[NSString class]])
+    {
+        @try {
+            secondNumber = [self parse:secondNumberIn defaultRegion:UNKNOWN_REGION_];
+            return [self isNumberMatch:firstNumberIn second:secondNumber];
+        }
+        @catch (NSException *e2) {
+            if ([e2.name isEqualToString:@"INVALID_COUNTRY_CODE"] == NO)
+            {
+                return NBEMatchTypeNOT_A_NUMBER;
+            }
+            return [self isNumberMatch:secondNumberIn second:firstNumber];
+        }
+    }
+    else
+    {
+        secondNumber = [secondNumberIn copy];
+    }
+    
+    // First clear raw_input, country_code_source and
+    // preferred_domestic_carrier_code fields and any empty-string extensions so
+    // that we can use the proto-buffer equality method.
+    firstNumber.rawInput = @"";
+    [firstNumber clearCountryCodeSource];
+    firstNumber.PreferredDomesticCarrierCode = @"";
+    
+    secondNumber.rawInput = @"";
+    [secondNumber clearCountryCodeSource];
+    secondNumber.PreferredDomesticCarrierCode = @"";
+    
+    if (firstNumber.extension != nil && firstNumber.extension.length == 0)
+    {
+        firstNumber.extension = nil;
+    }
+    
+    if (secondNumber.extension != nil && secondNumber.extension.length == 0)
+    {
+        secondNumber.extension = nil;
+    }
+    
+    // Early exit if both had extensions and these are different.
+    if ([self hasValue:firstNumber.extension] && [self hasValue:secondNumber.extension] &&
+        [firstNumber.extension isEqualToString:secondNumber.extension] == NO)
+    {
+        return NBEMatchTypeNO_MATCH;
+    }
+    
+    NSNumber *firstNumberCountryCode = firstNumber.countryCode;
+    NSNumber *secondNumberCountryCode = secondNumber.countryCode;
+    
+    // Both had country_code specified.
+    if (![firstNumberCountryCode isEqualToNumber:@0] && ![secondNumberCountryCode isEqualToNumber:@0])
+    {
+        if ([firstNumber isEqual:secondNumber])
+        {
+            return NBEMatchTypeEXACT_MATCH;
+        }
+        else if ([firstNumberCountryCode isEqualToNumber:secondNumberCountryCode] && [self isNationalNumberSuffixOfTheOther:firstNumber second:secondNumber])
+        {
+            // A SHORT_NSN_MATCH occurs if there is a difference because of the
+            // presence or absence of an 'Italian leading zero', the presence or
+            // absence of an extension, or one NSN being a shorter variant of the
+            // other.
+            return NBEMatchTypeSHORT_NSN_MATCH;
+        }
+        // This is not a match.
+        return NBEMatchTypeNO_MATCH;
+    }
+    // Checks cases where one or both country_code fields were not specified. To
+    // make equality checks easier, we first set the country_code fields to be
+    // equal.
+    firstNumber.countryCode = @0;
+    secondNumber.countryCode = @0;
+    // If all else was the same, then this is an NSN_MATCH.
+    if ([firstNumber isEqual:secondNumber])
+    {
+        return NBEMatchTypeNSN_MATCH;
+    }
+    
+    if ([self isNationalNumberSuffixOfTheOther:firstNumber second:secondNumber])
+    {
+        return NBEMatchTypeSHORT_NSN_MATCH;
+    }
+    return NBEMatchTypeNO_MATCH;
+}
+
+
+/**
+ * Returns NO when one national number is the suffix of the other or both are
+ * the same.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber
+ *     object.
+ * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber
+ *     object.
+ * @return {boolean} NO if one PhoneNumber is the suffix of the other one.
+ * @private
+ */
+- (BOOL)isNationalNumberSuffixOfTheOther:(NBPhoneNumber*)firstNumber second:(NBPhoneNumber*)secondNumber
+{
+    NSString *firstNumberNationalNumber = [NSString stringWithFormat:@"%@", firstNumber.nationalNumber];
+    NSString *secondNumberNationalNumber = [NSString stringWithFormat:@"%@", secondNumber.nationalNumber];
+    
+    // Note that endsWith returns NO if the numbers are equal.
+    return [firstNumberNationalNumber hasSuffix:secondNumberNationalNumber] ||
+    [secondNumberNationalNumber hasSuffix:firstNumberNationalNumber];
+}
+
+
+/**
+ * Returns NO if the number can be dialled from outside the region, or
+ * unknown. If the number can only be dialled from within the region, returns
+ * NO. Does not check the number is a valid number.
+ * TODO: Make this method public when we have enough metadata to make it
+ * worthwhile. Currently visible for testing purposes only.
+ *
+ * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we
+ *     want to know whether it is diallable from outside the region.
+ * @return {boolean} NO if the number can only be dialled from within the
+ *     country.
+ */
+- (BOOL)canBeInternationallyDialled:(NBPhoneNumber*)number error:(NSError**)error
+{
+    BOOL res = NO;
+    @try {
+        res = [self canBeInternationallyDialled:number];
+    }
+    @catch (NSException *exception) {
+        NSDictionary *userInfo = [NSDictionary dictionaryWithObject:exception.reason
+                                                             forKey:NSLocalizedDescriptionKey];
+        if (error != NULL)
+            (*error) = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
+    }
+    return res;
+}
+
+- (BOOL)canBeInternationallyDialled:(NBPhoneNumber*)number
+{
+    NBPhoneMetaData *metadata = [self getMetadataForRegion:[self getRegionCodeForNumber:number]];
+    if (metadata == nil)
+    {
+        // Note numbers belonging to non-geographical entities (e.g. +800 numbers)
+        // are always internationally diallable, and will be caught here.
+        return YES;
+    }
+    NSString *nationalSignificantNumber = [self getNationalSignificantNumber:number];
+    return [self isNumberMatchingDesc:nationalSignificantNumber numberDesc:metadata.noInternationalDialling] == NO;
+}
+
+
+/**
+ * Check whether the entire input sequence can be matched against the regular
+ * expression.
+ *
+ * @param {!RegExp|string} regex the regular expression to match against.
+ * @param {string} str the string to test.
+ * @return {boolean} NO if str can be matched entirely against regex.
+ * @private
+ */
+- (BOOL)matchesEntirely:(NSString*)regex string:(NSString*)str
+{
+    if ([regex rangeOfString:@"^"].location == NSNotFound)
+    {
+        regex = [NSString stringWithFormat:@"^(?:%@)$", regex];
+    }
+    
+    NSError *error = nil;
+    NSRegularExpression *currentPattern = [NSRegularExpression regularExpressionWithPattern:regex options:0 error:&error];
+    NSTextCheckingResult *matchResult = [currentPattern firstMatchInString:str options:0 range:NSMakeRange(0, str.length)];
+    
+    if (matchResult != nil)
+    {
+        NSString *founds = [str substringWithRange:matchResult.range];
+        
+        if ([founds isEqualToString:str])
+        {
+            return YES;
+        }
+    }
+    
+    return NO;
+}
+
+
+@end