diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index e5ade24..d4bf0d9 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -2,10 +2,7 @@ name: Swift on: pull_request: - branches: [ main ] - - pull_request: - branches: [ develop ] + branches: [ main, develop ] jobs: @@ -20,7 +17,9 @@ jobs: build: needs: swiftLint - runs-on: macos-latest + env: + DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer + runs-on: macos-11.0 steps: - uses: actions/checkout@v2 - name: Install Bundle @@ -31,20 +30,22 @@ jobs: uses: actions/upload-artifact@v2 with: name: build - path: derivedData/Build/Products/Debug-iphonesimulator/Addame.app + path: '"derivedData/Build/Products/Debug CI-iphonesimulator/Addame.app"' unitTests: needs: build - runs-on: macos-latest + env: + DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer + runs-on: macos-11.0 steps: - uses: actions/checkout@v2 - - name: Download core tests - uses: actions/download-artifact@v2 - with: - name: coreTests - path: derivedData/Build/Products/Debug-iphonesimulator/EventFormViewTests.xctest - name: Install Bundle run: bundle install - name: Run unit tests run: bundle exec fastlane unitTestLane + - name: Run tests + uses: actions/download-artifact@v2 + with: + name: unitTests + path: '"derivedData/Build/Products/Debug CI-iphonesimulator/EventFormViewTests.xctest"' diff --git a/.gitignore b/.gitignore index 21c1a0f..8241b04 100644 --- a/.gitignore +++ b/.gitignore @@ -119,3 +119,7 @@ Addame/Configs/Production.xcconfig /fastlane/FastlaneRunner test_output/report.html test_output/report.junit +env-vars.sh +Addame/Autogenerated/AppSecrets.generated.swift +Addame/Templates/AppSecrets.stencil +AddameSPM/Sources/ProfileView/File.swift diff --git a/Addame.xcodeproj/project.pbxproj b/Addame.xcodeproj/project.pbxproj index 28f7d55..4ec5892 100644 --- a/Addame.xcodeproj/project.pbxproj +++ b/Addame.xcodeproj/project.pbxproj @@ -7,17 +7,17 @@ objects = { /* Begin PBXBuildFile section */ - C3186C642647F1FB00E1B69F /* AppFeature in Frameworks */ = {isa = PBXBuildFile; productRef = C3186C632647F1FB00E1B69F /* AppFeature */; }; C33DFAC8261F1B4100132010 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33DFAC7261F1B4100132010 /* Environment.swift */; }; + C3511D5D26EF6044004B9155 /* AppFeature in Frameworks */ = {isa = PBXBuildFile; productRef = C3511D5C26EF6044004B9155 /* AppFeature */; }; C3E50CA0261B5DFA00285977 /* Addame.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E50C9F261B5DFA00285977 /* Addame.swift */; }; C3E50CA4261B5DFF00285977 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C3E50CA3261B5DFF00285977 /* Assets.xcassets */; }; C3E50CA7261B5DFF00285977 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C3E50CA6261B5DFF00285977 /* Preview Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - C33DFABA261F1A9700132010 /* ProductionCopy.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ProductionCopy.xcconfig; sourceTree = ""; }; + C33DFABA261F1A9700132010 /* ProductionCI.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ProductionCI.xcconfig; sourceTree = ""; }; C33DFABB261F1A9700132010 /* Production.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Production.xcconfig; sourceTree = ""; }; - C33DFABC261F1A9700132010 /* DevelopmentCopy.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DevelopmentCopy.xcconfig; sourceTree = ""; }; + C33DFABC261F1A9700132010 /* DevelopmentCI.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DevelopmentCI.xcconfig; sourceTree = ""; }; C33DFABD261F1A9700132010 /* Development.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Development.xcconfig; sourceTree = ""; }; C33DFAC7261F1B4100132010 /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; C3E50C9C261B5DFA00285977 /* Addame.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Addame.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -32,7 +32,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - C3186C642647F1FB00E1B69F /* AppFeature in Frameworks */, + C3511D5D26EF6044004B9155 /* AppFeature in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -44,9 +44,9 @@ children = ( C33DFAC7261F1B4100132010 /* Environment.swift */, C33DFABD261F1A9700132010 /* Development.xcconfig */, - C33DFABC261F1A9700132010 /* DevelopmentCopy.xcconfig */, + C33DFABC261F1A9700132010 /* DevelopmentCI.xcconfig */, C33DFABB261F1A9700132010 /* Production.xcconfig */, - C33DFABA261F1A9700132010 /* ProductionCopy.xcconfig */, + C33DFABA261F1A9700132010 /* ProductionCI.xcconfig */, ); path = Configs; sourceTree = ""; @@ -107,6 +107,7 @@ C3E50C9A261B5DFA00285977 /* Resources */, C36C678E26E3FC9A007CC94D /* swift-format */, C36AE8D826E8ABD6002FFF84 /* SwiftLint */, + C39CB4FF26EF597C004BC15F /* ShellScript */, ); buildRules = ( ); @@ -114,7 +115,7 @@ ); name = Addame; packageProductDependencies = ( - C3186C632647F1FB00E1B69F /* AppFeature */, + C3511D5C26EF6044004B9155 /* AppFeature */, ); productName = TComposableAAddaMe; productReference = C3E50C9C261B5DFA00285977 /* Addame.app */; @@ -201,6 +202,23 @@ shellPath = /bin/sh; shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n#if which swift-format >/dev/null; then\n # swift-format -m format -i -r ${PROJECT_DIR}\n # swift-format -m lint -r ${PROJECT_DIR}\n#else\n # echo \"warning: swift-format not installed\"\n#fi\n"; }; + C39CB4FF26EF597C004BC15F /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -216,9 +234,100 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - C3E50CA9261B5DFF00285977 /* Debug */ = { + C3C1EE1C26EDFC7E00376AE6 /* Debug Development */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C33DFABD261F1A9700132010 /* Development.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = "Debug Development"; + }; + C3C1EE1D26EDFC7E00376AE6 /* Debug Development */ = { isa = XCBuildConfiguration; baseConfigurationReference = C33DFABD261F1A9700132010 /* Development.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 10; + DEVELOPMENT_ASSET_PATHS = "\"Addame/Preview Content\""; + DEVELOPMENT_TEAM = 6989658CU5; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = AddaMe/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.2.5; + PRODUCT_BUNDLE_IDENTIFIER = com.addame.AddaMeIOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug Development"; + }; + C3E50CA9261B5DFF00285977 /* Debug CI */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C33DFABC261F1A9700132010 /* DevelopmentCI.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -277,7 +386,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; - name = Debug; + name = "Debug CI"; }; C3E50CAA261B5DFF00285977 /* Release */ = { isa = XCBuildConfiguration; @@ -336,14 +445,15 @@ }; name = Release; }; - C3E50CAC261B5DFF00285977 /* Debug */ = { + C3E50CAC261B5DFF00285977 /* Debug CI */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C33DFABD261F1A9700132010 /* Development.xcconfig */; + baseConfigurationReference = C33DFABC261F1A9700132010 /* DevelopmentCI.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_ASSET_PATHS = "\"Addame/Preview Content\""; DEVELOPMENT_TEAM = 6989658CU5; ENABLE_PREVIEWS = YES; @@ -353,14 +463,15 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.2.5; PRODUCT_BUNDLE_IDENTIFIER = com.addame.AddaMeIOS; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; - name = Debug; + name = "Debug CI"; }; C3E50CAD261B5DFF00285977 /* Release */ = { isa = XCBuildConfiguration; @@ -368,8 +479,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_ASSET_PATHS = "\"Addame/Preview Content\""; DEVELOPMENT_TEAM = 6989658CU5; ENABLE_PREVIEWS = YES; @@ -379,9 +491,10 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.2.5; PRODUCT_BUNDLE_IDENTIFIER = com.addame.AddaMeIOS; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; @@ -394,7 +507,8 @@ C3E50C97261B5DFA00285977 /* Build configuration list for PBXProject "Addame" */ = { isa = XCConfigurationList; buildConfigurations = ( - C3E50CA9261B5DFF00285977 /* Debug */, + C3E50CA9261B5DFF00285977 /* Debug CI */, + C3C1EE1C26EDFC7E00376AE6 /* Debug Development */, C3E50CAA261B5DFF00285977 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -403,7 +517,8 @@ C3E50CAB261B5DFF00285977 /* Build configuration list for PBXNativeTarget "Addame" */ = { isa = XCConfigurationList; buildConfigurations = ( - C3E50CAC261B5DFF00285977 /* Debug */, + C3E50CAC261B5DFF00285977 /* Debug CI */, + C3C1EE1D26EDFC7E00376AE6 /* Debug Development */, C3E50CAD261B5DFF00285977 /* Release */, ); defaultConfigurationIsVisible = 0; @@ -412,7 +527,7 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - C3186C632647F1FB00E1B69F /* AppFeature */ = { + C3511D5C26EF6044004B9155 /* AppFeature */ = { isa = XCSwiftPackageProductDependency; productName = AppFeature; }; diff --git a/Addame.xcworkspace/contents.xcworkspacedata b/Addame.xcworkspace/contents.xcworkspacedata index 846e9ab..01f0360 100644 --- a/Addame.xcworkspace/contents.xcworkspacedata +++ b/Addame.xcworkspace/contents.xcworkspacedata @@ -8,6 +8,6 @@ location = "group:Addame.xcodeproj"> + location = "group:AddameSPM"> diff --git a/Addame.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Addame.xcworkspace/xcshareddata/swiftpm/Package.resolved index bdaf6dc..55d64ef 100644 --- a/Addame.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Addame.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -2,12 +2,12 @@ "object": { "pins": [ { - "package": "AWSSDKSwift", - "repositoryURL": "https://github.com/swift-aws/aws-sdk-swift.git", + "package": "async-http-client", + "repositoryURL": "https://github.com/swift-server/async-http-client.git", "state": { "branch": null, - "revision": "b402b8a434ca39f24d189289ab93fbee96664502", - "version": "4.9.0" + "revision": "cbf533073d9a5edfb16c266d14151f69137ba7c9", + "version": "1.8.2" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/pointfreeco/combine-schedulers", "state": { "branch": null, - "revision": "6bde3b0063ba8e7537b43744948535ca7e9e0dad", - "version": "0.5.2" + "revision": "4cf088c29a20f52be0f2ca54992b492c54e0076b", + "version": "0.5.3" } }, { @@ -30,56 +30,56 @@ }, { "package": "composable-core-location", - "repositoryURL": "https://github.com/pointfreeco/composable-core-location", + "repositoryURL": "https://github.com/pointfreeco/composable-core-location.git", "state": { - "branch": null, - "revision": "ad0b25210c1daef738f2565c4308765123fa248f", - "version": "0.1.0" + "branch": "main", + "revision": "42bb4d67b9afe88dc67ac0512f1bd98aebc7c79a", + "version": null } }, { - "package": "HttpRequest", - "repositoryURL": "https://github.com/AddaMeSPB/HttpRequest.git", + "package": "HTTPRequestKit", + "repositoryURL": "https://github.com/AddaMeSPB/HTTPRequestKit.git", "state": { "branch": null, - "revision": "8f93450f1113a697be54ffe6a071b9fd2bf90b95", - "version": "2.2.0" + "revision": "d2e387fe13eb3e9dd551f5530aa549284517e5c6", + "version": "3.0.0" } }, { - "package": "HypertextApplicationLanguage", - "repositoryURL": "https://github.com/swift-aws/HypertextApplicationLanguage.git", + "package": "jmespath.swift", + "repositoryURL": "https://github.com/adam-fowler/jmespath.swift.git", "state": { "branch": null, - "revision": "aa2c9141d491682f17b2310aed17b9adfc006256", - "version": "1.1.1" + "revision": "4a166ea71f0d9e9cc3523fc3dee516080a4c36a0", + "version": "1.0.0" } }, { - "package": "INIParser", - "repositoryURL": "https://github.com/swift-aws/Perfect-INIParser.git", + "package": "PhoneNumberKit", + "repositoryURL": "https://github.com/marmelroy/PhoneNumberKit", "state": { "branch": null, - "revision": "42de0efc7a01105e19b80d533d3d282a98277f6c", - "version": "3.0.3" + "revision": "1ef0431b971f69c48ca5eb4cdba07f2c5da54c35", + "version": "3.3.3" } }, { - "package": "PhoneNumberKit", - "repositoryURL": "https://github.com/marmelroy/PhoneNumberKit", + "package": "soto", + "repositoryURL": "https://github.com/soto-project/soto.git", "state": { "branch": null, - "revision": "1ef0431b971f69c48ca5eb4cdba07f2c5da54c35", - "version": "3.3.3" + "revision": "3648a7fcbaa1ac06b6ab2b4b227d521ed065e780", + "version": "5.13.1" } }, { - "package": "AWSSDKSwiftCore", + "package": "soto-core", "repositoryURL": "https://github.com/soto-project/soto-core.git", "state": { "branch": null, - "revision": "856a7df0c15763de4f9f3e3d7baea4a8aa009d22", - "version": "4.7.2" + "revision": "3079d17f2576cff5f2a3f68865629af455c673d1", + "version": "5.9.3" } }, { @@ -87,8 +87,8 @@ "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", "state": { "branch": null, - "revision": "d226d167bd4a68b51e352af5655c92bce8ee0463", - "version": "0.7.0" + "revision": "ce9c0d897db8a840c39de64caaa9b60119cf4be8", + "version": "0.8.1" } }, { @@ -96,17 +96,17 @@ "repositoryURL": "https://github.com/apple/swift-collections", "state": { "branch": null, - "revision": "9d8719c8bebdc79740b6969c912ac706eb721d7a", - "version": "0.0.7" + "revision": "48254824bb4248676bf7ce56014ff57b142b77eb", + "version": "1.0.2" } }, { - "package": "swift-composable-architecture", - "repositoryURL": "https://github.com/pointfreeco/swift-composable-architecture.git", + "package": "swift-composable-presentation", + "repositoryURL": "https://github.com/darrarski/swift-composable-presentation.git", "state": { "branch": null, - "revision": "60dc8067185b3e1fb29237f5a4548bff005b0fec", - "version": "0.26.0" + "revision": "e48fc5d8c4e3360c2f8fd579cbf38e49dbee34a5", + "version": "0.3.0" } }, { @@ -114,8 +114,8 @@ "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump", "state": { "branch": null, - "revision": "8655495733d8c712db8d9078f47d17f3555db79f", - "version": "0.1.2" + "revision": "c4f78db9b90ca57b7b6abc2223e235242739ea3c", + "version": "0.4.0" } }, { @@ -123,8 +123,26 @@ "repositoryURL": "https://github.com/pointfreeco/swift-identified-collections", "state": { "branch": null, - "revision": "04502c882077cd838d380d05b127db9a6e48d8da", - "version": "0.2.0" + "revision": "2d6b7ffcc67afd9077fac5e5a29bcd6d39b71076", + "version": "0.4.0" + } + }, + { + "package": "swift-log", + "repositoryURL": "https://github.com/apple/swift-log.git", + "state": { + "branch": null, + "revision": "5d66f7ba25daf4f94100e7022febf3c75e37a6c7", + "version": "1.4.2" + } + }, + { + "package": "swift-metrics", + "repositoryURL": "https://github.com/apple/swift-metrics.git", + "state": { + "branch": null, + "revision": "3edd2f57afc4e68e23c3e4956bc8b65ca6b5b2ff", + "version": "2.2.0" } }, { @@ -132,8 +150,26 @@ "repositoryURL": "https://github.com/apple/swift-nio.git", "state": { "branch": null, - "revision": "94f41c4121a82fae5c7b1cb03e630e9f9e5e20f1", - "version": "2.32.1" + "revision": "124119f0bb12384cef35aa041d7c3a686108722d", + "version": "2.40.0" + } + }, + { + "package": "swift-nio-extras", + "repositoryURL": "https://github.com/apple/swift-nio-extras.git", + "state": { + "branch": null, + "revision": "f73ca5ee9c6806800243f1ac415fcf82de9a4c91", + "version": "1.10.2" + } + }, + { + "package": "swift-nio-http2", + "repositoryURL": "https://github.com/apple/swift-nio-http2.git", + "state": { + "branch": null, + "revision": "72bcaf607b40d7c51044f65b0f5ed8581a911832", + "version": "1.21.0" } }, { @@ -141,8 +177,8 @@ "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", "state": { "branch": null, - "revision": "4829979d9f5ed9a2f4c6efd9c1ed51d1ab4d0394", - "version": "2.14.1" + "revision": "5e68c1ded15619bb281b273fa8c2d8fd7f7b2b7d", + "version": "2.16.1" } }, { @@ -150,8 +186,8 @@ "repositoryURL": "https://github.com/apple/swift-nio-transport-services.git", "state": { "branch": null, - "revision": "9571a61d236c5253b6a255a2d13fac536a1e2625", - "version": "1.11.2" + "revision": "e7f5278a26442dc46783ba7e063643d524e414a0", + "version": "1.11.3" } }, { diff --git a/Addame.xcworkspace/xcshareddata/xcschemes/Addame.xcscheme b/Addame.xcworkspace/xcshareddata/xcschemes/AddameCI.xcscheme similarity index 99% rename from Addame.xcworkspace/xcshareddata/xcschemes/Addame.xcscheme rename to Addame.xcworkspace/xcshareddata/xcschemes/AddameCI.xcscheme index 29bbc13..5c1320b 100644 --- a/Addame.xcworkspace/xcshareddata/xcschemes/Addame.xcscheme +++ b/Addame.xcworkspace/xcshareddata/xcschemes/AddameCI.xcscheme @@ -723,7 +723,7 @@ @@ -735,13 +735,13 @@ BlueprintIdentifier = "EventFormViewTests" BuildableName = "EventFormViewTests" BlueprintName = "EventFormViewTests" - ReferencedContainer = "container:Addame/Addame"> + ReferencedContainer = "container:AddameSPM"> + buildConfiguration = "Debug CI"> diff --git a/Addame.xcworkspace/xcshareddata/xcschemes/AddameDev.xcscheme b/Addame.xcworkspace/xcshareddata/xcschemes/AddameDev.xcscheme new file mode 100644 index 0000000..9135775 --- /dev/null +++ b/Addame.xcworkspace/xcshareddata/xcschemes/AddameDev.xcscheme @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Addame.xcworkspace/xcshareddata/xcschemes/AddamePro.xcscheme b/Addame.xcworkspace/xcshareddata/xcschemes/AddamePro.xcscheme new file mode 100644 index 0000000..6081656 --- /dev/null +++ b/Addame.xcworkspace/xcshareddata/xcschemes/AddamePro.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Addame/Addame.swift b/Addame/Addame.swift index 0cc1523..889cfa9 100644 --- a/Addame/Addame.swift +++ b/Addame/Addame.swift @@ -10,17 +10,20 @@ import AuthClient import AuthClientLive import AuthenticationView import ComposableArchitecture -import ConversationsView -import EventView -import ProfileView import SwiftUI import TabsView @main struct AddameApp: App { + let store = Store( + initialState: AppState(), + reducer: appReducer, + environment: .live + ) + var body: some Scene { WindowGroup { - AppView() + AppView(store: store) } } } diff --git a/Addame/Addame/Sources/AppFeature/AppDelegate.swift b/Addame/Addame/Sources/AppFeature/AppDelegate.swift deleted file mode 100644 index dea1de2..0000000 --- a/Addame/Addame/Sources/AppFeature/AppDelegate.swift +++ /dev/null @@ -1,109 +0,0 @@ -import AuthClient -import ChatClient -import ComposableArchitecture -import ConversationClient -import EventClient -import NotificationHelpers -import RemoteNotificationsClient -import SettingsView -import UIKit -import UserClient -import UserNotificationClient -import UserNotifications - -public enum AppDelegateAction: Equatable { - case didFinishLaunching - case didRegisterForRemoteNotifications(Result) - case userNotifications(UserNotificationClient.DelegateEvent) - case userSettingsLoaded(Result) -} - -struct AppDelegateEnvironment { - var mainQueue: AnySchedulerOf - var setUserInterfaceStyle: (UIUserInterfaceStyle) -> Effect - var userNotifications: UserNotificationClient - var remoteNotifications: RemoteNotificationsClient - var authClient: AuthClient - - // #if DEBUG - // static let failing = Self( - // backgroundQueue: .failing("backgroundQueue"), - // mainQueue: .failing("mainQueue"), - // remoteNotifications: .failing, - // setUserInterfaceStyle: { _ in .failing("setUserInterfaceStyle") }, - // userNotifications: .failing - // ) - // #endif -} - -let appDelegateReducer = Reducer< - UserSettings, AppDelegateAction, AppDelegateEnvironment -> { state, action, environment in - switch action { - case .didFinishLaunching: - return .merge( - // Set notifications delegate - environment.userNotifications.delegate - .map(AppDelegateAction.userNotifications), - - environment.userNotifications.getNotificationSettings - .receive(on: environment.mainQueue) - .flatMap { settings in - [.notDetermined, .provisional].contains(settings.authorizationStatus) - ? environment.userNotifications.requestAuthorization(.provisional) - : settings.authorizationStatus == .authorized - ? environment.userNotifications.requestAuthorization([.alert, .sound]) - : .none - } - .flatMap { successful in - successful - ? Effect.registerForRemoteNotifications( - mainQueue: environment.mainQueue, - remoteNotifications: environment.remoteNotifications, - userNotifications: environment.userNotifications - ) - : .none - } - .eraseToEffect() - .fireAndForget() - ) - - case .didRegisterForRemoteNotifications(.failure): - return .none - - case let .didRegisterForRemoteNotifications(.success(tokenData)): - let token = tokenData.map { String(format: "%02.2hhx", $0) }.joined() - return .none - // environment.userNotifications.getNotificationSettings - // .flatMap { settings in - // environment.apiClient.apiRequest( - // route: .push( - // .register( - // .init( - // authorizationStatus: .init(rawValue: settings.authorizationStatus.rawValue), - // build: environment.build.number(), - // token: token - // ) - // ) - // ) - // ) - // } - // .fireAndForget() - - case let .userNotifications(.willPresentNotification(_, completionHandler)): - return .fireAndForget { - completionHandler(.banner) - } - - case .userNotifications: - return .none - - case let .userSettingsLoaded(result): - state = (try? result.get()) ?? state - return environment.setUserInterfaceStyle(state.colorScheme.userInterfaceStyle) - // NB: This is necessary because UIKit needs at least one tick of the run loop before we - // can set the user interface style. - .subscribe(on: environment.mainQueue) - .fireAndForget() - } -} diff --git a/Addame/Addame/Sources/AppFeature/AppView.swift b/Addame/Addame/Sources/AppFeature/AppView.swift deleted file mode 100644 index edf2a24..0000000 --- a/Addame/Addame/Sources/AppFeature/AppView.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// AppView.swift -// -// -// Created by Saroar Khandoker on 05.05.2021. -// - -import AuthClient -import AuthClientLive -import AuthenticationView -import ComposableArchitecture -import ConversationsView -import EventView -import ProfileView -import SwiftUI -import TabsView - -public struct AppView: View { - public init() {} - - @AppStorage("isAuthorized") - public var isAuthorized: Bool = false - - static let tabsEnv = TabsEnvironment( - backgroundQueue: .main, - mainQueue: .main, - webSocketClient: .live - ) - - static let tabsState = TabsState( - selectedTab: .event, - event: EventsState(), - conversations: ConversationsState(), - profile: ProfileState() - ) - - let tabsStore = Store( - initialState: tabsState, - reducer: tabsReducer, // .debug(), - environment: tabsEnv - ) - - static let environment = AuthenticationEnvironment( - authClient: AuthClient.live(api: .build), - mainQueue: DispatchQueue.main.eraseToAnyScheduler() - ) - - static let authState = LoginState.build - let authStore = Store( - initialState: authState, - reducer: loginReducer, - environment: environment - ) - - @ViewBuilder - public var body: some View { - Group { - if isAuthorized { - TabsView(store: tabsStore) - } else { - AuthenticationView(store: authStore) - } - } - } -} diff --git a/Addame/Addame/Sources/AsyncImageLoder/ImagePicker.swift b/Addame/Addame/Sources/AsyncImageLoder/ImagePicker.swift deleted file mode 100644 index c0b72cf..0000000 --- a/Addame/Addame/Sources/AsyncImageLoder/ImagePicker.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// ImagePicker.swift -// -// -// Created by Saroar Khandoker on 26.01.2021. -// - -import Foundation -import SwiftUI -import UIKit - -public struct ImagePicker: UIViewControllerRepresentable { - @Environment(\.presentationMode) var presentationMode - @Binding var image: UIImage? - - public init(image: Binding) { - _image = image - } - - public func makeUIViewController( - context: UIViewControllerRepresentableContext - ) -> UIImagePickerController { - let picker = UIImagePickerController() - picker.delegate = context.coordinator - return picker - } - - public func updateUIViewController( - _: UIImagePickerController, context _: UIViewControllerRepresentableContext - ) {} - - public func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - public class Coordinator: NSObject, UINavigationControllerDelegate, - UIImagePickerControllerDelegate { - public let parent: ImagePicker - - public init(_ parent: ImagePicker) { - self.parent = parent - } - - public func imagePickerController( - _: UIImagePickerController, - didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any] - ) { - if let uiImage = info[.originalImage] as? UIImage { - parent.image = uiImage - } - - parent.presentationMode.wrappedValue.dismiss() - } - } -} diff --git a/Addame/Addame/Sources/AttachmentClient/AttachmentClient.swift b/Addame/Addame/Sources/AttachmentClient/AttachmentClient.swift deleted file mode 100644 index 90c5338..0000000 --- a/Addame/Addame/Sources/AttachmentClient/AttachmentClient.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// AttachmentClient.swift -// -// -// Created by Saroar Khandoker on 27.01.2021. -// - -import Combine -import Foundation -import HttpRequest -import SharedModels - -public struct AttachmentClient { - public typealias UserImageUploadHandler = (Attachment) -> AnyPublisher - public let uploadAvatar: UserImageUploadHandler - - public init(uploadAvatar: @escaping UserImageUploadHandler) { - self.uploadAvatar = uploadAvatar - } -} diff --git a/Addame/Addame/Sources/AttachmentClient/AwsS3Manager.swift b/Addame/Addame/Sources/AttachmentClient/AwsS3Manager.swift deleted file mode 100644 index 347a5b6..0000000 --- a/Addame/Addame/Sources/AttachmentClient/AwsS3Manager.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// AwsS3Manager.swift -// -// -// Created by Saroar Khandoker on 27.01.2021. -// - -import AVFoundation -import FoundationExtension -import KeychainService -import NIO -import S3 -import SharedModels -import UIKit - -public enum AWSS3Helper { - public static var bucketWithEndpoint = "https://adda.nyc3.digitaloceanspaces.com/" - private static let compressionQueue = OperationQueue() - - public static var getCurrentMillis: Int64 { - return Int64(Date().timeIntervalSince1970 * 1000) - } - - public static func uploadImage( - _ image: UIImage, - conversationId: String? = nil, - userId: String? = nil, - completion: @escaping (String?) -> Void - ) { - guard let user: User = KeychainService.loadCodable(for: .user) else { - print(#line, "Missing current user from KeychainService") - return - } - - let awsS3Service = S3( - accessKeyId: "", // EnvironmentKeys.accessKeyId, - secretAccessKey: "", // EnvironmentKeys.secretAccessKey, - region: .useast1, - endpoint: "https://nyc3.digitaloceanspaces.com" - ) - - let data = image.compressImage(conversationId == nil ? .highest : .medium) - let imageFormat = data.1 - guard let imageData = data.0 else { - completion(nil) - return - } - - let currentTime = AWSS3Helper.getCurrentMillis - var imageKey = String(format: "%ld", currentTime) - if let conversationId = conversationId { - imageKey = "uploads/images/\(conversationId)/\(imageKey).\(imageFormat)" - } else if let userId = userId { - imageKey = "uploads/images/\(userId)/\(imageKey).\(imageFormat)" - } else { - imageKey = "uploads/images/\(user.id)_\(imageKey).\(imageFormat) " - } - - // Put an Object - let putObjectRequest = S3.PutObjectRequest( - acl: .publicRead, - body: imageData, - bucket: "adda", - contentLength: Int64(imageData.count), - key: imageKey - ) - - let futureOutput = awsS3Service.putObject(putObjectRequest) - - futureOutput.whenSuccess { response in - print(#line, self, response, imageKey) - let finalURL = bucketWithEndpoint + imageKey - completion(finalURL) - } - - futureOutput.whenFailure { error in - print(#line, self, error) - completion(nil) - } - } -} diff --git a/Addame/Addame/Sources/AttachmentClientLive/Live.swift b/Addame/Addame/Sources/AttachmentClientLive/Live.swift deleted file mode 100644 index b665d54..0000000 --- a/Addame/Addame/Sources/AttachmentClientLive/Live.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Live.swift -// -// -// Created by Saroar Khandoker on 27.01.2021. -// - -import AttachmentClient -import Combine -import Foundation -import HttpRequest -import InfoPlist -import SharedModels - -public struct AttachmentAPI { - public static let build = Self() - - private var baseURL: URL { EnvironmentKeys.rootURL.appendingPathComponent("/attachments") } - - func updload(avatar: Attachment) -> AnyPublisher { - let builder: HttpRequest = .build( - baseURL: baseURL, - method: .post, - authType: .none, - path: "", - contentType: .json, - dataType: .encodable(input: avatar) - ) - - return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in - Fail(error: error).eraseToAnyPublisher() - } - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } -} - -extension AttachmentClient { - public static func live(api: AttachmentAPI) -> Self { - .init(uploadAvatar: api.updload(avatar:)) - } -} diff --git a/Addame/Addame/Sources/AuthenticationView/TermsAndPrivacyWebView.swift b/Addame/Addame/Sources/AuthenticationView/TermsAndPrivacyWebView.swift deleted file mode 100644 index 5f54314..0000000 --- a/Addame/Addame/Sources/AuthenticationView/TermsAndPrivacyWebView.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// TermsAndPrivacyWebView.swift -// AddaMeIOS -// -// Created by Saroar Khandoker on 07.12.2020. -// - -import SwiftUI - -public struct TermsAndPrivacyWebView: View { - @Environment(\.presentationMode) var presentationMode - let urlString: String - - public var body: some View { - TermsAndPrivacyWebRepresentableView(urlString: urlString) - .overlay( - Button( - action: { - presentationMode.wrappedValue.dismiss() - }, - label: { - Image(systemName: "xmark.circle").font(.title) - } - ) - .padding(.bottom, 10) - .padding(), - - alignment: .bottomTrailing - ) - } -} - -struct TermsAndPrivacyWebView_Previews: PreviewProvider { - static var previews: some View { - TermsAndPrivacyWebView(urlString: "http://10.0.1.3:3030/privacy") - } -} diff --git a/Addame/Addame/Sources/ComposableArchitectureHelpers/NavigationLink+Store.swift b/Addame/Addame/Sources/ComposableArchitectureHelpers/NavigationLink+Store.swift deleted file mode 100644 index de190c6..0000000 --- a/Addame/Addame/Sources/ComposableArchitectureHelpers/NavigationLink+Store.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// NavigationLink+Store.swift -// -// -// Created by Saroar Khandoker on 07.05.2021. -// - -import ComposableArchitecture -import SwiftUI - -extension NavigationLink { - /// Creates `NavigationLink` using a `Store` with an optional `State`. - /// - /// - Link is active if `State` is non-`nil` and inactive when it's `nil`. - /// - Link's destination is generated using last non-`nil` state value. - /// - /// - Parameters: - /// - store: A store with optional state. - /// - destination: A closure that creates link's destination view. - /// - destinationStore: A store with non-optional state. - /// - action: A closure invoked when the link is activated or deactivated. - /// - isActive: Determines if the link is active or inactive. - /// - label: The link's label. - /// - Returns: Navigation link wrapped in a `WithViewStore`. - static func store( - _ store: Store, - destination: @escaping (_ destinationStore: Store) -> DestinationContent, - action: @escaping (_ isActive: Bool) -> Void, - label: @escaping () -> Label - ) -> some View - where - DestinationContent: View, - Destination == IfLetStore { - WithViewStore(store.scope(state: { $0 != nil })) { viewStore in - NavigationLink( - destination: IfLetStore( - store.scope(state: replayNonNil()), - then: destination - ), - isActive: Binding( - get: { viewStore.state }, - set: action - ), - label: label - ) - } - } -} - -extension View { - /// Adds `NavigationLink` without a label, using `Store` with an optional `State`. - /// - /// - Link is active if `State` is non-`nil` and inactive when it's `nil`. - /// - Link's destination is generated using last non-`nil` state value. - /// - /// - Parameters: - /// - store: store with optional state - /// - destination: closure that creates link's destination view - /// - destinationStore: store with non-optional state - /// - onDismiss: closure invoked when link is deactivated - /// - Returns: view with label-less `NavigationLink` added as a background view - public func navigate( - using store: Store, - destination: @escaping (_ destinationStore: Store) -> DestinationContent, - onDismiss: @escaping () -> Void - ) -> some View - where DestinationContent: View { - background( - NavigationLink.store( - store, - destination: destination, - action: { isActive in - if isActive == false { - onDismiss() - } - }, - label: EmptyView.init - ) - ) - } -} diff --git a/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+CaptureState.swift b/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+CaptureState.swift deleted file mode 100644 index 91a275f..0000000 --- a/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+CaptureState.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Reducer+CaptureState.swift -// -// -// Created by Saroar Khandoker on 13.06.2021. -// - -import ComposableArchitecture - -extension Reducer { - - /// Captures reduced state. - /// - Parameter capture: A closure called when a state is reduced. - /// state: The reduced state value. - /// - Returns: A reducer that works on `State`, `Action`, `Environment`. - func captureState(_ capture: @escaping (_ state: State) -> Void) -> Self { - .init { state, action, environment in - capture(state) - return run(&state, action, environment) - } - } -} diff --git a/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+Presents.swift b/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+Presents.swift deleted file mode 100644 index 6cc4de4..0000000 --- a/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+Presents.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Reducer+Presents.swift -// -// -// Created by Saroar Khandoker on 13.06.2021. -// - -import ComposableArchitecture - -// swiftlint:disable all -extension Reducer { - /// Combines the reducer with a reducer that works on optionally presented `LocalState`. - /// - /// - All effects returned by the local reducer are canceled when `LocalState` is `nil`. - /// - If `LocalAction` is sent when `LocalState` is `nil`: - /// - The last non-`nil` state value is passed to the local reducer (if available). - /// - The `LocalState` is unchanged (it stays `nil`). - /// - All effects returned by the local reducer are immediately canceled. - /// - /// Based on [Reducer.presents function](https://github.com/pointfreeco/swift-composable-architecture/blob/9ec4b71e5a84f448dedb063a21673e4696ce135f/Sources/ComposableArchitecture/Reducer.swift#L549-L572) from `iso` branch of `swift-composable-architecture` repository. - /// - /// - Parameters: - /// - localReducer: A reducer that works on `LocalState`, `LocalAction`, `LocalEnvironment`. - /// - toLocalState: A key path that can get/set `LocalState?` inside `State`. - /// - toLocalAction: A case path that can extract/embed `LocalAction` from `Action`. - /// - toLocalEnvironment: A function that transforms `Environment` into `LocalEnvironment`. - /// - Returns: A reducer that works on `State`, `Action`, `Environment`. - public func presents( - _ localReducer: Reducer, - state toLocalState: WritableKeyPath, - action toLocalAction: CasePath, - environment toLocalEnvironment: @escaping (Environment) -> LocalEnvironment - ) -> Self { - let localEffectsId = UUID() - var lastNonNilLocalState: LocalState? - return Self { state, action, environment in - let localEffects = - localReducer - .optional() - .replaceNilState(with: lastNonNilLocalState) - .captureState { lastNonNilLocalState = $0 ?? lastNonNilLocalState } - .pullback(state: toLocalState, action: toLocalAction, environment: toLocalEnvironment) - .run(&state, action, environment) - .cancellable(id: localEffectsId) - let globalEffects = run(&state, action, environment) - let hasLocalState = state[keyPath: toLocalState] != nil - return .merge( - localEffects, - globalEffects, - hasLocalState ? .none : .cancel(id: localEffectsId) - ) - } - } -} diff --git a/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+ReplaceNilState.swift b/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+ReplaceNilState.swift deleted file mode 100644 index 6762012..0000000 --- a/Addame/Addame/Sources/ComposableArchitectureHelpers/Reducer+ReplaceNilState.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Reducer+ReplaceNilState.swift -// -// -// Created by Saroar Khandoker on 13.06.2021. -// - -import ComposableArchitecture - -extension Reducer { - /// Replaces `nil` state with provided value. - /// - /// - If reducer is run with non-`nil` state its behavior is unchanged. - /// - If reducer is run with a `nil` state, replacement state is used instead. - /// - When replacement state is used, the original state wont be mutated! - /// - /// - Parameter replacement: The replacement state value. - /// - Returns: A reducer that works on `State`, `Action`, `Environment`. - func replaceNilState( - with replacement: @escaping @autoclosure () -> S? - ) -> Self where State == S? { - .init { state, action, environment in - guard state != nil else { - var replacedState = replacement() - return run(&replacedState, action, environment) - } - return run(&state, action, environment) - } - } -} diff --git a/Addame/Addame/Sources/ComposableArchitectureHelpers/ReplayNonNil.swift b/Addame/Addame/Sources/ComposableArchitectureHelpers/ReplayNonNil.swift deleted file mode 100644 index 29f2b90..0000000 --- a/Addame/Addame/Sources/ComposableArchitectureHelpers/ReplayNonNil.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ReplayNonNil.swift -// -// -// Created by Saroar Khandoker on 13.06.2021. -// - -// swiftlint:disable all -/// Converts a closure `(A) -> B?` to a closure that returns last non-`nil` `B` returned by the input closure. -/// -/// Based on a code from [Thomvis/Construct repository](https://github.com/Thomvis/Construct/blob/f165fd005cd939560c1a4eb8d6ee55075a52685d/Construct/Foundation/Memoize.swift) -/// -/// - Parameter inputClosure: The input closure. -/// - Returns: Modified closure. -func replayNonNil(_ inputClosure: @escaping (A) -> B?) -> (A) -> B? { - var lastNonNilOutput: B? - return { inputValue in - guard let outputValue = inputClosure(inputValue) else { - return lastNonNilOutput - } - lastNonNilOutput = outputValue - return outputValue - } -} - -/// Creates a closure (T?) -> T? that returns last non-`nil` T passed to it. -/// -/// - Returns: The closure. -func replayNonNil() -> (T?) -> T? { - replayNonNil { $0 } -} diff --git a/Addame/Addame/Sources/EventView/EventDetailsView.swift b/Addame/Addame/Sources/EventView/EventDetailsView.swift deleted file mode 100644 index 5885683..0000000 --- a/Addame/Addame/Sources/EventView/EventDetailsView.swift +++ /dev/null @@ -1,6 +0,0 @@ -// -// EventDetailsView.swift -// -// -// Created by Saroar Khandoker on 13.04.2021. -// diff --git a/Addame/Addame/Sources/EventView/EventsState.swift b/Addame/Addame/Sources/EventView/EventsState.swift deleted file mode 100644 index cf128ed..0000000 --- a/Addame/Addame/Sources/EventView/EventsState.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// EventState.swift -// -// -// Created by Saroar Khandoker on 06.04.2021. -// - -import ChatView -import ComposableArchitecture -import ComposableCoreLocation -import EventDetailsView -import EventFormView -import MapKit -import SharedModels - -public struct EventsState: Equatable { - public init( - alert: AlertState? = nil, isConnected: Bool = true, - isLocationAuthorized: Bool = false, isRequestingCurrentLocation: Bool = false, - waitingForUpdateLocation: Bool = true, - isMovingChatRoom: Bool = false, isLoadingPage: Bool = false, - canLoadMorePages: Bool = true, currentPage: Int = 1, - currentAddress: String = "", placeMark: CLPlacemark? = nil, - location: Location? = nil, events: IdentifiedArrayOf = [], - myEvents: IdentifiedArrayOf = [], event: EventResponse.Item? = nil, - eventFormState: EventFormState? = nil, eventDetailsState: EventDetailsState? = nil, - chatState: ChatState? = nil - ) { - self.alert = alert - self.isConnected = isConnected - self.isLocationAuthorized = isLocationAuthorized - self.isRequestingCurrentLocation = isRequestingCurrentLocation - self.waitingForUpdateLocation = waitingForUpdateLocation - self.isLoadingPage = isLoadingPage - self.canLoadMorePages = canLoadMorePages - self.isMovingChatRoom = isMovingChatRoom - self.currentPage = currentPage - self.currentAddress = currentAddress - self.placeMark = placeMark - self.location = location - self.events = events - self.myEvents = myEvents - self.event = event - self.eventFormState = eventFormState - self.eventDetailsState = eventDetailsState - self.chatState = chatState - } - - public var alert: AlertState? - public var isConnected = true - public var isLocationAuthorized = false - public var isRequestingCurrentLocation = false - public var waitingForUpdateLocation = true - public var isLoadingPage = false - public var canLoadMorePages = true - public var isMovingChatRoom: Bool = false - - public var currentPage = 1 - public var currentAddress = "" - public var placeMark: CLPlacemark? - public var location: Location? - public var events: IdentifiedArrayOf = [] - public var myEvents: IdentifiedArrayOf = [] - public var event: EventResponse.Item? - public var conversation: ConversationResponse.Item? - - public var eventFormState: EventFormState? - public var eventDetailsState: EventDetailsState? - public var chatState: ChatState? - - public var isEventDetailsSheetPresented: Bool { eventDetailsState != nil } -} - -extension EventsState { - var view: EventView.ViewState { - EventView.ViewState( - alert: alert, isConnected: isConnected, - isLocationAuthorized: isLocationAuthorized, - waitingForUpdateLocation: waitingForUpdateLocation, - isLoadingPage: isLoadingPage, isMovingChatRoom: isMovingChatRoom, - location: location, - events: events, myEvents: myEvents, - event: event, - placeMark: placeMark, - eventFormState: eventFormState, eventDetailsState: eventDetailsState, - chatState: chatState, - conversation: conversation - ) - } -} - -// swiftlint:disable all -extension EventsState { - public static let placeholderEvents = Self( - isConnected: true, - isLocationAuthorized: true, - waitingForUpdateLocation: false, - isLoadingPage: true, - location: Location( - coordinate: CLLocationCoordinate2D( - latitude: 60.020532228306031, longitude: 30.388014239849944)), - events: [ - .init( - id: "5fbfe53675a93bda87c7cb16", name: "Cool :)", categories: "General", duration: 14400, - isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", - addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, - overlay: false, coordinates: [60.020532228306031, 30.388014239849944], createdAt: Date(), - updatedAt: Date()), - .init( - id: "5fbe8a8c8ba94be8a688324a", name: "Awesome 🤩 app", categories: "General", - duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", - addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, - overlay: false, coordinates: [60.020525506753494, 30.387988546891499], createdAt: Date(), - updatedAt: Date()), - .init( - id: "5fbea245b226053f0ece711c", name: "Bicycling 🚴🏽", categories: "LookingForAcompany", - duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", - addressName: "9к5 улица Бутлерова Saint Petersburg, Saint Petersburg", type: "Point", - sponsored: false, overlay: false, coordinates: [60.00380571585201, 30.399472870547118], - createdAt: Date(), updatedAt: Date()), - .init( - id: "5fbea245b226053f0ece711c", name: "Walk Around 🚶🏽🚶🏼‍♀️", categories: "LookingForAcompany", - imageUrl: - "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", - duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", - addressName: "188839, Первомайское, СНТ Славино-2 Поселок, 31 Первомайское Россия", - type: "Point", sponsored: false, overlay: false, - coordinates: [60.261340452875721, 29.873706166262373], createdAt: Date(), updatedAt: Date()), - ] - ) -} diff --git a/Addame/Addame/Sources/EventView/LocationManagerReducer.swift b/Addame/Addame/Sources/EventView/LocationManagerReducer.swift deleted file mode 100644 index 58b0650..0000000 --- a/Addame/Addame/Sources/EventView/LocationManagerReducer.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// locationManagerReducer.swift -// -// -// Created by Saroar Khandoker on 31.07.2021. -// - -import Combine -import ComposableArchitecture -import ComposableCoreLocation -import CoreLocation -import EventDetailsView -import EventFormView -import HttpRequest -import MapKit -import SharedModels -import SwiftUI diff --git a/Addame/Addame/Sources/FoundationExtension/SwiftUIView/View+Extension+HideRowSeparatorModifier.swift b/Addame/Addame/Sources/FoundationExtension/SwiftUIView/View+Extension+HideRowSeparatorModifier.swift deleted file mode 100644 index e963a86..0000000 --- a/Addame/Addame/Sources/FoundationExtension/SwiftUIView/View+Extension+HideRowSeparatorModifier.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// View+Extension+HideRowSeparatorModifier.swift -// AddaMeIOS -// -// Created by Saroar Khandoker on 27.10.2020. -// - -import SwiftUI - -// public struct HideRowSeparatorModifier: ViewModifier { -// -// public static let defaultListRowHeight: CGFloat = 44 -// public var insets: EdgeInsets -// public var background: Color -// -// public init(insets: EdgeInsets, background: Color) { -// self.insets = insets -// var alpha: CGFloat = 0 -// -// if #available(iOS 14.0, *) { -// Color(background).getWhite(nil, alpha: &alpha) -// } else { -// Color.clear -// } -// assert(alpha == 1, "Setting background to a non-opaque color will result in separators remaining visible.") -// self.background = background -// } -// -// public func body(content: Content) -> some View { -// content -// .padding(insets) -// .frame( -// minWidth: 0, maxWidth: .infinity, -// minHeight: Self.defaultListRowHeight, -// alignment: .leading -// ) -// .listRowInsets(EdgeInsets()) -// .background(background) -// } -// } -// -// public extension EdgeInsets { -// static let defaultListRowInsets = Self(top: 0, leading: 16, bottom: 0, trailing: 16) -// } -// -// public extension View { -// func hideRowSeparator( -// insets: EdgeInsets = .defaultListRowInsets, -// background: Color = Color(UIColor.systemBackground) -// ) -> some View { -// modifier(HideRowSeparatorModifier( -// insets: insets, -// background: background -// )) -// } -// } diff --git a/Addame/Addame/Sources/ProfileView/ProfileView.swift b/Addame/Addame/Sources/ProfileView/ProfileView.swift deleted file mode 100644 index 59aa872..0000000 --- a/Addame/Addame/Sources/ProfileView/ProfileView.swift +++ /dev/null @@ -1,348 +0,0 @@ -import AsyncImageLoder -import AuthenticationView -import ComposableArchitecture -import HttpRequest -import KeychainService -import SettingsView -import SharedModels -import SwiftUI -import SwiftUIExtension -import UserClient - -extension ProfileView { - public struct ViewState: Equatable { - public var alert: AlertState? - public var isUploadingImage: Bool = false - public var showingImagePicker = false - public var inputImage: UIImage? - public var moveToSettingsView = false - public var moveToAuthView: Bool = false - public var user = User.draff - public var isUserHaveAvatarLink: Bool = false - public var myEvents: IdentifiedArrayOf = [] - public var isLoadingPage = false - public var canLoadMorePages = true - public var currentPage = 1 - public var settingsState: SettingsState? - } - - public enum ViewAction: Equatable { - case onAppear - case alertDismissed - case isUploadingImage - case showingImagePicker - case moveToSettingsView - case settingsView(isNavigation: Bool) - - case fetchMyData - case uploadAvatar(_ image: UIImage) - case updateUserName(String, String) - case createAttachment(_ attachment: Attachment) - - case userResponse(Result) - case attacmentResponse(Result) - case event(index: EventResponse.Item.ID, action: MyEventAction) - case settings(SettingsAction) - - case resetAuthData - } -} - -public struct ProfileView: View { - @Environment(\.colorScheme) var colorScheme - let store: Store - - public init(store: Store) { - self.store = store - } - - @ViewBuilder - public var body: some View { - WithViewStore(self.store.scope(state: { $0.view }, action: ProfileAction.view)) { viewStore in - - ScrollView { - if viewStore.state.user.attachments == nil { - Image(systemName: "person.fill") - .font(.system(size: 200, weight: .medium)) - .frame(width: 450, height: 350) - .foregroundColor(Color.backgroundColor(for: self.colorScheme)) - .overlay( - ProfileImageOverlay(store: self.store) - .padding(.top, 40), - alignment: .bottomTrailing - ) - } - - if viewStore.state.user.lastAvatarURLString != nil { - AsyncImage( - urlString: viewStore.state.user.lastAvatarURLString!, - placeholder: { - HUDProgressView( - placeHolder: "Image uploading...", - show: viewStore.binding( - get: { $0.isUploadingImage }, - send: { _ in ViewAction.isUploadingImage } - ) - ) - .frame(width: 350, height: 150) - .padding(.top, 100) - .padding(.bottom, 100) - }, - image: { - Image(uiImage: $0) - .renderingMode(.original) - .resizable() - } - ) - // .redacted(reason: .placeholder) - .aspectRatio(contentMode: .fit) - .overlay( - ProfileImageOverlay(store: self.store), - alignment: .bottomTrailing - ) - } - - VStack(alignment: .leading) { - Text("My Events:") - .font(.system(size: 23, weight: .bold, design: .rounded)) - .padding(.top, 10) - .padding() - } - - Divider() - - MyEventListView(store: self.store) - - Divider() - - HStack { - Button { - viewStore.send(.resetAuthData) - // self.uvm.resetAuthData() - // self.uvm.moveToAuthView = true - } label: { - Text("Logout") - .font(.title) - .bold() - } - // .background( - // NavigationLink.init( - // destination: AuthView(authViewModel: self.avm, userViewModel: self.uvm) - // .onAppear(perform: { - // //appState.tabBarIsHidden = true - // }) - // .navigationBarTitle(String.empty) - // .navigationBarHidden(true), - // isActive: self.$uvm.moveToAuthView, - // label: {} - // ) - // ) - } - .padding(.bottom, 45) - } - .onAppear { viewStore.send(.onAppear) } - .navigationBarTitle("Profile", displayMode: .inline) - // .sheet(isPresented: self.$uvm.showingImagePicker, onDismiss: self.uvm.loadImage) { - // ImagePicker(image: self.$uvm.inputImage) - // } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - // settings - - Button { - viewStore.send(.settingsView(isNavigation: true)) - } label: { - Image(systemName: "gear") - .font(.title) - // .foregroundColor(Color("bg")) - } - .navigate( - using: store.scope( - state: \.settingsState, - action: ProfileAction.settings - ), - destination: SettingsView.init(store:), - onDismiss: { - viewStore.send(.settingsView(isNavigation: false)) - } - ) - } - } - .onAppear { - viewStore.send(.fetchMyData) - } - .background(Color(UIColor.systemBackground).edgesIgnoringSafeArea(.all)) - .alert(self.store.scope(state: { $0.alert }), dismiss: .alertDismissed) - } - } -} - -struct ProfileView_Previews: PreviewProvider { - static let environment = ProfileEnvironment( - userClient: .happyPath, - eventClient: .happyPath, - authClient: .happyPath, - attachmentClient: .happyPath, - backgroundQueue: .immediate, - mainQueue: .immediate - ) - - static let store = Store( - initialState: ProfileState.events, - reducer: profileReducer, // here i am mixing - environment: environment - ) - - static var previews: some View { - Group { - ProfileView(store: store) - - ProfileView(store: store) - .environment(\.colorScheme, .dark) - } - } -} - -public struct ProfileImageOverlay: View { - @Environment(\.colorScheme) var colorScheme - - let store: Store - - public init(store: Store) { - self.store = store - } - - public var body: some View { - WithViewStore(self.store.scope(state: { $0.view }, action: ProfileAction.view)) { viewStore in - ZStack { - if viewStore.state.isUploadingImage { - withAnimation { - HUDProgressView( - placeHolder: "Image uploading...", - show: viewStore.binding( - get: { $0.isUploadingImage }, - send: { _ in .isUploadingImage } - ) - ) - } - } - - VStack { - HStack { - Spacer() - Button( - action: { - viewStore.send(.showingImagePicker) - }, - label: { - Image(systemName: "camera") - .font(.system(size: 15, weight: .medium)) - .foregroundColor(colorScheme == .dark ? .white : .black) - .frame(width: 40, height: 40) - .background(Color.green) - .clipShape(Circle()) - .padding(.trailing, 30) - } - ) - .imageScale(.large) - .frame(width: 40, height: 40, alignment: .center) - .padding() - } - - Spacer() - - Text(viewStore.user.fullName) - .font(.title).bold() - .foregroundColor(Color.backgroundColor(for: self.colorScheme)) - } - .padding(6) - } - } - } -} - -// struct ProfileImageOverlay_Previews: PreviewProvider { -// static let environment = ProfileEnvironment( -// userClient: .happyPath, -// eventClient: .happyPath, -// authClient: .happyPath, -// attachmentClient: .happyPath, -// mainQueue: DispatchQueue.main.eraseToAnyScheduler() -// ) -// -// static let store = Store( -// initialState: ProfileState(), -// reducer: profileReducer, -// environment: ProfileEnvironment( -// userClient: .happyPath, -// eventClient: .happyPath, -// authClient: .happyPath, -// attachmentClient: .happyPath, -// mainQueue: DispatchQueue.main.eraseToAnyScheduler() -// ) -// ) -// -// static var previews: some View { -// ProfileImageOverlay(store: store) -// } -// } - -public struct MyEventListView: View { - let store: Store - - public var body: some View { - WithViewStore(self.store) { _ in - ForEachStore( - self.store.scope(state: \.myEvents, action: ProfileAction.event) - ) { eventStore in - WithViewStore(eventStore) { _ in - // Button(action: { viewStore.send(.eventTapped(eventViewStore.state)) }) { - EventRowView(store: eventStore) - // } - // .buttonStyle(PlainButtonStyle()) - } - } - } - } -} - -public struct EventRowView: View { - @Environment(\.colorScheme) var colorScheme - - public init(store: Store) { - self.store = store - } - - public let store: Store - - public var body: some View { - WithViewStore(self.store) { viewStore in - VStack(alignment: .leading) { - Text(viewStore.name) - .lineLimit(2) - .foregroundColor(colorScheme == .dark ? Color.white : Color.black) - .font(.system(size: 23, weight: .light, design: .rounded)) - .padding(10) - .padding(.leading, 10) - - Text(viewStore.addressName) - .lineLimit(2) - .font(.system(size: 15, weight: .light, design: .rounded)) - .foregroundColor(.blue) - .padding([.leading, .bottom], 20) - } - .frame(maxWidth: .infinity, alignment: .leading) - .background( - RoundedRectangle(cornerRadius: 10) - .foregroundColor( - colorScheme == .dark - ? Color( - #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260520637, alpha: 1)) - : Color( - #colorLiteral( - red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 0.5))) - ) - .padding(10) - } - } -} diff --git a/Addame/Addame/Sources/SettingsView/SettingsView.swift b/Addame/Addame/Sources/SettingsView/SettingsView.swift deleted file mode 100644 index 70f8323..0000000 --- a/Addame/Addame/Sources/SettingsView/SettingsView.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// SwiftUIView.swift -// -// -// Created by Saroar Khandoker on 09.04.2021. -// - -import ComposableArchitecture -import KeychainService -import SwiftUI -import UserNotificationClient - -extension SettingsView { - public struct ViewState: Equatable { - public var alert: AlertState? - public var userNotificationSettings: UserNotificationClient.Notification.Settings? - public var userSettings: UserSettings - public var distance: DistanceState - } - - public enum ViewAction: Equatable { - case leaveUsAReviewButtonTapped - case onAppear - case onDismiss - case distanceView(DistanceAction) - } -} - -public struct SettingsView: View { - let store: Store - - public init(store: Store) { - self.store = store - } - - public var body: some View { - WithViewStore( - self.store.scope( - state: { $0.view }, - action: SettingsAction.view - ) - ) { _ in - VStack(alignment: .leading, spacing: 20) { - Text("Settings") - .font(.title) - .bold() - .padding() - - // Toggle(isOn: - // viewStore.binding( - // get: \.distanceTypeToggleisOn, - // send: ViewAction.distanceTypeToggleChanged - // ) - // ) { - // Text("Remote Notifications") - // .font(.system(.title2, design: .rounded)) - // .bold() - // .foregroundColor(viewStore.distanceTypeToggleisOn == true ? .green : .gray) - // } - // .padding() - - DistanceFilterView( - store: self.store.scope( - state: \.distance, - action: SettingsAction.distanceView - ) - ) - .padding([.top, .bottom], 20) - .transition(.opacity) - - HStack { - Spacer() - Button( - action: { - // showingTermsSheet = true - }, - label: { - Text("Terms") - .font(.title) - .bold() - .foregroundColor(.blue) - .padding() - }) - // .sheet(isPresented: $showingTermsSheet) { - // TermsAndPrivacyWebView(urlString: "" + "/terms") - // EnvironmentKeys.rootURL.absoluteString - // } - - Text("&") - .font(.title3) - .bold() - .padding([.leading, .trailing], 10) - .foregroundColor(Color(UIColor.systemBackground)) - - Button( - action: { - // showingPrivacySheet = true - }, - label: { - Text("Privacy") - .font(.title) - .bold() - .foregroundColor(.blue) - .padding() - }) - // .sheet(isPresented: $showingPrivacySheet) { - // TermsAndPrivacyWebView(urlString: "" + "/privacy") //EnvironmentKeys.rootURL.absoluteString - // } - - Spacer() - } - // .frame(width: .infinity, height: 100, alignment: .center) - .background(Color.yellow) - .clipShape(RoundedRectangle(cornerRadius: 13, style: .continuous)) - .padding() - - Spacer() - } - } - .background(Color(UIColor.systemBackground).edgesIgnoringSafeArea(.all)) - } -} - -struct SettingsView_Previews: PreviewProvider { - static let env = SettingsEnvironment( - applicationClient: .noop, - backgroundQueue: .immediate, - mainQueue: .immediate, - userDefaults: .noop, - userNotifications: .noop - ) - - static let store = Store( - initialState: SettingsState.settingsSatate, - reducer: settingsReducer, - environment: env - ) - - static var previews: some View { - Group { - SettingsView(store: store) - SettingsView(store: store) - .environment(\.colorScheme, .dark) - } - } -} diff --git a/Addame/Addame/Sources/SwiftUIExtension/NavigationLink+Store.swift b/Addame/Addame/Sources/SwiftUIExtension/NavigationLink+Store.swift deleted file mode 100644 index 16c0ba9..0000000 --- a/Addame/Addame/Sources/SwiftUIExtension/NavigationLink+Store.swift +++ /dev/null @@ -1,6 +0,0 @@ -// -// NavigationLink+Store.swift -// -// -// Created by Saroar Khandoker on 16.04.2021. -// diff --git a/Addame/Addame/Sources/TabsView/Tabs.swift b/Addame/Addame/Sources/TabsView/Tabs.swift deleted file mode 100644 index 165934e..0000000 --- a/Addame/Addame/Sources/TabsView/Tabs.swift +++ /dev/null @@ -1,9 +0,0 @@ -public enum Tabs: Int, CaseIterable, Equatable { - case event - case conversation - case profile -} - -extension Tabs: Identifiable { - public var id: Int { rawValue } -} diff --git a/Addame/Addame/Sources/TabsView/TabsAction.swift b/Addame/Addame/Sources/TabsView/TabsAction.swift deleted file mode 100644 index c2faa36..0000000 --- a/Addame/Addame/Sources/TabsView/TabsAction.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// TabsAction.swift -// -// -// Created by Saroar Khandoker on 05.04.2021. -// - -import ConversationsView -import EventView -import Foundation -import HttpRequest -import ProfileView -import WebSocketClient - -public enum TabsAction: Equatable { - case onAppear - case didSelectTab(Tabs) - case event(EventsAction) - case conversation(ConversationsAction) - case profile(ProfileAction) - - case webSocket(WebSocketClient.Action) - case getAccessToketFromKeyChain(Result) - case receivedSocketMessage(Result) - case sendResponse(NSError?) -} diff --git a/Addame/Addame/Sources/TabsView/TabsState.swift b/Addame/Addame/Sources/TabsView/TabsState.swift deleted file mode 100644 index de3fd38..0000000 --- a/Addame/Addame/Sources/TabsView/TabsState.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// TabsState.swift -// -// -// Created by Saroar Khandoker on 06.04.2021. -// - -import ConversationsView -import EventView -import ProfileView - -public struct TabsState: Equatable { - public init( - selectedTab: Tabs, - event: EventsState, - conversations: ConversationsState, - profile: ProfileState - ) { - self.selectedTab = selectedTab - self.event = event - self.conversations = conversations - self.profile = profile - } - - public var selectedTab: Tabs - public var event: EventsState - public var conversations: ConversationsState - public var profile: ProfileState -} - -struct TabsViewState: Equatable { - public init( - selectedTab: Tabs, event: EventsState, conversations: ConversationsState, profile: ProfileState - ) { - self.selectedTab = selectedTab - self.event = event - self.conversations = conversations - self.profile = profile - } - - public var selectedTab: Tabs - public var event: EventsState - public var conversations: ConversationsState - public var profile: ProfileState -} diff --git a/Addame/Addame/Sources/TabsView/TabsView.swift b/Addame/Addame/Sources/TabsView/TabsView.swift deleted file mode 100644 index 9c9ed7e..0000000 --- a/Addame/Addame/Sources/TabsView/TabsView.swift +++ /dev/null @@ -1,151 +0,0 @@ -// -// TabsView.swift -// -// -// Created by Saroar Khandoker on 06.04.2021. -// - -import ComposableArchitecture -import ConversationsView -import EventView -import ProfileView -import SwiftUI - -public struct TabsView: View { - @AppStorage("isUserFirstNameEmpty") - public var isUserFirstNameEmpty: Bool = true - @Environment(\.colorScheme) var colorScheme - - struct ViewState: Equatable { - public init(state: TabsState) { - selectedTab = state.selectedTab - event = state.event - conversations = state.conversations - profile = state.profile - } - - public var selectedTab: Tabs - public var event: EventsState - public var conversations: ConversationsState - public var profile: ProfileState - } - - let store: Store - - public init(store: Store) { - self.store = store - } - - public var body: some View { - WithViewStore(self.store.scope(state: ViewState.init)) { viewStore in - TabView( - selection: viewStore.binding( - get: \.selectedTab, - send: TabsAction.didSelectTab - ) - ) { - ForEach( - Tabs.allCases, content: tabView(_:) - ) - } - .onAppear { - ViewStore(store.stateless).send(.onAppear) - } - } - } - - private func tabView(_ tabs: Tabs) -> some View { - view(for: tabs) - .tabItem { - Image(systemName: image(for: tabs)) - Text(title(for: tabs)) - } - .tag(tabs) - } - - private func title(for tab: Tabs) -> String { - switch tab { - case .event: return "Events" - case .conversation: return "Chat" - case .profile: return "Profile" - } - } - - private func image(for tab: Tabs) -> String { - switch tab { - case .event: return "list.bullet.below.rectangle" - case .conversation: return "bubble.left.and.bubble.right" - case .profile: return "person" - } - } - - @ViewBuilder - private func view(for tabs: Tabs) -> some View { - switch tabs { - case .event: - NavigationView { - EventView( - store: store.scope( - state: \.event, - action: TabsAction.event - )) - } - .onAppear { - ViewStore(store.stateless).send(.event(.onAppear)) - } - .navigationViewStyle(StackNavigationViewStyle()) - - case .conversation: - NavigationView { - ConversationsView( - store: store.scope( - state: \.conversations, - action: TabsAction.conversation - )) - } - .onAppear { - ViewStore(store.stateless).send(.conversation(.onAppear)) - } - .navigationViewStyle(StackNavigationViewStyle()) - - case .profile: - - NavigationView { - ProfileView( - store: store.scope( - state: \.profile, - action: TabsAction.profile - )) - } - .onAppear { - ViewStore(store.stateless).send(.profile(.fetchMyData)) - } - .navigationViewStyle(StackNavigationViewStyle()) - } - } -} - -struct TabsView_Previews: PreviewProvider { - static let tabsEnv = TabsEnvironment( - backgroundQueue: .immediate, - mainQueue: .immediate, - webSocketClient: .live - ) - - static let tabsState = TabsState( - selectedTab: .event, - event: EventsState.placeholderEvents, - conversations: ConversationsState.placholderConversations, - profile: ProfileState() - ) - - static let store = Store( - initialState: tabsState, - reducer: tabsReducer, - environment: tabsEnv - ) - - static var previews: some View { - TabsView(store: store) - } -} diff --git a/Addame/Configs/DevelopmentCopy.xcconfig b/Addame/Configs/DevelopmentCI.xcconfig similarity index 78% rename from Addame/Configs/DevelopmentCopy.xcconfig rename to Addame/Configs/DevelopmentCI.xcconfig index c30f142..64fc657 100644 --- a/Addame/Configs/DevelopmentCopy.xcconfig +++ b/Addame/Configs/DevelopmentCI.xcconfig @@ -9,8 +9,8 @@ // https://help.apple.com/xcode/#/dev745c5c974 // Server URL -ROOT_URL = http:/$()/ip:port/v1 -WEB_SOCKET_URL = ws:/$()/ip:port/v1/chat +ROOT_URL = http:/$()/localhost:8080/v1 +WEB_SOCKET_URL = ws:/$()/localhost:6060/v1/chat // Image Uploading to DigitalOcen ACCESS_KEY_ID = value diff --git a/Addame/Configs/ProductionCopy.xcconfig b/Addame/Configs/ProductionCI.xcconfig similarity index 100% rename from Addame/Configs/ProductionCopy.xcconfig rename to Addame/Configs/ProductionCI.xcconfig diff --git a/Addame/Info.plist b/Addame/Info.plist index da5af76..917e7b1 100644 --- a/Addame/Info.plist +++ b/Addame/Info.plist @@ -19,9 +19,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.1.0 + $(MARKETING_VERSION) CFBundleVersion - 2 + $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS NSAppTransportSecurity @@ -35,6 +35,8 @@ We dont share your location with anyone, with share your locatuon you can create and see other user events/hangouts nearby you and other user can see your. NSLocationWhenInUseUsageDescription We dont share your location with anyone, with share your locatuon you can create and see other user events/hangouts nearby you and other user can see your. + NSUserTrackingUsageDescription + Without track your data we cant show current user event which is main feature of our App and we dont send any 3rd party your data. ROOT_URL $(ROOT_URL) SECRET_ACCESS_KEY diff --git a/Addame/Addame/.gitignore b/AddameSPM/.gitignore similarity index 100% rename from Addame/Addame/.gitignore rename to AddameSPM/.gitignore diff --git a/Addame/Addame/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AddameSPM/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from Addame/Addame/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to AddameSPM/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/AppFeature.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AppFeature.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/AppFeature.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AppFeature.xcscheme diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/AppFeatureTests.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AppFeatureTests.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/AppFeatureTests.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AppFeatureTests.xcscheme diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AttachmentClient.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AttachmentClient.xcscheme new file mode 100644 index 0000000..cfa2ade --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AttachmentClient.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AuthenticationView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AuthenticationView.xcscheme new file mode 100644 index 0000000..fa4540d --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AuthenticationView.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/ChatView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ChatView.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/ChatView.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ChatView.xcscheme diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/EventFormView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/Event.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/EventFormView.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/Event.xcscheme diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClient.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClient.xcscheme new file mode 100644 index 0000000..8af941a --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClient.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClientLive.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClientLive.xcscheme new file mode 100644 index 0000000..5dc7688 --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClientLive.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormView.xcscheme new file mode 100644 index 0000000..38f368f --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormView.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/EventFormViewTests.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormViewTests.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/EventFormViewTests.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormViewTests.xcscheme diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventView.xcscheme new file mode 100644 index 0000000..3021961 --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventView.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventViewTests.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventViewTests.xcscheme new file mode 100644 index 0000000..1025b63 --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventViewTests.xcscheme @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/KeychainService.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/KeychainService.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/KeychainService.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/KeychainService.xcscheme diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/PathMonitorClient.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/PathMonitorClient.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/PathMonitorClient.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/PathMonitorClient.xcscheme diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ProfileView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ProfileView.xcscheme new file mode 100644 index 0000000..e90364e --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ProfileView.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SettingsView.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SettingsView.xcscheme new file mode 100644 index 0000000..7ae9e3e --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SettingsView.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SharedModels.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SharedModels.xcscheme new file mode 100644 index 0000000..d0f4c62 --- /dev/null +++ b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SharedModels.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIExtension.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIExtension.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIExtension.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIExtension.xcscheme diff --git a/Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIHelpers.xcscheme b/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIHelpers.xcscheme similarity index 100% rename from Addame/Addame/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIHelpers.xcscheme rename to AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIHelpers.xcscheme diff --git a/Addame/Addame/Package.resolved b/AddameSPM/Package.resolved similarity index 92% rename from Addame/Addame/Package.resolved rename to AddameSPM/Package.resolved index 9540518..219e9b4 100644 --- a/Addame/Addame/Package.resolved +++ b/AddameSPM/Package.resolved @@ -105,8 +105,17 @@ "repositoryURL": "https://github.com/pointfreeco/swift-composable-architecture.git", "state": { "branch": null, - "revision": "96cdc7e38e2d1d89b95b0ad80c914eb369476c4b", - "version": "0.24.0" + "revision": "e2795c1789c8f44fe62301892d585e44772ff880", + "version": "0.27.0" + } + }, + { + "package": "swift-custom-dump", + "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump", + "state": { + "branch": null, + "revision": "8655495733d8c712db8d9078f47d17f3555db79f", + "version": "0.1.2" } }, { diff --git a/Addame/Addame/Package.swift b/AddameSPM/Package.swift similarity index 74% rename from Addame/Addame/Package.swift rename to AddameSPM/Package.swift index 9aebeb4..5cb768e 100644 --- a/Addame/Addame/Package.swift +++ b/AddameSPM/Package.swift @@ -6,7 +6,7 @@ import PackageDescription // swiftlint:disable file_length let package = Package( - name: "Addame", + name: "AddameSPM", platforms: [ .macOS(.v10_15), .iOS(.v14) @@ -47,6 +47,8 @@ let package = Package( .library(name: "WebSocketClient", targets: ["WebSocketClient"]), .library(name: "WebSocketClientLive", targets: ["WebSocketClientLive"]), .library(name: "LocationSearchClient", targets: ["LocationSearchClient"]), + .library(name: "IDFAClient", targets: ["IDFAClient"]), + .library(name: "IDFAClientLive", targets: ["IDFAClientLive"]), // Views .library(name: "AuthenticationView", targets: ["AuthenticationView"]), @@ -63,22 +65,24 @@ let package = Package( // Helpers .library(name: "NotificationHelpers", targets: ["NotificationHelpers"]), - .library(name: "SwiftUIHelpers", targets: ["SwiftUIHelpers"]), .library(name: "CombineHelpers", targets: ["CombineHelpers"]), - .library(name: "ComposableArchitectureHelpers", targets: ["ComposableArchitectureHelpers"]) + .library(name: "ComposableArchitectureHelpers", targets: ["ComposableArchitectureHelpers"]), + .library(name: "ImagePicker", targets: ["ImagePicker"]) ], dependencies: [ - .package( - name: "AWSSDKSwift", url: "https://github.com/swift-aws/aws-sdk-swift.git", from: "4.9.0"), +// .package(name: "AWSSDKSwift", url: "https://github.com/swift-aws/aws-sdk-swift.git", from: "4.9.0"), + .package(url: "https://github.com/soto-project/soto.git", from: "5.13.1"), .package(url: "https://github.com/marmelroy/PhoneNumberKit", .upToNextMajor(from: "3.3.3")), .package( - url: "https://github.com/pointfreeco/swift-composable-architecture.git", from: "0.25.1"), - .package(url: "https://github.com/pointfreeco/composable-core-location", from: "0.1.0"), + url: "https://github.com/pointfreeco/swift-composable-architecture.git", from: "0.36.0"), + .package(url: "https://github.com/pointfreeco/composable-core-location.git", .branch("main")), .package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "0.1.0"), .package(url: "https://github.com/AddaMeSPB/CombineContacts.git", from: "1.0.0"), - .package(url: "https://github.com/AddaMeSPB/HttpRequest.git", from: "2.2.0") +// .package(path: "../../HTTPRequestKit"), + .package(url: "https://github.com/AddaMeSPB/HTTPRequestKit.git", from: "3.0.0"), + .package(url: "https://github.com/darrarski/swift-composable-presentation.git", from: "0.3.0") ], targets: [ @@ -87,11 +91,11 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), "UserNotificationClient", "RemoteNotificationsClient", "NotificationHelpers", - "AuthClient", "AuthClientLive", "AttachmentClient", "ChatClient", "ContactClient", + "AuthClient", "AuthClientLive", "AttachmentClient", "ChatClient", "ConversationClient", "EventClient", "UserClient", "WebSocketClient", - - "EventView", "ConversationsView", "ProfileView", "TabsView", "AuthenticationView", - "SettingsView" + "EventView", "ConversationsView", "ProfileView", "TabsView", + "AuthenticationView", "SettingsView", "ContactClient", "UserDefaultsClient", + "KeychainService" ] ), @@ -163,9 +167,10 @@ let package = Package( .target( name: "AttachmentClient", dependencies: [ - .product(name: "S3", package: "AWSSDKSwift"), +// .product(name: "S3", package: "AWSSDKSwift"), + .product(name: "SotoS3", package: "soto"), "SharedModels", "KeychainService", "FoundationExtension", - "HttpRequest", "InfoPlist" + "HTTPRequestKit", "InfoPlist" ] ), .target(name: "AttachmentClientLive", dependencies: ["AttachmentClient"]), @@ -174,7 +179,7 @@ let package = Package( name: "AuthClient", dependencies: [ "SharedModels", "InfoPlist", "FoundationExtension", - "HttpRequest", "PhoneNumberKit" + "HTTPRequestKit", "PhoneNumberKit" ] ), .target(name: "AuthClientLive", dependencies: ["AuthClient"]), @@ -182,7 +187,7 @@ let package = Package( .target( name: "ChatClient", dependencies: [ - "SharedModels", "FoundationExtension", "HttpRequest", + "SharedModels", "FoundationExtension", "HTTPRequestKit", "InfoPlist", "KeychainService" ] ), @@ -192,17 +197,28 @@ let package = Package( name: "ContactClient", dependencies: [ "SharedModels", "InfoPlist", "FoundationExtension", - "HttpRequest", "PhoneNumberKit", "CombineContacts" + "HTTPRequestKit", "PhoneNumberKit", "CombineContacts" ] ), .target( name: "ContactClientLive", dependencies: ["ContactClient", "CoreDataStore"] ), - + .target( + name: "IDFAClient", + dependencies: [ + .product(name: "ComposableArchitecture", package: "swift-composable-architecture") + ] + ), + .target( + name: "IDFAClientLive", + dependencies: [ + .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), + "IDFAClient" + ]), .target( name: "ConversationClient", - dependencies: ["FoundationExtension", "HttpRequest", "SharedModels"] + dependencies: ["FoundationExtension", "HTTPRequestKit", "SharedModels"] ), .target( name: "ConversationClientLive", @@ -211,7 +227,7 @@ let package = Package( .target( name: "EventClient", - dependencies: ["SharedModels", "HttpRequest", "InfoPlist"] + dependencies: ["SharedModels", "HTTPRequestKit", "InfoPlist"] ), .target( name: "EventClientLive", @@ -223,7 +239,7 @@ let package = Package( .target( name: "UserClient", - dependencies: ["SharedModels", "HttpRequest", "KeychainService", "InfoPlist"] + dependencies: ["SharedModels", "HTTPRequestKit", "KeychainService", "InfoPlist"] ), .target(name: "UserClientLive", dependencies: ["UserClient"]), @@ -231,7 +247,7 @@ let package = Package( name: "WebSocketClient", dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), - "FoundationExtension", "HttpRequest", "SharedModels", "InfoPlist", "KeychainService" + "FoundationExtension", "HTTPRequestKit", "SharedModels", "InfoPlist", "KeychainService" ] ), .target( @@ -255,7 +271,18 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), "PhoneNumberKit", "SharedModels", "AuthClient", "KeychainService", - "HttpRequest", "AuthClientLive" + "HTTPRequestKit", "AuthClientLive", "UserDefaultsClient" + ], + resources: [ + .process("Resources/PhoneNumberMetadata.json") + ] + ), + .testTarget( + name: "AuthenticationViewTests", + dependencies: [ + "AuthenticationView", + "PhoneNumberKit", "SharedModels", "AuthClient", "KeychainService", + "HTTPRequestKit", "AuthClientLive" ] ), @@ -279,7 +306,7 @@ let package = Package( "SharedModels", "InfoPlist", "KeychainService", "WebSocketClient", "ConversationClient", "ChatClient", "SwiftUIExtension", "FoundationExtension", "AsyncImageLoder", - "HttpRequest", "ChatClientLive", "ConversationClientLive", + "HTTPRequestKit", "ChatClientLive", "ConversationClientLive", "WebSocketClientLive" ] ), @@ -288,10 +315,11 @@ let package = Package( name: "ConversationsView", dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "SharedModels", "InfoPlist", "KeychainService", "WebSocketClient", "ChatClient", "ChatClientLive", "SwiftUIExtension", "FoundationExtension", "AsyncImageLoder", - "HttpRequest", "ConversationClient", "ConversationClientLive", + "HTTPRequestKit", "ConversationClient", "ConversationClientLive", "WebSocketClientLive", "ChatView", "ComposableArchitectureHelpers", "ContactClient", "ContactClientLive", "ContactsView", "CoreDataClient" ] @@ -301,7 +329,8 @@ let package = Package( name: "ContactsView", dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), - "SharedModels", "AsyncImageLoder", "HttpRequest", + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), + "SharedModels", "AsyncImageLoder", "HTTPRequestKit", "ContactClient", "ContactClientLive", "WebSocketClient", "WebSocketClientLive", "ChatClient", "ChatClientLive", "CoreDataStore", "CoreDataClient", @@ -314,12 +343,26 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "ComposableCoreLocation", package: "composable-core-location"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "SharedModels", "EventClient", "InfoPlist", "EventFormView", "PathMonitorClient", "WebSocketClient", "WebSocketClientLive", "SwiftUIExtension", "FoundationExtension", "AsyncImageLoder", - "HttpRequest", "KeychainService", "ChatClient", "ChatView", - "PathMonitorClientLive", "EventClientLive", "ComposableArchitectureHelpers", + "HTTPRequestKit", "KeychainService", "ChatClient", "ChatView", + "PathMonitorClientLive", "EventClientLive", "EventDetailsView", "ConversationClient", "ConversationClientLive", + "UserDefaultsClient", "ComposableArchitectureHelpers", + "IDFAClient", "IDFAClientLive" + ] + ), + .testTarget( + name: "EventViewTests", + dependencies: [ + "EventView", + "HTTPRequestKit", + "KeychainService", + "SharedModels", + "PathMonitorClient", + "PathMonitorClientLive", "UserDefaultsClient" ] ), @@ -329,18 +372,19 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "ComposableCoreLocation", package: "composable-core-location"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "SharedModels", "EventClient", "InfoPlist", - "PathMonitorClient", "ConversationClient", "ComposableArchitectureHelpers", + "PathMonitorClient", "ConversationClient", "SwiftUIExtension", "FoundationExtension", "AsyncImageLoder", - "HttpRequest", "KeychainService", "ChatClient", "EventClientLive", - "PathMonitorClientLive", "MapView" + "HTTPRequestKit", "KeychainService", "ChatClient", "EventClientLive", + "PathMonitorClientLive", "MapView", "ComposableArchitectureHelpers" ] ), .testTarget( name: "EventFormViewTests", dependencies: [ "EventFormView", - "HttpRequest", + "HTTPRequestKit", "KeychainService", "SharedModels" ] @@ -351,12 +395,12 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "ComposableCoreLocation", package: "composable-core-location"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "SharedModels", "EventClient", "InfoPlist", - "PathMonitorClient", "ConversationClient", - "SwiftUIExtension", "FoundationExtension", "AsyncImageLoder", - "HttpRequest", "KeychainService", "ChatClient", - "PathMonitorClientLive", "ComposableArchitectureHelpers", "MapView", - "ConversationClientLive", "ChatView" + "AsyncImageLoder", "SwiftUIExtension", "FoundationExtension", + "HTTPRequestKit", "KeychainService", "ChatClient", + "PathMonitorClient", "PathMonitorClientLive", "MapView", "ChatView", + "ConversationClient", "ConversationClientLive", "ComposableArchitectureHelpers" ] ), @@ -364,13 +408,16 @@ let package = Package( name: "ProfileView", dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "AuthClient", "EventClient", "AttachmentClient", "InfoPlist", "UserClient", "SharedModels", "SwiftUIExtension", "FoundationExtension", "AsyncImageLoder", - "HttpRequest", "KeychainService", "AuthenticationView", + "HTTPRequestKit", "KeychainService", "AuthenticationView", "AttachmentClientLive", "AuthClientLive", "UserClientLive", - "EventClientLive", "SettingsView", "ComposableArchitectureHelpers" + "EventClientLive", "SettingsView", "ComposableArchitectureHelpers", + "ImagePicker" ] + // resources: [.process("Images")] ), .target( @@ -378,8 +425,9 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "UserNotificationClient", "UIApplicationClient", "UserDefaultsClient", - "KeychainService" + "KeychainService", "SharedModels", "AuthenticationView" ] ), @@ -388,6 +436,7 @@ let package = Package( dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture"), .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), + .product(name: "ComposablePresentation", package: "swift-composable-presentation"), "SwiftUIExtension", "SharedModels", "ComposableArchitectureHelpers" ] ), @@ -405,13 +454,19 @@ let package = Package( ] ), - .target(name: "SwiftUIHelpers"), .target(name: "CombineHelpers"), .target( name: "ComposableArchitectureHelpers", dependencies: [ .product(name: "ComposableArchitecture", package: "swift-composable-architecture") ] + ), + + .target( + name: "ImagePicker", + dependencies: [ + .product(name: "ComposableArchitecture", package: "swift-composable-architecture") + ] ) ] ) diff --git a/Addame/Addame/README.md b/AddameSPM/README.md similarity index 100% rename from Addame/Addame/README.md rename to AddameSPM/README.md diff --git a/AddameSPM/Sources/AppFeature/AppView.swift b/AddameSPM/Sources/AppFeature/AppView.swift new file mode 100644 index 0000000..c1ad382 --- /dev/null +++ b/AddameSPM/Sources/AppFeature/AppView.swift @@ -0,0 +1,147 @@ +// +// AppView.swift +// +// +// Created by Saroar Khandoker on 05.05.2021. +// + +import AuthClient +import AuthClientLive +import AuthenticationView +import ComposableArchitecture +import ConversationsView +import EventView +import ProfileView +import SwiftUI +import TabsView +import UserDefaultsClient +import KeychainService +import SharedModels + +public enum AppState: Equatable { + case login(LoginState) + case tabs(TabsViewState) + + public init() { self = .login(.init()) } +} + +public enum AppAction: Equatable { + case onAppear + case login(LoginAction) + case tabs(TabsAction) + case logout +} + +public struct AppEnvironment { + public var authenticationClient: AuthClient + public var userDefaults: UserDefaultsClient + public var mainQueue: AnySchedulerOf + + public init( + authenticationClient: AuthClient, + userDefaults: UserDefaultsClient, + mainQueue: AnySchedulerOf + ) { + self.authenticationClient = authenticationClient + self.userDefaults = userDefaults + self.mainQueue = mainQueue + } +} + +extension AppEnvironment { + public static let live: AppEnvironment = .init( + authenticationClient: .live(api: .build), + userDefaults: .live(), + mainQueue: .main + ) +} + +public let appReducer = Reducer.combine( + loginReducer.pullback( + state: /AppState.login, + action: /AppAction.login, + environment: { _ in AuthenticationEnvironment.live } + ), + tabsReducer.pullback( + state: /AppState.tabs, + action: /AppAction.tabs, + environment: { _ in TabsEnvironment.live } + ), + Reducer { state, action, environment in + + switch action { + case .onAppear: + + // this code move to login and remove onApper + if environment.userDefaults.boolForKey(AppUserDefaults.Key.isAuthorized.rawValue) == true { + state = .tabs( + .init( + selectedTab: .event, + event: EventsState(), + conversations: ConversationsState(), + profile: ProfileState() + ) + ) + } + return .none + + case let .login(.verificationResponse(.success(loginRes))): +// where environment.userDefaults.boolForKey(AppUserDefaults.Key.isAuthorized.rawValue): + + state = .tabs( + .init( + selectedTab: .event, + event: EventsState(), + conversations: ConversationsState(), + profile: ProfileState() + ) + ) + return .none + + case .login: + return .none + + case let .tabs(.profile(.settings(.isLogoutButton(tapped: tapped)))) where tapped: + KeychainService.save(codable: User?.none, for: .user) + KeychainService.save(codable: AuthResponse?.none, for: .token) + KeychainService.logout() + AppUserDefaults.erase() + + state = .login(.init()) + return environment + .userDefaults + .remove(AppUserDefaults.Key.isAuthorized.rawValue) + .fireAndForget() + + case .tabs: + return .none + + case .logout: + return .none + } + } +) + +public struct AppView: View { + + @Environment(\.scenePhase) private var scenePhase + let store: Store + + public init(store: Store) { + self.store = store + } + + public var body: some View { + SwitchStore(self.store) { + CaseLet(state: /AppState.login, action: AppAction.login) { store in + AuthenticationView(store: store) + } + CaseLet(state: /AppState.tabs, action: AppAction.tabs) { store in + TabsView(store: store) + } + } + .onAppear { + ViewStore(store.stateless).send(.onAppear) + } + } +} diff --git a/Addame/Addame/Sources/AsyncImageLoder/AssetExtractor.swift b/AddameSPM/Sources/AsyncImageLoder/AssetExtractor.swift similarity index 100% rename from Addame/Addame/Sources/AsyncImageLoder/AssetExtractor.swift rename to AddameSPM/Sources/AsyncImageLoder/AssetExtractor.swift diff --git a/Addame/Addame/Sources/AsyncImageLoder/AsyncImage.swift b/AddameSPM/Sources/AsyncImageLoder/AsyncImage.swift similarity index 100% rename from Addame/Addame/Sources/AsyncImageLoder/AsyncImage.swift rename to AddameSPM/Sources/AsyncImageLoder/AsyncImage.swift diff --git a/Addame/Addame/Sources/AsyncImageLoder/AsyncImageLoder.swift b/AddameSPM/Sources/AsyncImageLoder/AsyncImageLoder.swift similarity index 100% rename from Addame/Addame/Sources/AsyncImageLoder/AsyncImageLoder.swift rename to AddameSPM/Sources/AsyncImageLoder/AsyncImageLoder.swift diff --git a/Addame/Addame/Sources/AsyncImageLoder/EnvironmentValues.swift b/AddameSPM/Sources/AsyncImageLoder/EnvironmentValues.swift similarity index 100% rename from Addame/Addame/Sources/AsyncImageLoder/EnvironmentValues.swift rename to AddameSPM/Sources/AsyncImageLoder/EnvironmentValues.swift diff --git a/Addame/Addame/Sources/AsyncImageLoder/ImageDraw.swift b/AddameSPM/Sources/AsyncImageLoder/ImageDraw.swift similarity index 100% rename from Addame/Addame/Sources/AsyncImageLoder/ImageDraw.swift rename to AddameSPM/Sources/AsyncImageLoder/ImageDraw.swift diff --git a/AddameSPM/Sources/AsyncImageLoder/ImagePicker.swift b/AddameSPM/Sources/AsyncImageLoder/ImagePicker.swift new file mode 100644 index 0000000..1b72bc2 --- /dev/null +++ b/AddameSPM/Sources/AsyncImageLoder/ImagePicker.swift @@ -0,0 +1,6 @@ +// +// ImagePicker.swift +// +// +// Created by Saroar Khandoker on 26.01.2021. +// diff --git a/Addame/Addame/Sources/AsyncImageLoder/TemporaryImageCache.swift b/AddameSPM/Sources/AsyncImageLoder/TemporaryImageCache.swift similarity index 100% rename from Addame/Addame/Sources/AsyncImageLoder/TemporaryImageCache.swift rename to AddameSPM/Sources/AsyncImageLoder/TemporaryImageCache.swift diff --git a/AddameSPM/Sources/AttachmentClient/AttachmentClient.swift b/AddameSPM/Sources/AttachmentClient/AttachmentClient.swift new file mode 100644 index 0000000..960744f --- /dev/null +++ b/AddameSPM/Sources/AttachmentClient/AttachmentClient.swift @@ -0,0 +1,28 @@ +// +// AttachmentClient.swift +// +// +// Created by Saroar Khandoker on 27.01.2021. +// + +import Combine +import Foundation +import HTTPRequestKit +import SharedModels +import UIKit + +public struct AttachmentClient { + public typealias UpdateUserImageURLHandler = (Attachment, String) -> AnyPublisher + public typealias UploadImageToS3Handler = (UIImage, String?, String?) -> AnyPublisher + + public let uploadImageToS3: UploadImageToS3Handler + public let updateUserImageURL: UpdateUserImageURLHandler + + public init( + uploadImageToS3: @escaping UploadImageToS3Handler, + updateUserImageURL: @escaping UpdateUserImageURLHandler + ) { + self.uploadImageToS3 = uploadImageToS3 + self.updateUserImageURL = updateUserImageURL + } +} diff --git a/AddameSPM/Sources/AttachmentClient/AwsS3Manager.swift b/AddameSPM/Sources/AttachmentClient/AwsS3Manager.swift new file mode 100644 index 0000000..982a3f3 --- /dev/null +++ b/AddameSPM/Sources/AttachmentClient/AwsS3Manager.swift @@ -0,0 +1,102 @@ +// +// AwsS3Manager.swift +// +// +// Created by Saroar Khandoker on 27.01.2021. +// + +import AVFoundation +import FoundationExtension +import KeychainService +import NIO +import SotoS3 +import SharedModels +import UIKit +import Combine +import HTTPRequestKit +import InfoPlist + +public enum AWSS3Helper { + private static let bucket = "adda" + public static var bucketWithEndpoint = "https://adda.nyc3.digitaloceanspaces.com/" + private static let compressionQueue = OperationQueue() + + public static var getCurrentMillis: Int64 { + return Int64(Date().timeIntervalSince1970 * 1000) + } + + private static let client = AWSClient( + credentialProvider: .static( + accessKeyId: EnvironmentKeys.accessKeyId, + secretAccessKey: EnvironmentKeys.secretAccessKey + ), + httpClientProvider: .createNew + ) + + private static let awsS3 = S3( + client: client, + region: .useast1, + endpoint: "https://nyc3.digitaloceanspaces.com" + ) + + // swiftlint:disable function_body_length superfluous_disable_command + public static func uploadImage( + _ image: UIImage, + conversationId: String? = nil, + userId: String? = nil + ) -> Combine.Future { + + return Combine.Future { promise in + let data = image.compressImage(conversationId == nil ? .highest : .medium) + + let imageFormat = data.1 + guard let imageData = data.0 else { + promise(.failure(HTTPRequest.HRError.custom("Data compressImage error", .none))) + return + } + + let imageKey = buildImageKey(conversationId: conversationId, userId: userId, imageFormat: imageFormat) + + let body = AWSPayload.data(imageData) + + // Put an Object + let putObjectRequest = S3.PutObjectRequest( + acl: .publicRead, + body: body, + bucket: "adda", + contentLength: Int64(imageData.count), + key: imageKey + ) + + let futureOutput = awsS3.putObject(putObjectRequest) + + futureOutput.whenSuccess { response in + print(#line, self, response, imageKey) + let finalURL = bucketWithEndpoint + imageKey + promise(.success(finalURL)) + } + + futureOutput.whenFailure { error in + print(#line, self, error) + promise(.failure(HTTPRequest.HRError.networkError(error))) + } + } + } + + private static func buildImageKey( + conversationId: String? = nil, + userId: String? = nil, + imageFormat: String + ) -> String { + let currentTime = Int64(Date().timeIntervalSince1970 * 1000) + var imageKey = String(format: "%ld", currentTime) + if let conversationId = conversationId { + imageKey = "uploads/images/\(conversationId)/\(imageKey).\(imageFormat)" + } else if let userId = userId { + imageKey = "uploads/images/\(userId)/\(imageKey).\(imageFormat)" + } + + return imageKey + } + +} diff --git a/Addame/Addame/Sources/AttachmentClient/Mocks.swift b/AddameSPM/Sources/AttachmentClient/Mocks.swift similarity index 51% rename from Addame/Addame/Sources/AttachmentClient/Mocks.swift rename to AddameSPM/Sources/AttachmentClient/Mocks.swift index 134e23c..39ce66f 100644 --- a/Addame/Addame/Sources/AttachmentClient/Mocks.swift +++ b/AddameSPM/Sources/AttachmentClient/Mocks.swift @@ -7,25 +7,38 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels +// swiftlint:disable line_length superfluous_disable_command extension AttachmentClient { public static let empty = Self( - uploadAvatar: { _ in - Just(Attachment.draff) - .setFailureType(to: HTTPError.self) + uploadImageToS3: { _, _, _ in + Just("") + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() + }, + updateUserImageURL: { _, _ in + Just( + Attachment.draff + ) + .setFailureType(to: HTTPRequest.HRError.self) + .eraseToAnyPublisher() } ) public static let happyPath = Self( - uploadAvatar: { _ in + + uploadImageToS3: { _, _, _ in + Just("https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/5fabb05d2470c17919b3c0e2_1605792619988.jpeg") + .setFailureType(to: HTTPRequest.HRError.self) + .eraseToAnyPublisher() + }, + updateUserImageURL: { _, _ in Just( Attachment( id: "5fb6736c1432f950f8ea2d33", type: .image, userId: "5fabb05d2470c17919b3c0e2", - // swiftlint:disable line_length superfluous_disable_command imageUrlString: "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/5fabb05d2470c17919b3c0e2_1605792619988.jpeg", audioUrlString: nil, videoUrlString: nil, @@ -33,7 +46,7 @@ extension AttachmentClient { createdAt: Date(), updatedAt: Date() ) ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) diff --git a/AddameSPM/Sources/AttachmentClientLive/Live.swift b/AddameSPM/Sources/AttachmentClientLive/Live.swift new file mode 100644 index 0000000..03759c2 --- /dev/null +++ b/AddameSPM/Sources/AttachmentClientLive/Live.swift @@ -0,0 +1,180 @@ +// +// Live.swift +// +// +// Created by Saroar Khandoker on 27.01.2021. +// + +import AttachmentClient +import Combine +import Foundation +import HTTPRequestKit +import SotoS3 +import InfoPlist +import SharedModels +import KeychainService +import UIKit + +func token() -> AnyPublisher { + guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { + print(#line, "not Authorized Token are missing") + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) + .eraseToAnyPublisher() + } + + return Just(token.accessToken) + .setFailureType(to: HTTPRequest.HRError.self) + .eraseToAnyPublisher() +} + +public struct AttachmentAPI { + public static let build = Self() + + private var baseURL: URL { EnvironmentKeys.rootURL.appendingPathComponent("/attachments") } + + private static let bucket = "adda" + private var bucketWithEndpoint = "https://adda.nyc3.digitaloceanspaces.com/" + + private static let client = AWSClient( + credentialProvider: .static( + accessKeyId: EnvironmentKeys.accessKeyId, + secretAccessKey: EnvironmentKeys.secretAccessKey + ), + httpClientProvider: .createNew + ) + + private static let awsS3 = S3( + client: client, + region: .useast1, + endpoint: "https://nyc3.digitaloceanspaces.com" + ) + + fileprivate func handleDataType( + input: Input? = nil, + params: [String: Any] = [:], + queryItems: [URLQueryItem] = [] + ) -> HTTPRequest.DataType { + if !params.isEmpty { + return .query(with: params) + } else if !queryItems.isEmpty { + return .query(with: queryItems) + } else { + return .encodable(input: input, encoder: .init()) + } + } + + private func tokenHandle( + input: Input? = nil, + path: String, + method: HTTPRequest.Method, + params: [String: Any] = [:], + queryItems: [URLQueryItem] = [] + ) -> AnyPublisher { + return token().flatMap { token -> AnyPublisher in + + let builder: HTTPRequest = .build( + baseURL: baseURL, + method: method, + authType: .bearer(token: token), + path: path, + contentType: .json, + dataType: handleDataType(input: input, params: params, queryItems: queryItems) + ) + + return builder.send(scheduler: RunLoop.main) + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in + Fail(error: error).eraseToAnyPublisher() + } + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() + } + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in + Fail(error: error).eraseToAnyPublisher() + } + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() + } + + func updateUserImage(attachment: Attachment, path: String) -> AnyPublisher { + + return tokenHandle(input: attachment, path: path, method: .post) + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in + Fail(error: error).eraseToAnyPublisher() + } + .receive(on: DispatchQueue.main) + .eraseToAnyPublisher() + } + + func buildImageKey( + conversationId: String? = nil, + userId: String? = nil, + imageFormat: String + ) -> String { + let currentTime = Int64(Date().timeIntervalSince1970 * 1000) + var imageKey = String(format: "%ld", currentTime) + if let conversationId = conversationId { + imageKey = "uploads/images/\(conversationId)/\(imageKey).\(imageFormat)" + } else if let userId = userId { + imageKey = "uploads/images/\(userId)/\(imageKey).\(imageFormat)" + } + + return imageKey + } +} + +extension AttachmentAPI { + // upload image to DigitalOcen Spaces + // swiftlint:disable function_body_length superfluous_disable_command + func uploadImage( + image: UIImage, + conversationId: String? = nil, + userId: String? = nil + ) -> AnyPublisher { + + Combine.Future { promise in + + let data = image.compressImage(conversationId == nil ? .highest : .medium) + let imageFormat = data.1 + guard let imageData = data.0 else { + promise(.failure(HTTPRequest.HRError.custom("Data compressImage error", .none))) + return + } + + let imageKey = buildImageKey(conversationId: conversationId, userId: userId, imageFormat: imageFormat) + + let body = AWSPayload.data(imageData) + + // Put an Object + let putObjectRequest = S3.PutObjectRequest( + acl: .publicRead, + body: body, + bucket: "adda", + contentLength: Int64(imageData.count), + key: imageKey + ) + + let futureOutput = AttachmentAPI.awsS3.putObject(putObjectRequest) + + futureOutput.whenSuccess { response in + print(#line, self, response, imageKey) + let finalURL = bucketWithEndpoint + imageKey + promise(.success(finalURL)) + } + + futureOutput.whenFailure { error in + print(#line, self, error) + promise(.failure(HTTPRequest.HRError.networkError(error))) + } + } + .eraseToAnyPublisher() + } +} + +extension AttachmentClient { + public static func live(api: AttachmentAPI) -> Self { + .init( + uploadImageToS3: api.uploadImage(image:conversationId:userId:), + updateUserImageURL: api.updateUserImage(attachment:path:) + ) + } +} diff --git a/Addame/Addame/Sources/AuthClient/AuthClient.swift b/AddameSPM/Sources/AuthClient/AuthClient.swift similarity index 82% rename from Addame/Addame/Sources/AuthClient/AuthClient.swift rename to AddameSPM/Sources/AuthClient/AuthClient.swift index 4a34a03..e109b96 100644 --- a/Addame/Addame/Sources/AuthClient/AuthClient.swift +++ b/AddameSPM/Sources/AuthClient/AuthClient.swift @@ -1,11 +1,11 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels public struct AuthClient { - public typealias LoginHandler = (AuthResponse) -> AnyPublisher - public typealias VerificationHandler = (AuthResponse) -> AnyPublisher + public typealias LoginHandler = (AuthResponse) -> AnyPublisher + public typealias VerificationHandler = (AuthResponse) -> AnyPublisher public var login: LoginHandler public var verification: VerificationHandler diff --git a/Addame/Addame/Sources/AuthClient/Mocks.swift b/AddameSPM/Sources/AuthClient/Mocks.swift similarity index 59% rename from Addame/Addame/Sources/AuthClient/Mocks.swift rename to AddameSPM/Sources/AuthClient/Mocks.swift index 3deddc2..c07eb6b 100644 --- a/Addame/Addame/Sources/AuthClient/Mocks.swift +++ b/AddameSPM/Sources/AuthClient/Mocks.swift @@ -7,16 +7,20 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels extension AuthClient { public static let happyPath = Self( login: { _ in Just( - AuthResponse(phoneNumber: "+79218888888") + AuthResponse( + phoneNumber: "+79218888888", + attemptId: "165541EC-692E-440A-9CF8-565776E9DC99", + code: "336699" + ) ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, @@ -38,8 +42,21 @@ extension AuthClient { // KeychainService.save(codable: res.access, for: .token) // return res // } - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) + + public static let failing = Self( + login: { _ in + Fail(error: HTTPRequest.HRError.custom("Missing code", "")) + .eraseToAnyPublisher() + }, + verification: { _ in + Fail(error: HTTPRequest.HRError.custom("verification fail", "")) + .eraseToAnyPublisher() + } + ) } + +extension String: Error {} diff --git a/Addame/Addame/Sources/AuthClientLive/Live.swift b/AddameSPM/Sources/AuthClientLive/Live.swift similarity index 78% rename from Addame/Addame/Sources/AuthClientLive/Live.swift rename to AddameSPM/Sources/AuthClientLive/Live.swift index 0626f8b..b269e02 100644 --- a/Addame/Addame/Sources/AuthClientLive/Live.swift +++ b/AddameSPM/Sources/AuthClientLive/Live.swift @@ -8,7 +8,7 @@ import AuthClient import Combine import Foundation -import HttpRequest +import HTTPRequestKit import InfoPlist import SharedModels @@ -17,8 +17,8 @@ public struct AuthAPI { private var baseURL: URL { EnvironmentKeys.rootURL.appendingPathComponent("/auth/") } - public func login(input: AuthResponse) -> AnyPublisher { - let builder: HttpRequest = .build( + public func login(input: AuthResponse) -> AnyPublisher { + let builder: HTTPRequest = .build( baseURL: baseURL, method: .post, authType: .none, @@ -28,15 +28,15 @@ public struct AuthAPI { ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func verification(input: AuthResponse) -> AnyPublisher { - let builder: HttpRequest = .build( + public func verification(input: AuthResponse) -> AnyPublisher { + let builder: HTTPRequest = .build( baseURL: baseURL, method: .post, authType: .none, @@ -46,7 +46,7 @@ public struct AuthAPI { ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) diff --git a/Addame/Addame/Sources/AuthenticationView/AuthenticationCore.swift b/AddameSPM/Sources/AuthenticationView/AuthenticationCore.swift similarity index 63% rename from Addame/Addame/Sources/AuthenticationView/AuthenticationCore.swift rename to AddameSPM/Sources/AuthenticationView/AuthenticationCore.swift index 7c268ca..4aa3c81 100644 --- a/Addame/Addame/Sources/AuthenticationView/AuthenticationCore.swift +++ b/AddameSPM/Sources/AuthenticationView/AuthenticationCore.swift @@ -2,14 +2,16 @@ import AuthClient import AuthClientLive import Combine import ComposableArchitecture -import HttpRequest +import HTTPRequestKit import KeychainService import PhoneNumberKit import SharedModels import SwiftUI +import UserDefaultsClient public struct LoginState: Equatable { - public static let build = Self() + + public init() {} public static func == (lhs: LoginState, rhs: LoginState) -> Bool { return lhs.isAuthorized == rhs.isAuthorized @@ -19,38 +21,70 @@ public struct LoginState: Equatable { public var authResponse: AuthResponse = .draff public var isValidationCodeIsSend = false public var isLoginRequestInFlight = false - @AppStorage("isAuthorized") public var isAuthorized: Bool = false - @AppStorage("isUserFirstNameEmpty") public var isUserFirstNameEmpty: Bool = true + public var isAuthorized: Bool = false + public var isUserFirstNameEmpty: Bool = true public var showTermsSheet: Bool = false public var showPrivacySheet: Bool = false } public enum LoginAction: Equatable { + case onAppear case alertDismissed case showTermsSheet case showPrivacySheet case sendPhoneNumberButtonTapped(String) case verificationRequest(String) - case loninResponse(Result) - case verificationResponse(Result) + case loninResponse(Result) + case verificationResponse(Result) } public struct AuthenticationEnvironment { - public var authClient = AuthClient.live(api: .build) + public var authClient: AuthClient public var mainQueue: AnySchedulerOf + public var userDefaults: UserDefaultsClient - public init(authClient: AuthClient, mainQueue: AnySchedulerOf) { + public init( + authClient: AuthClient, + userDefaults: UserDefaultsClient, + mainQueue: AnySchedulerOf + ) { self.authClient = authClient + self.userDefaults = userDefaults self.mainQueue = mainQueue } } +extension AuthenticationEnvironment { + public static let live: AuthenticationEnvironment = .init( + authClient: .live(api: .build), + userDefaults: .live(), + mainQueue: .main + ) +} + public let loginReducer = Reducer { state, action, environment in + + var saveBoolValue: Effect { + return environment.userDefaults + .setBool(true, AppUserDefaults.Key.isAuthorized.rawValue) + .receive(on: environment.mainQueue) + .fireAndForget() + } + switch action { + + case .onAppear: + state.isAuthorized = environment.userDefaults + .boolForKey(AppUserDefaults.Key.isAuthorized.rawValue) + state.isUserFirstNameEmpty = environment.userDefaults + .boolForKey(AppUserDefaults.Key.isUserFirstNameEmpty.rawValue) + return .none + case .alertDismissed: state.alert = nil return .none + case let .sendPhoneNumberButtonTapped(phoneNumber): state.isLoginRequestInFlight = true @@ -60,7 +94,7 @@ public let loginReducer = Reducer Bool { - return lhs.isValid == rhs.isValid && lhs.phoneNumber == rhs.phoneNumber - } - - public func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - @Binding var phoneNumber: String - @Binding var isValid: Bool - - let phoneTextField = PhoneNumberTextField() - - public func makeUIView(context: Context) -> PhoneNumberTextField { - phoneTextField.withExamplePlaceholder = true - phoneTextField.withFlag = true - phoneTextField.withPrefix = true - phoneTextField.withExamplePlaceholder = true - // phoneTextField.placeholder = "Enter phone number" - phoneTextField.becomeFirstResponder() - phoneTextField.addTarget( - context.coordinator, action: #selector(Coordinator.onTextUpdate), for: .editingChanged) - return phoneTextField - } - - public func getCurrentText() { - guard let phoneText = phoneTextField.text else { - return - } - phoneNumber = phoneText - } - - public func updateUIView(_: PhoneNumberTextField, context _: Context) {} - - public class Coordinator: NSObject, UITextFieldDelegate { - var control: PhoneNumberTextFieldView - - init(_ control: PhoneNumberTextFieldView) { - self.control = control - } - - @objc func onTextUpdate(textField _: UITextField) { - control.isValid = control.phoneTextField.isValidNumber - } - } -} - public struct AuthenticationView: View { - private var baseURL: URL { URL(string: "http://0.0.0.0:8080/v1/")! } // load from info plist + @State private var phoneField: PhoneNumberTextFieldView? @State private var isValidPhoneNumber: Bool = false @State private var phoneNumber = String.empty @@ -71,13 +23,15 @@ public struct AuthenticationView: View { self.store = store } - @ViewBuilder fileprivate func inputMobileNumberTextView( + @ViewBuilder + private func inputMobileNumberTextView( _ viewStore: ViewStore ) -> some View { HStack { phoneField.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 60) .keyboardType(.phonePad) .padding(.leading) + .disabled(viewStore.isLoginRequestInFlight) Button( action: { @@ -85,18 +39,24 @@ public struct AuthenticationView: View { viewStore.send(.sendPhoneNumberButtonTapped(self.phoneNumber)) }, label: { - Text("GO") - .font(.headline) - .bold() - .padding() + if !viewStore.isLoginRequestInFlight { + Text("GO").font(.headline).bold().padding() + } else { + ProgressView() + .accentColor(Color.black) + .font(.headline) + .padding() + // color have to be black + } } ) - .disabled(!self.isValidPhoneNumber) + .disabled(!self.isValidPhoneNumber || viewStore.isLoginRequestInFlight) .foregroundColor(self.isValidPhoneNumber ? Color.black : Color.white) .background( self.isValidPhoneNumber ? Color.yellow : Color.gray ) .cornerRadius(50) + } .overlay( RoundedRectangle(cornerRadius: 30) @@ -104,7 +64,13 @@ public struct AuthenticationView: View { .foregroundColor( Color( #colorLiteral( - red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.06563035103))) + red: 0.8039215803, + green: 0.8039215803, + blue: 0.8039215803, + alpha: 0.06563035103 + ) + ) + ) ) .onAppear { self.phoneField = PhoneNumberTextFieldView( @@ -116,12 +82,7 @@ public struct AuthenticationView: View { public var body: some View { WithViewStore(self.store.scope(state: { $0.view }, action: LoginAction.view)) { viewStore in - ZStack { - if viewStore.isLoginRequestInFlight { - withAnimation { - Text("Lodaing......") - } - } + ZStack(alignment: .top) { VStack { Text("Adda") @@ -146,6 +107,7 @@ public struct AuthenticationView: View { ZStack { if !viewStore.isValidationCodeIsSend { inputMobileNumberTextView(viewStore) + .disabled(viewStore.isLoginRequestInFlight) } if viewStore.isValidationCodeIsSend { @@ -165,10 +127,11 @@ public struct AuthenticationView: View { } } - fileprivate func inputValidationCodeTextView( + @ViewBuilder + private func inputValidationCodeTextView( _ viewStore: ViewStore ) -> some View { - return VStack { + VStack { HStack { TextField( "__ __ __ __ __ __", @@ -223,7 +186,7 @@ public struct AuthenticationView: View { .showTermsSheet }) ) { - TermsAndPrivacyWebView(urlString: baseURL.appendingPathComponent("/terms").absoluteString) + // TermsAndPrivacyWebView(urlString: baseURL.appendingPathComponent("/terms").absoluteString) } Text("&") @@ -248,8 +211,7 @@ public struct AuthenticationView: View { $0.showPrivacySheet }, send: { _ -> ViewAction in .showPrivacySheet }) ) { - TermsAndPrivacyWebView( - urlString: baseURL.appendingPathComponent("/privacy").absoluteString) + // TermsAndPrivacyWebView(urlString: baseURL.appendingPathComponent("/privacy").absoluteString) } } } @@ -265,7 +227,8 @@ struct AuthenticationView_Previews: PreviewProvider { static var environment = AuthenticationEnvironment( authClient: .happyPath, - mainQueue: DispatchQueue.main.eraseToAnyScheduler() + userDefaults: .live(), + mainQueue: .main.eraseToAnyScheduler() ) static var store = Store( diff --git a/AddameSPM/Sources/AuthenticationView/PhoneNumberKit+Extension.swift b/AddameSPM/Sources/AuthenticationView/PhoneNumberKit+Extension.swift new file mode 100644 index 0000000..e72eb5a --- /dev/null +++ b/AddameSPM/Sources/AuthenticationView/PhoneNumberKit+Extension.swift @@ -0,0 +1,25 @@ +// +// PhoneNumberKit+Extension.swift +// +// +// Created by Saroar Khandoker on 06.10.2021. +// + +import Foundation +import PhoneNumberKit + +// extension PhoneNumberKit { +// +// public override convenience init() { +// self.init(metadataCallback: PhoneNumberKit.bundleMetadataCallback) +// } +// +// public static func bundleMetadataCallback() throws -> Data? { +// guard let jsonPath = Bundle.main.path(forResource: "PhoneNumberMetadata", ofType: "json") else { +// throw PhoneNumberError.metadataNotFound +// } +// let data = try Data(contentsOf: URL(fileURLWithPath: jsonPath)) +// return data +// } +// +// } diff --git a/AddameSPM/Sources/AuthenticationView/PhoneNumberTextFieldView.swift b/AddameSPM/Sources/AuthenticationView/PhoneNumberTextFieldView.swift new file mode 100644 index 0000000..7d59464 --- /dev/null +++ b/AddameSPM/Sources/AuthenticationView/PhoneNumberTextFieldView.swift @@ -0,0 +1,57 @@ +// +// PhoneNumberTextFieldView.swift +// +// +// Created by Saroar Khandoker on 15.09.2021. +// + +import PhoneNumberKit +import SwiftUI + +public struct PhoneNumberTextFieldView: UIViewRepresentable, Equatable { + public static func == (lhs: PhoneNumberTextFieldView, rhs: PhoneNumberTextFieldView) -> Bool { + return lhs.isValid == rhs.isValid && lhs.phoneNumber == rhs.phoneNumber + } + + public func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + @Binding var phoneNumber: String + @Binding var isValid: Bool + + let phoneTextField = PhoneNumberTextField() + + public func makeUIView(context: Context) -> PhoneNumberTextField { + phoneTextField.withExamplePlaceholder = true + phoneTextField.withFlag = true + phoneTextField.withPrefix = true + phoneTextField.withExamplePlaceholder = true + // phoneTextField.placeholder = "Enter phone number" + phoneTextField.becomeFirstResponder() + phoneTextField.addTarget( + context.coordinator, action: #selector(Coordinator.onTextUpdate), for: .editingChanged) + return phoneTextField + } + + public func getCurrentText() { + guard let phoneText = phoneTextField.text else { + return + } + phoneNumber = phoneText + } + + public func updateUIView(_: PhoneNumberTextField, context _: Context) {} + + public class Coordinator: NSObject, UITextFieldDelegate { + var control: PhoneNumberTextFieldView + + init(_ control: PhoneNumberTextFieldView) { + self.control = control + } + + @objc func onTextUpdate(textField _: UITextField) { + control.isValid = control.phoneTextField.isValidNumber + } + } +} diff --git a/AddameSPM/Sources/AuthenticationView/Resources/PhoneNumberMetadata.json b/AddameSPM/Sources/AuthenticationView/Resources/PhoneNumberMetadata.json new file mode 100644 index 0000000..e69246c --- /dev/null +++ b/AddameSPM/Sources/AuthenticationView/Resources/PhoneNumberMetadata.json @@ -0,0 +1 @@ +{ "phoneNumberMetadata": {"territories": {"territory": [{"internationalPrefix": "00", "id": "AC", "countryCode": "247", "generalDesc": {"nationalNumberPattern": "(?:[01589]\\d|[46])\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "62889", "nationalNumberPattern": "6[2-467]\\d{3}"}, "mobile": {"possibleLengths": {"national": "5"}, "exampleNumber": "40123", "nationalNumberPattern": "4\\d{4}"}, "uan": {"possibleLengths": {"national": "6"}, "exampleNumber": "542011", "nationalNumberPattern": "(?:0[1-9]|[1589]\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "AD", "countryCode": "376", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "[135-9]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "1", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "6", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:1|6\\d)\\d{7}|[135-9]\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "1800\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "6"}, "exampleNumber": "712345", "nationalNumberPattern": "[78]\\d{5}"}, "mobile": {"possibleLengths": {"national": "6,9"}, "exampleNumber": "312345", "nationalNumberPattern": "690\\d{6}|[356]\\d{5}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "18001234", "nationalNumberPattern": "180[02]\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "6"}, "exampleNumber": "912345", "nationalNumberPattern": "[19]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "AE", "countryCode": "971", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2,9})", "leadingDigits": "60|8", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[236]|[479][2-8]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d)(\\d{5})", "leadingDigits": "[479]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[4-7]\\d|9[0-689])\\d{7}|800\\d{2,9}|[2-4679]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "22345678", "nationalNumberPattern": "[2-4679][2-8]\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "501234567", "nationalNumberPattern": "5[024-68]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "[5-12]"}, "exampleNumber": "800123456", "nationalNumberPattern": "400\\d{6}|800\\d{2,9}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900234567", "nationalNumberPattern": "900[02]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "700012345", "nationalNumberPattern": "700[05]\\d{5}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "600212345", "nationalNumberPattern": "600[25]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "AF", "countryCode": "93", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[1-9]", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-7]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[2-7]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "234567890", "nationalNumberPattern": "(?:[25][0-8]|[34][0-4]|6[0-5])[2-9]\\d{6}"}, "mobile": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "701234567", "nationalNumberPattern": "7\\d{8}"}}, {"nationalPrefixForParsing": "1|([457]\\d{6})$", "countryCode": "1", "leadingDigits": "268", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "268$1", "internationalPrefix": "011", "id": "AG", "generalDesc": {"nationalNumberPattern": "(?:268|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2684601234", "nationalNumberPattern": "268(?:4(?:6[0-38]|84)|56[0-2])\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2684641234", "nationalNumberPattern": "268(?:464|7(?:1[3-9]|[28]\\d|3[0246]|64|7[0-689]))\\d{4}"}, "pager": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2684061234", "nationalNumberPattern": "26840[69]\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}, "voip": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2684801234", "nationalNumberPattern": "26848[01]\\d{4}"}}, {"nationalPrefixForParsing": "1|([2457]\\d{6})$", "countryCode": "1", "leadingDigits": "264", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "264$1", "internationalPrefix": "011", "id": "AI", "generalDesc": {"nationalNumberPattern": "(?:264|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2644612345", "nationalNumberPattern": "264(?:292|4(?:6[12]|9[78]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2642351234", "nationalNumberPattern": "264(?:235|4(?:69|76)|5(?:3[6-9]|8[1-4])|7(?:29|72))\\d{4}"}, "pager": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2647241234", "nationalNumberPattern": "264724\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "AL", "countryCode": "355", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "80|9", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "4[2-6]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2358][2-5]|4", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23578]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:700\\d\\d|900)\\d{3}|8\\d{5,7}|(?:[2-5]|6\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "[5-7]"}, "exampleNumber": "22345678", "nationalNumberPattern": "4505[0-2]\\d{3}|(?:[2358][16-9]\\d[2-9]|4410)\\d{4}|(?:[2358][2-5][2-9]|4(?:[2-57-9][2-9]|6\\d))\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "672123456", "nationalNumberPattern": "6(?:[78][2-9]|9\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "6"}, "exampleNumber": "900123", "nationalNumberPattern": "900[1-9]\\d\\d"}, "sharedCost": {"possibleLengths": {"national": "6"}, "exampleNumber": "808123", "nationalNumberPattern": "808[1-9]\\d\\d"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "70021234", "nationalNumberPattern": "700[2-9]\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "AM", "countryCode": "374", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "[89]0", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2|3[12]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "1|47", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3-9]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:[1-489]\\d|55|60|77)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "5,6"}, "exampleNumber": "10123456", "nationalNumberPattern": "(?:(?:1[0-25]|47)\\d|2(?:2[2-46]|3[1-8]|4[2-69]|5[2-7]|6[1-9]|8[1-7])|3[12]2)\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "77123456", "nationalNumberPattern": "(?:33|4[1349]|55|77|88|9[13-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "90[016]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80112345", "nationalNumberPattern": "80[1-4]\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "60271234", "nationalNumberPattern": "60(?:2[78]|3[5-9]|4[02-9]|5[0-46-9]|[6-8]\\d|90)\\d{4}"}}, {"internationalPrefix": "00", "id": "AO", "countryCode": "244", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[29]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[29]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "222123456", "nationalNumberPattern": "2\\d(?:[0134][25-9]|[25-9]\\d)\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "923123456", "nationalNumberPattern": "9[1-49]\\d{7}"}}, {"nationalPrefixForParsing": "0?(?:(11|2(?:2(?:02?|[13]|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:02?|1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[67])|4(?:7[3-578]|9)|6(?:[0136]|2[24-6]|4[6-8]?|5[15-8])|80|9(?:0[1-3]|[19]|2\\d|3[1-6]|4[02568]?|5[2-4]|6[2-46]|72?|8[23]?))|3(?:3(?:2[79]|6|8[2578])|4(?:0[0-24-9]|[12]|3[5-8]?|4[24-7]|5[4-68]?|6[02-9]|7[126]|8[2379]?|9[1-36-8])|5(?:1|2[1245]|3[237]?|4[1-46-9]|6[2-4]|7[1-6]|8[2-5]?)|6[24]|7(?:[069]|1[1568]|2[15]|3[145]|4[13]|5[14-8]|7[2-57]|8[126])|8(?:[01]|2[15-7]|3[2578]?|4[13-6]|5[4-8]?|6[1-357-9]|7[36-8]?|8[5-8]?|9[124])))15)?", "countryCode": "54", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "nationalPrefixTransformRule": "9$1", "internationalPrefix": "00", "id": "AR", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})", "leadingDigits": "0|1(?:0[0-35-7]|1[02-5]|2[015]|3[47]|4[478])|911", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{4})", "leadingDigits": "[1-9]", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-8]", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[1-8]", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{2})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["2(?:2[024-9]|3[0-59]|47|6[245]|9[02-8])|3(?:3[28]|4[03-9]|5[2-46-8]|7[1-578]|8[2-9])", "2(?:[23]02|6(?:[25]|4[6-8])|9(?:[02356]|4[02568]|72|8[23]))|3(?:3[28]|4(?:[04679]|3[5-8]|5[4-68]|8[2379])|5(?:[2467]|3[237]|8[2-5])|7[1-578]|8(?:[2469]|3[2578]|5[4-8]|7[36-8]|8[5-8]))|2(?:2[24-9]|3[1-59]|47)", "2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3[78]|5(?:4[46]|8)|8[2379])|5(?:[2467]|3[237]|8[23])|7[1-578]|8(?:[2469]|3[278]|5[56][46]|86[3-6]))|2(?:2[24-9]|3[1-59]|47)|38(?:[58][78]|7[378])|3(?:4[35][56]|58[45]|8(?:[38]5|54|76))[4-6]", "2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3(?:5(?:4[0-25689]|[56])|[78])|58|8[2379])|5(?:[2467]|3[237]|8(?:[23]|4(?:[45]|60)|5(?:4[0-39]|5|64)))|7[1-578]|8(?:[2469]|3[278]|54(?:4|5[13-7]|6[89])|86[3-6]))|2(?:2[24-9]|3[1-59]|47)|38(?:[58][78]|7[378])|3(?:454|85[56])[46]|3(?:4(?:36|5[56])|8(?:[38]5|76))[4-6]"], "format": "$1 $2-$3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2-$3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[68]", "format": "$1-$2-$3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23]", "format": "$1 $2-$3"}, {"pattern": "(\\d)(\\d{4})(\\d{2})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["9(?:2[2-469]|3[3-578])", "9(?:2(?:2[024-9]|3[0-59]|47|6[245]|9[02-8])|3(?:3[28]|4[03-9]|5[2-46-8]|7[1-578]|8[2-9]))", "9(?:2(?:[23]02|6(?:[25]|4[6-8])|9(?:[02356]|4[02568]|72|8[23]))|3(?:3[28]|4(?:[04679]|3[5-8]|5[4-68]|8[2379])|5(?:[2467]|3[237]|8[2-5])|7[1-578]|8(?:[2469]|3[2578]|5[4-8]|7[36-8]|8[5-8])))|92(?:2[24-9]|3[1-59]|47)", "9(?:2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3[78]|5(?:4[46]|8)|8[2379])|5(?:[2467]|3[237]|8[23])|7[1-578]|8(?:[2469]|3[278]|5(?:[56][46]|[78])|7[378]|8(?:6[3-6]|[78]))))|92(?:2[24-9]|3[1-59]|47)|93(?:4[35][56]|58[45]|8(?:[38]5|54|76))[4-6]", "9(?:2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3(?:5(?:4[0-25689]|[56])|[78])|5(?:4[46]|8)|8[2379])|5(?:[2467]|3[237]|8(?:[23]|4(?:[45]|60)|5(?:4[0-39]|5|64)))|7[1-578]|8(?:[2469]|3[278]|5(?:4(?:4|5[13-7]|6[89])|[56][46]|[78])|7[378]|8(?:6[3-6]|[78]))))|92(?:2[24-9]|3[1-59]|47)|93(?:4(?:36|5[56])|8(?:[38]5|76))[4-6]"], "format": "$2 15-$3-$4", "intlFormat": "$1 $2 $3-$4"}, {"pattern": "(\\d)(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "91", "format": "$2 15-$3-$4", "intlFormat": "$1 $2 $3-$4"}, {"pattern": "(\\d)(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$2 15-$3-$4", "intlFormat": "$1 $2 $3-$4"}]}, "generalDesc": {"nationalNumberPattern": "11\\d{8}|(?:[2368]|9\\d)\\d{9}"}, "noInternationalDialling": {"possibleLengths": {"national": "10"}, "nationalNumberPattern": "810\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "[6-8]"}, "exampleNumber": "1123456789", "nationalNumberPattern": "3888[013-9]\\d{5}|(?:29(?:54|66)|3(?:777|865))[2-8]\\d{5}|3(?:7(?:1[15]|81)|8(?:21|4[16]|69|9[12]))[46]\\d{5}|(?:2(?:2(?:2[59]|44|52)|3(?:26|44)|473|9(?:[07]2|2[26]|34|46))|3327)[45]\\d{5}|(?:2(?:284|302|657|920)|3(?:4(?:8[27]|92)|541|755|878))[2-7]\\d{5}|(?:2(?:(?:26|62)2|32[03]|477|9(?:42|83))|3(?:329|4(?:[47]6|62|89)|564))[2-6]\\d{5}|(?:(?:11[1-8]|670)\\d|2(?:2(?:0[45]|1[2-6]|3[3-6])|3(?:[06]4|7[45])|494|6(?:04|1[2-7]|[36][45]|4[3-6])|80[45]|9(?:[17][4-6]|[48][45]|9[3-6]))|3(?:364|4(?:1[2-7]|[235][4-6]|84)|5(?:1[2-8]|[38][4-6])|6(?:2[45]|44)|7[069][45]|8(?:[03][45]|[17][2-6]|[58][3-6])))\\d{6}|2(?:2(?:21|4[23]|6[145]|7[1-4]|8[356]|9[267])|3(?:16|3[13-8]|43|5[346-8]|9[3-5])|475|6(?:2[46]|4[78]|5[1568])|9(?:03|2[1457-9]|3[1356]|4[08]|[56][23]|82))4\\d{5}|(?:2(?:2(?:57|81)|3(?:24|46|92)|9(?:01|23|64))|3(?:4(?:42|71)|5(?:25|37|4[347]|71)|7(?:18|5[17])))[3-6]\\d{5}|(?:2(?:2(?:02|2[3467]|4[156]|5[45]|6[6-8]|91)|3(?:1[47]|25|[45][25]|96)|47[48]|625|932)|3(?:38[2578]|4(?:0[0-24-9]|3[78]|4[457]|58|6[03-9]|72|83|9[136-8])|5(?:2[124]|[368][23]|4[2689]|7[2-6])|7(?:16|2[15]|3[145]|4[13]|5[468]|7[2-5]|8[26])|8(?:2[5-7]|3[278]|4[3-5]|5[78]|6[1-378]|[78]7|94)))[4-6]\\d{5}"}, "mobile": {"possibleLengths": {"national": "10,11", "localOnly": "[6-8]"}, "exampleNumber": "91123456789", "nationalNumberPattern": "93888[013-9]\\d{5}|9(?:29(?:54|66)|3(?:777|865))[2-8]\\d{5}|93(?:7(?:1[15]|81)|8(?:21|4[16]|69|9[12]))[46]\\d{5}|9(?:2(?:2(?:2[59]|44|52)|3(?:26|44)|473|9(?:[07]2|2[26]|34|46))|3327)[45]\\d{5}|9(?:2(?:284|302|657|920)|3(?:4(?:8[27]|92)|541|755|878))[2-7]\\d{5}|9(?:2(?:(?:26|62)2|32[03]|477|9(?:42|83))|3(?:329|4(?:[47]6|62|89)|564))[2-6]\\d{5}|(?:675\\d|9(?:11[1-8]\\d|2(?:2(?:0[45]|1[2-6]|3[3-6])|3(?:[06]4|7[45])|494|6(?:04|1[2-7]|[36][45]|4[3-6])|80[45]|9(?:[17][4-6]|[48][45]|9[3-6]))|3(?:364|4(?:1[2-7]|[235][4-6]|84)|5(?:1[2-8]|[38][4-6])|6(?:2[45]|44)|7[069][45]|8(?:[03][45]|[17][2-6]|[58][3-6]))))\\d{6}|92(?:2(?:21|4[23]|6[145]|7[1-4]|8[356]|9[267])|3(?:16|3[13-8]|43|5[346-8]|9[3-5])|475|6(?:2[46]|4[78]|5[1568])|9(?:03|2[1457-9]|3[1356]|4[08]|[56][23]|82))4\\d{5}|9(?:2(?:2(?:57|81)|3(?:24|46|92)|9(?:01|23|64))|3(?:4(?:42|71)|5(?:25|37|4[347]|71)|7(?:18|5[17])))[3-6]\\d{5}|9(?:2(?:2(?:02|2[3467]|4[156]|5[45]|6[6-8]|91)|3(?:1[47]|25|[45][25]|96)|47[48]|625|932)|3(?:38[2578]|4(?:0[0-24-9]|3[78]|4[457]|58|6[03-9]|72|83|9[136-8])|5(?:2[124]|[368][23]|4[2689]|7[2-6])|7(?:16|2[15]|3[145]|4[13]|5[468]|7[2-5]|8[26])|8(?:2[5-7]|3[278]|4[3-5]|5[78]|6[1-378]|[78]7|94)))[4-6]\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "6001234567", "nationalNumberPattern": "60[04579]\\d{7}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "8101234567", "nationalNumberPattern": "810\\d{7}"}}, {"nationalPrefixForParsing": "1|([267]\\d{6})$", "countryCode": "1", "leadingDigits": "684", "nationalPrefix": "1", "nationalPrefixTransformRule": "684$1", "internationalPrefix": "011", "id": "AS", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|684|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6846221234", "nationalNumberPattern": "6846(?:22|33|44|55|77|88|9[19])\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6847331234", "nationalNumberPattern": "684(?:2(?:48|5[2468]|72)|7(?:3[13]|70|82))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "AT", "countryCode": "43", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3,12})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1(?:11|[2-9])", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "517", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5[079]", "format": "$1 $2"}, {"pattern": "(\\d{6})", "leadingDigits": "1", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3,10})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:31|4)6|51|6(?:5[0-3579]|[6-9])|7(?:20|32|8)|[89]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{3,9})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-467]|5[2-6]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{3,12}|2\\d{6,12}|43(?:(?:0\\d|5[02-9])\\d{3,9}|2\\d{4,5}|[3467]\\d{4}|8\\d{4,6}|9\\d{4,7})|5\\d{4,12}|8\\d{7,12}|9\\d{8,12}|(?:[367]\\d|4[0-24-9])\\d{4,11}"}, "fixedLine": {"possibleLengths": {"national": "[4-13]", "localOnly": "3"}, "exampleNumber": "1234567890", "nationalNumberPattern": "1(?:11\\d|[2-9]\\d{3,11})|(?:316|463|(?:51|66|73)2)\\d{3,10}|(?:2(?:1[467]|2[13-8]|5[2357]|6[1-46-8]|7[1-8]|8[124-7]|9[1458])|3(?:1[1-578]|3[23568]|4[5-7]|5[1378]|6[1-38]|8[3-68])|4(?:2[1-8]|35|7[1368]|8[2457])|5(?:2[1-8]|3[357]|4[147]|5[12578]|6[37])|6(?:13|2[1-47]|4[135-8]|5[468])|7(?:2[1-8]|35|4[13478]|5[68]|6[16-8]|7[1-6]|9[45]))\\d{4,10}"}, "mobile": {"possibleLengths": {"national": "[7-13]"}, "exampleNumber": "664123456", "nationalNumberPattern": "6(?:5[0-3579]|6[013-9]|[7-9]\\d)\\d{4,10}"}, "tollFree": {"possibleLengths": {"national": "[9-13]"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6,10}"}, "premiumRate": {"possibleLengths": {"national": "[9-13]"}, "exampleNumber": "900123456", "nationalNumberPattern": "9(?:0[01]|3[019])\\d{6,10}"}, "sharedCost": {"possibleLengths": {"national": "[8-13]"}, "exampleNumber": "810123456", "nationalNumberPattern": "8(?:10|2[018])\\d{6,10}|828\\d{5}"}, "voip": {"possibleLengths": {"national": "[5-13]"}, "exampleNumber": "780123456", "nationalNumberPattern": "5(?:0[1-9]|17|[79]\\d)\\d{2,10}|7[28]0\\d{6,10}"}}, {"mainCountryForCode": "true", "countryCode": "61", "nationalPrefixForParsing": "0|(183[12])", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredInternationalPrefix": "0011", "internationalPrefix": "001[14-689]|14(?:1[14]|34|4[17]|[56]6|7[47]|88)0011", "id": "AU", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "16", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "13", "format": "$1 $2 $3", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "19", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": ["180", "1802"], "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{3,4})", "leadingDigits": "19", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "16", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "14|4", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "carrierCodeFormattingRule": "$CC ($FG)", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[2378]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "1(?:30|[89])", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1(?:[0-79]\\d{7,8}|8[0-24-9]\\d{7})|[2-478]\\d{8}|1\\d{4,7}"}, "noInternationalDialling": {"possibleLengths": {"national": "[6-8],10"}, "nationalNumberPattern": "1[38]00\\d{6}|1(?:345[0-4]|802)\\d{3}|13\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "8"}, "exampleNumber": "212345678", "nationalNumberPattern": "8(?:51(?:0(?:0[03-9]|[12479]\\d|3[2-9]|5[0-8]|6[1-9]|8[0-7])|1(?:[0235689]\\d|1[0-69]|4[0-589]|7[0-47-9])|2(?:0[0-7]|3[2-4]|[4-6]\\d))|91(?:[0-57-9]\\d|6[0135-9])\\d)\\d{3}|(?:2(?:[0-26-9]\\d|3[0-8]|4[02-9]|5[0135-9])|3(?:[0-3589]\\d|4[0-578]|6[1-9]|7[0-35-9])|7(?:[013-57-9]\\d|2[0-8])|8(?:6[0-8]|[78]\\d|9[02-9]))\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "412345678", "nationalNumberPattern": "4(?:83[0-38]|93[0-4])\\d{5}|4(?:[0-3]\\d|4[047-9]|5[0-25-9]|6[06-9]|7[02-9]|8[0-24-9]|9[0-27-9])\\d{6}"}, "pager": {"possibleLengths": {"national": "[5-9]"}, "exampleNumber": "1631234", "nationalNumberPattern": "163\\d{2,6}"}, "tollFree": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "180(?:0\\d{3}|2)\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1900123456", "nationalNumberPattern": "190[0-26]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "6,8,10"}, "exampleNumber": "1300123456", "nationalNumberPattern": "13(?:00\\d{3}|45[0-4])\\d{3}|13\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "147101234", "nationalNumberPattern": "14(?:5(?:1[0458]|[23][458])|71\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "AW", "countryCode": "297", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[25-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[25-79]\\d\\d|800)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "5212345", "nationalNumberPattern": "5(?:2\\d|8[1-9])\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "5601234", "nationalNumberPattern": "(?:290|5[69]\\d|6(?:[03]0|22|4[0-2]|[69]\\d)|7(?:[34]\\d|7[07])|9(?:6[45]|9[4-8]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9001234", "nationalNumberPattern": "900\\d{4}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "5011234", "nationalNumberPattern": "(?:28\\d|501)\\d{4}"}}, {"countryCode": "358", "leadingDigits": "18", "nationalPrefix": "0", "preferredInternationalPrefix": "00", "internationalPrefix": "00|99(?:[01469]|5(?:[14]1|3[23]|5[59]|77|88|9[09]))", "id": "AX", "generalDesc": {"nationalNumberPattern": "2\\d{4,9}|35\\d{4,5}|(?:60\\d\\d|800)\\d{4,6}|7\\d{5,11}|(?:[14]\\d|3[0-46-9]|50)\\d{4,8}"}, "fixedLine": {"possibleLengths": {"national": "[6-9]"}, "exampleNumber": "181234567", "nationalNumberPattern": "18[1-8]\\d{3,6}"}, "mobile": {"possibleLengths": {"national": "[6-10]"}, "exampleNumber": "412345678", "nationalNumberPattern": "(?:4[0-8]|50)\\d{4,8}"}, "tollFree": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{4,6}"}, "premiumRate": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "600123456", "nationalNumberPattern": "[67]00\\d{5,6}"}, "uan": {"possibleLengths": {"national": "[5-12]"}, "exampleNumber": "10112345", "nationalNumberPattern": "20\\d{4,8}|60[12]\\d{5,6}|7(?:099\\d{4,5}|5[03-9]\\d{3,7})|20[2-59]\\d\\d|(?:606|7(?:0[78]|1|3\\d))\\d{7}|(?:10|29|3[09]|70[1-5]\\d)\\d{4,8}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "AZ", "countryCode": "994", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{2})", "leadingDigits": "[1-9]", "format": "$1 $2 $3", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "90", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": ["1[28]|2|365|46", "1[28]|2|365|46", "1[28]|2|365(?:[0-46-9]|5[0-35-9])|46"], "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[13-9]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "365\\d{6}|(?:[124579]\\d|60|88)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "123123456", "nationalNumberPattern": "(?:222[0-79]\\d|365(?:[0-46-9]\\d|5[0-35-9]))\\d{4}|(?:(?:1[28]|46)\\d|2(?:[045]2|1[24]|2[34]|33|6[23]))\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "401234567", "nationalNumberPattern": "(?:36554|99[2-9]\\d\\d)\\d{4}|(?:[16]0|4[04]|5[015]|7[07])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "881234567", "nationalNumberPattern": "88\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900200123", "nationalNumberPattern": "900200\\d{3}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "BA", "countryCode": "387", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "[2-9]", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6[1-3]|[7-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3-5]|6[56]", "format": "$1 $2-$3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "6\\d{8}|(?:[35689]\\d|49|70)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6"}, "exampleNumber": "30212345", "nationalNumberPattern": "(?:3(?:[05-79][2-9]|1[4579]|[23][24-9]|4[2-4689]|8[2457-9])|49[2-579]|5(?:0[2-49]|[13][2-9]|[268][2-4679]|4[4689]|5[2-79]|7[2-69]|9[2-4689]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "61123456", "nationalNumberPattern": "6040\\d{5}|6(?:03|[1-356]|44|7\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "8[08]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "9[0246]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "82123456", "nationalNumberPattern": "8[12]\\d{6}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "70341234", "nationalNumberPattern": "703[235]0\\d{3}|70(?:2[0-5]|3[0146]|[56]0)\\d{4}"}}, {"nationalPrefixForParsing": "1|([2-9]\\d{6})$", "countryCode": "1", "leadingDigits": "246", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "246$1", "internationalPrefix": "011", "id": "BB", "generalDesc": {"nationalNumberPattern": "(?:246|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2464123456", "nationalNumberPattern": "246(?:2(?:2[78]|7[0-4])|4(?:1[024-6]|2\\d|3[2-9])|5(?:20|[34]\\d|54|7[1-3])|6(?:2\\d|38)|7[35]7|9(?:1[89]|63))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2462501234", "nationalNumberPattern": "246(?:2(?:[3568]\\d|4[0-57-9])|45\\d|69[5-7]|8(?:[2-5]\\d|83))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "9002123456", "nationalNumberPattern": "(?:246976|900[2-9]\\d\\d)\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}, "voip": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2463101234", "nationalNumberPattern": "24631\\d{5}"}, "uan": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2464301234", "nationalNumberPattern": "246(?:292|367|4(?:1[7-9]|3[01]|44|67)|7(?:36|53))\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "BD", "countryCode": "880", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{4,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "31[5-8]|[459]1", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{3,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3(?:[67]|8[013-9])|4(?:6[168]|7|[89][18])|5(?:6[128]|9)|6(?:28|4[14]|5)|7[2-589]|8(?:0[014-9]|[12])|9[358]|(?:3[2-5]|4[235]|5[2-578]|6[0389]|76|8[3-7]|9[24])1|(?:44|66)[01346-9]", "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{3,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[13-9]", "format": "$1-$2"}, {"pattern": "(\\d)(\\d{7,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1-$2"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{9}|2\\d{7,8}|88\\d{4,6}|(?:8[0-79]|9\\d)\\d{4,8}|(?:[346]\\d|[57])\\d{5,8}"}, "fixedLine": {"possibleLengths": {"national": "[6-10]"}, "exampleNumber": "27111234", "nationalNumberPattern": "(?:4(?:31\\d\\d|423)|5222)\\d{3}(?:\\d{2})?|8332[6-9]\\d\\d|(?:3(?:03[56]|224)|4(?:22[25]|653))\\d{3,4}|(?:3(?:42[47]|529|823)|4(?:027|525|65(?:28|8))|562|6257|7(?:1(?:5[3-5]|6[12]|7[156]|89)|22[589]56|32|42675|52(?:[25689](?:56|8)|[347]8)|71(?:6[1267]|75|89)|92374)|82(?:2[59]|32)56|9(?:03[23]56|23(?:256|373)|31|5(?:1|2[4589]56)))\\d{3}|(?:3(?:02[348]|22[35]|324|422)|4(?:22[67]|32[236-9]|6(?:2[46]|5[57])|953)|5526|6(?:024|6655)|81)\\d{4,5}|(?:2(?:7(?:1[0-267]|2[0-289]|3[0-29]|4[01]|5[1-3]|6[013]|7[0178]|91)|8(?:0[125]|1[1-6]|2[0157-9]|3[1-69]|41|6[1-35]|7[1-5]|8[1-8]|9[0-6])|9(?:0[0-2]|1[0-4]|2[568]|3[3-6]|5[5-7]|6[0136-9]|7[0-7]|8[014-9]))|3(?:0(?:2[025-79]|3[2-4])|181|22[12]|32[2356]|824)|4(?:02[09]|22[348]|32[045]|523|6(?:27|54))|666(?:22|53)|7(?:22[57-9]|42[56]|82[35])8|8(?:0[124-9]|2(?:181|2[02-4679]8)|4[12]|[5-7]2)|9(?:[04]2|2(?:2|328)|81))\\d{4}|(?:2[45]\\d\\d|3(?:1(?:2[5-7]|[5-7])|425|822)|4(?:033|1\\d|[257]1|332|4(?:2[246]|5[25])|6(?:2[35]|56|62)|8(?:23|54)|92[2-5])|5(?:02[03489]|22[457]|32[35-79]|42[46]|6(?:[18]|53)|724|826)|6(?:023|2(?:2[2-5]|5[3-5]|8)|32[3478]|42[34]|52[47]|6(?:[18]|6(?:2[34]|5[24]))|[78]2[2-5]|92[2-6])|7(?:02|21\\d|[3-589]1|6[12]|72[24])|8(?:217|3[12]|[5-7]1)|9[24]1)\\d{5}|(?:(?:3[2-8]|5[2-57-9]|6[03-589])1|4[4689][18])\\d{5}|[59]1\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "1812345678", "nationalNumberPattern": "(?:1[13-9]\\d|644)\\d{7}|(?:3[78]|44|66)[02-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "80[03]\\d{7}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "9604123456", "nationalNumberPattern": "96(?:0[469]|1[0-47]|3[389]|6[69]|7[78])\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "BE", "countryCode": "32", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:80|9)0", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[239]|4[23]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[15-8]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "4", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "4\\d{8}|[1-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "12345678", "nationalNumberPattern": "80[2-8]\\d{5}|(?:1[0-69]|[23][2-8]|4[23]|5\\d|6[013-57-9]|71|8[1-79]|9[2-4])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "470123456", "nationalNumberPattern": "4[5-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800[1-9]\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "(?:70(?:2[0-57]|3[0457]|44|69|7[0579])|90(?:0[0-35-8]|1[36]|2[0-3568]|3[0135689]|4[2-68]|5[1-68]|6[0-378]|7[23568]|9[34679]))\\d{4}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "78791234", "nationalNumberPattern": "7879\\d{4}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "78102345", "nationalNumberPattern": "78(?:0[57]|1[0458]|2[25]|3[15-8]|48|[56]0|7[078])\\d{4}"}}, {"internationalPrefix": "00", "id": "BF", "countryCode": "226", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[025-7]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "[025-7]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "20491234", "nationalNumberPattern": "2(?:0(?:49|5[23]|6[56]|9[016-9])|4(?:4[569]|5[4-6]|6[56]|7[0179])|5(?:[34]\\d|50|6[5-7]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "70123456", "nationalNumberPattern": "(?:0[127]|5[1-8]|[67]\\d)\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "BG", "countryCode": "359", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{6})", "leadingDigits": "1", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d)(\\d)(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "43[1-6]|70[1-9]", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[356]|4[124-7]|7[1-9]|8[1-6]|9[1-7]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:70|8)0", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "43[1-7]|7", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[48]|9[08]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[2-7]\\d{6,7}|[89]\\d{6,8}|2\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "[6-8]", "localOnly": "4,5"}, "exampleNumber": "2123456", "nationalNumberPattern": "2\\d{5,7}|(?:43[1-6]|70[1-9])\\d{4,5}|(?:[36]\\d|4[124-7]|[57][1-9]|8[1-6]|9[1-7])\\d{5,6}"}, "mobile": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "48123456", "nationalNumberPattern": "43[07-9]\\d{5}|(?:48|8[7-9]\\d|9(?:8\\d|9[69]))\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "90\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "70012345", "nationalNumberPattern": "700\\d{5}"}}, {"internationalPrefix": "00", "id": "BH", "countryCode": "973", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[13679]|8[047]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "[136-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "17001234", "nationalNumberPattern": "(?:1(?:3[1356]|6[0156]|7\\d)\\d|6(?:1[16]\\d|500|6(?:0\\d|3[12]|44|7[7-9]|88)|9[69][69])|7(?:1(?:11|78)|7\\d\\d))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "36001234", "nationalNumberPattern": "(?:3(?:[1-79]\\d|8[0-47-9])\\d|6(?:3(?:00|33|6[16])|6(?:3[03-9]|[69]\\d|7[0-6])))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "80\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "(?:87|9[014578])\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "84123456", "nationalNumberPattern": "84\\d{6}"}}, {"internationalPrefix": "00", "id": "BI", "countryCode": "257", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[2367]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:[267]\\d|31)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22201234", "nationalNumberPattern": "22\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "79561234", "nationalNumberPattern": "(?:29|31|6[1289]|7[125-9])\\d{6}"}}, {"internationalPrefix": "00", "id": "BJ", "countryCode": "229", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[25689]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:[2689]\\d|51)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "20211234", "nationalNumberPattern": "2(?:02|1[037]|2[45]|3[68])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "90011234", "nationalNumberPattern": "(?:51|6\\d|9[013-9])\\d{6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "85751234", "nationalNumberPattern": "857[58]\\d{4}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "81123456", "nationalNumberPattern": "81\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "BL", "countryCode": "590", "mobileNumberPortableRegion": "true", "generalDesc": {"nationalNumberPattern": "(?:590|69\\d|976)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "590271234", "nationalNumberPattern": "590(?:2[7-9]|5[12]|87)\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "690001234", "nationalNumberPattern": "69(?:0\\d\\d|1(?:2[29]|3[0-5]))\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "976012345", "nationalNumberPattern": "976[01]\\d{5}"}}, {"nationalPrefixForParsing": "1|([2-8]\\d{6})$", "countryCode": "1", "leadingDigits": "441", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "441$1", "internationalPrefix": "011", "id": "BM", "generalDesc": {"nationalNumberPattern": "(?:441|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "4414123456", "nationalNumberPattern": "441(?:[46]\\d\\d|5(?:4\\d|60|89))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "4413701234", "nationalNumberPattern": "441(?:[2378]\\d|5[0-39])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"internationalPrefix": "00", "id": "BN", "countryCode": "673", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-578]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "[2-578]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2345678", "nationalNumberPattern": "22[0-7]\\d{4}|(?:2[013-9]|[34]\\d|5[0-25-9])\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "7123456", "nationalNumberPattern": "(?:22[89]|[78]\\d\\d)\\d{4}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "5345678", "nationalNumberPattern": "5[34]\\d{5}"}}, {"nationalPrefix": "0", "nationalPrefixForParsing": "0(1\\d)?", "internationalPrefix": "00(?:1\\d)?", "id": "BO", "countryCode": "591", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{7})", "carrierCodeFormattingRule": "$NP$CC $FG", "leadingDigits": "[23]|4[46]", "format": "$1 $2"}, {"pattern": "(\\d{8})", "carrierCodeFormattingRule": "$NP$CC $FG", "leadingDigits": "[67]", "format": "$1"}, {"pattern": "(\\d{3})(\\d{2})(\\d{4})", "carrierCodeFormattingRule": "$NP$CC $FG", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[2-467]\\d\\d|8001)\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "9"}, "nationalNumberPattern": "8001[07]\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "22123456", "nationalNumberPattern": "(?:2(?:2\\d\\d|5(?:11|[258]\\d|9[67])|6(?:12|2\\d|9[34])|8(?:2[34]|39|62))|3(?:3\\d\\d|4(?:6\\d|8[24])|8(?:25|42|5[257]|86|9[25])|9(?:[27]\\d|3[2-4]|4[248]|5[24]|6[2-6]))|4(?:4\\d\\d|6(?:11|[24689]\\d|72)))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "71234567", "nationalNumberPattern": "[67]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800171234", "nationalNumberPattern": "8001[07]\\d{4}"}}, {"leadingDigits": "[347]", "internationalPrefix": "00", "id": "BQ", "countryCode": "599", "generalDesc": {"nationalNumberPattern": "(?:[34]1|7\\d)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "7151234", "nationalNumberPattern": "(?:318[023]|41(?:6[023]|70)|7(?:1[578]|2[05]|50)\\d)\\d{3}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "3181234", "nationalNumberPattern": "(?:31(?:8[14-8]|9[14578])|416[14-9]|7(?:0[01]|7[07]|8\\d|9[056])\\d)\\d{3}"}}, {"nationalPrefixForParsing": "(?:0|90)(?:(1[245]|2[1-35]|31|4[13]|[56]5|99)(\\d{10,11}))?", "countryCode": "55", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "nationalPrefixTransformRule": "$2", "internationalPrefix": "00(?:1[245]|2[1-35]|31|4[13]|[56]5|99)", "id": "BR", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3,6})", "leadingDigits": "1(?:1[25-8]|2[357-9]|3[02-68]|4[12568]|5|6[0-8]|8[015]|9[0-47-9])|321|610", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": ["300|4(?:0[02]|37)", "4(?:02|37)0|[34]00"], "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": ["[2-57]", "[2357]|4(?:[0-24-9]|3(?:[0-689]|7[1-9]))"], "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{2,3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:[358]|90)0", "format": "$1 $2 $3"}, {"pattern": "(\\d{5})(\\d{4})", "leadingDigits": "9", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "carrierCodeFormattingRule": "$NP $CC ($FG)", "nationalPrefixFormattingRule": "($FG)", "leadingDigits": "(?:[14689][1-9]|2[12478]|3[1-578]|5[13-5]|7[13-579])[2-57]", "format": "$1 $2-$3"}, {"pattern": "(\\d{2})(\\d{5})(\\d{4})", "carrierCodeFormattingRule": "$NP $CC ($FG)", "nationalPrefixFormattingRule": "($FG)", "leadingDigits": "[16][1-9]|[2-57-9]", "format": "$1 $2-$3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[1-46-9]\\d\\d|5(?:[0-46-9]\\d|5[0-24679]))\\d{8}|[1-9]\\d{9}|[3589]\\d{8}|[34]\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "4020\\d{4}|[34]00\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "8"}, "exampleNumber": "1123456789", "nationalNumberPattern": "(?:[14689][1-9]|2[12478]|3[1-578]|5[13-5]|7[13-579])[2-5]\\d{7}"}, "mobile": {"possibleLengths": {"national": "10,11", "localOnly": "8,9"}, "exampleNumber": "11961234567", "nationalNumberPattern": "(?:[14689][1-9]|2[12478]|3[1-578]|5[13-5]|7[13-579])(?:7|9\\d)\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6,7}"}, "premiumRate": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "300123456", "nationalNumberPattern": "300\\d{6}|[59]00\\d{6,7}"}, "sharedCost": {"possibleLengths": {"national": "8,10"}, "exampleNumber": "40041234", "nationalNumberPattern": "300\\d{7}|[34]00\\d{5}|4(?:02|37)0\\d{4}"}}, {"nationalPrefixForParsing": "1|([3-8]\\d{6})$", "countryCode": "1", "leadingDigits": "242", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "242$1", "internationalPrefix": "011", "id": "BS", "generalDesc": {"nationalNumberPattern": "(?:242|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2423456789", "nationalNumberPattern": "242(?:3(?:02|[236][1-9]|4[0-24-9]|5[0-68]|7[347]|8[0-4]|9[2-467])|461|502|6(?:0[1-4]|12|2[013]|[45]0|7[67]|8[78]|9[89])|7(?:02|88))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2423591234", "nationalNumberPattern": "242(?:3(?:5[79]|7[56]|95)|4(?:[23][1-9]|4[1-35-9]|5[1-8]|6[2-8]|7\\d|81)|5(?:2[45]|3[35]|44|5[1-46-9]|65|77)|6[34]6|7(?:27|38)|8(?:0[1-9]|1[02-9]|2\\d|[89]9))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8002123456", "nationalNumberPattern": "242300\\d{4}|8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "2422250123", "nationalNumberPattern": "242225\\d{4}"}}, {"internationalPrefix": "00", "id": "BT", "countryCode": "975", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "[2-7]", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d)(\\d{3})(\\d{3})", "leadingDigits": "[2-68]|7[246]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "1[67]|7", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[17]\\d{7}|[2-8]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7", "localOnly": "6"}, "exampleNumber": "2345678", "nationalNumberPattern": "(?:2[3-6]|[34][5-7]|5[236]|6[2-46]|7[246]|8[2-4])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "17123456", "nationalNumberPattern": "(?:1[67]|77)\\d{6}"}}, {"internationalPrefix": "00", "id": "BW", "countryCode": "267", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{5})", "leadingDigits": "90", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[24-6]|3[15-79]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "leadingDigits": "[37]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "0", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{3})", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:0800|(?:[37]|800)\\d)\\d{6}|(?:[2-6]\\d|90)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2401234", "nationalNumberPattern": "(?:2(?:4[0-48]|6[0-24]|9[0578])|3(?:1[0-35-9]|55|[69]\\d|7[013])|4(?:6[03]|7[1267]|9[0-5])|5(?:3[0389]|4[0489]|7[1-47]|88|9[0-49])|6(?:2[1-35]|5[149]|8[067]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "71123456", "nationalNumberPattern": "77200\\d{3}|(?:321|7(?:[1-6]\\d|7[013-9]|8[01]))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "0800012345", "nationalNumberPattern": "(?:0800|800\\d)\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9012345", "nationalNumberPattern": "90\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "79101234", "nationalNumberPattern": "79(?:1(?:[01]\\d|20)|2[0-2]\\d)\\d{3}"}}, {"nationalPrefixForParsing": "0|80?", "countryCode": "375", "mobileNumberPortableRegion": "true", "nationalPrefix": "8", "preferredInternationalPrefix": "8~10", "internationalPrefix": "810", "id": "BY", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "800", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2,4})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "800", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP 0$FG", "leadingDigits": ["1(?:5[169]|6[3-5]|7[179])|2(?:1[35]|2[34]|3[3-5])", "1(?:5[169]|6(?:3[1-3]|4|5[125])|7(?:1[3-9]|7[0-24-6]|9[2-7]))|2(?:1[35]|2[34]|3[3-5])"], "format": "$1 $2-$3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP 0$FG", "leadingDigits": "1(?:[56]|7[467])|2[1-3]", "format": "$1 $2-$3-$4"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP 0$FG", "leadingDigits": "[1-4]", "format": "$1 $2-$3-$4"}, {"pattern": "(\\d{3})(\\d{3,4})(\\d{4})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "[89]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[12]\\d|33|44|902)\\d{7}|8(?:0[0-79]\\d{5,7}|[1-7]\\d{9})|8(?:1[0-489]|[5-79]\\d)\\d{7}|8[1-79]\\d{6,7}|8[0-79]\\d{5}|8\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "[6-11]"}, "nationalNumberPattern": "800\\d{3,7}|(?:8(?:0[13]|10|20\\d)|902)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "[5-7]"}, "exampleNumber": "152450911", "nationalNumberPattern": "(?:1(?:5(?:1[1-5]|[24]\\d|6[2-4]|9[1-7])|6(?:[235]\\d|4[1-7])|7\\d\\d)|2(?:1(?:[246]\\d|3[0-35-9]|5[1-9])|2(?:[235]\\d|4[0-8])|3(?:[26]\\d|3[02-79]|4[024-7]|5[03-7])))\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "294911911", "nationalNumberPattern": "(?:2(?:5[5-79]|9[1-9])|(?:33|44)\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "[6-11]"}, "exampleNumber": "8011234567", "nationalNumberPattern": "800\\d{3,7}|8(?:0[13]|20\\d)\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9021234567", "nationalNumberPattern": "(?:810|902)\\d{7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "249123456", "nationalNumberPattern": "249\\d{6}"}}, {"internationalPrefix": "00", "id": "BZ", "countryCode": "501", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-8]", "format": "$1-$2"}, {"pattern": "(\\d)(\\d{3})(\\d{4})(\\d{3})", "leadingDigits": "0", "format": "$1-$2-$3-$4"}]}, "generalDesc": {"nationalNumberPattern": "(?:0800\\d|[2-8])\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2221234", "nationalNumberPattern": "(?:236|732)\\d{4}|[2-578][02]\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "6221234", "nationalNumberPattern": "6[0-35-7]\\d{5}"}, "tollFree": {"possibleLengths": {"national": "11"}, "exampleNumber": "08001234123", "nationalNumberPattern": "0800\\d{7}"}}, {"nationalPrefix": "1", "internationalPrefix": "011", "id": "CA", "countryCode": "1", "mobileNumberPortableRegion": "true", "generalDesc": {"nationalNumberPattern": "(?:[2-8]\\d|90)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "5062345678", "nationalNumberPattern": "(?:2(?:04|[23]6|[48]9|50)|3(?:06|43|6[57])|4(?:03|1[68]|3[178]|50)|5(?:06|1[49]|48|79|8[17])|6(?:04|13|39|47|72)|7(?:0[59]|78|8[02])|8(?:[06]7|19|25|73)|90[25])[2-9]\\d{6}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "5062345678", "nationalNumberPattern": "(?:2(?:04|[23]6|[48]9|50)|3(?:06|43|6[57])|4(?:03|1[68]|3[178]|50)|5(?:06|1[49]|48|79|8[17])|6(?:04|13|39|47|72)|7(?:0[59]|78|8[02])|8(?:[06]7|19|25|73)|90[25])[2-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|(?:5(?:00|2[12]|33|44|66|77|88)|622)[2-9]\\d{6}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "6002012345", "nationalNumberPattern": "600[2-9]\\d{6}"}}, {"nationalPrefixForParsing": "0|([59]\\d{7})$", "countryCode": "61", "nationalPrefix": "0", "preferredInternationalPrefix": "0011", "nationalPrefixTransformRule": "8$1", "internationalPrefix": "001[14-689]|14(?:1[14]|34|4[17]|[56]6|7[47]|88)0011", "id": "CC", "generalDesc": {"nationalNumberPattern": "1(?:[0-79]\\d|8[0-24-9])\\d{7}|[148]\\d{8}|1\\d{5,7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "8"}, "exampleNumber": "891621234", "nationalNumberPattern": "8(?:51(?:0(?:02|31|60|89)|118)|91(?:0(?:1[0-2]|29)|1(?:[28]2|50|79)|2(?:10|64)|3(?:[06]8|22)|4[29]8|62\\d|70[23]|959))\\d{3}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "412345678", "nationalNumberPattern": "4(?:83[0-38]|93[0-4])\\d{5}|4(?:[0-3]\\d|4[047-9]|5[0-25-9]|6[06-9]|7[02-9]|8[0-24-9]|9[0-27-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "180(?:0\\d{3}|2)\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1900123456", "nationalNumberPattern": "190[0-26]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "6,8,10"}, "exampleNumber": "1300123456", "nationalNumberPattern": "13(?:00\\d{3}|45[0-4])\\d{3}|13\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "147101234", "nationalNumberPattern": "14(?:5(?:1[0458]|[23][458])|71\\d)\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "CD", "countryCode": "243", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "88", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-6]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[189]\\d{8}|[1-68]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "1234567", "nationalNumberPattern": "12\\d{7}|[1-6]\\d{6}"}, "mobile": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "991234567", "nationalNumberPattern": "88\\d{5}|(?:8[0-2459]|9[017-9])\\d{7}"}}, {"internationalPrefix": "00", "id": "CF", "countryCode": "236", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[278]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:[27]\\d{3}|8776)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21612345", "nationalNumberPattern": "2[12]\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "70012345", "nationalNumberPattern": "7[0257]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "87761234", "nationalNumberPattern": "8776\\d{4}"}}, {"internationalPrefix": "00", "id": "CG", "countryCode": "242", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "801", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "leadingDigits": "8", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "leadingDigits": "[02]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "222\\d{6}|(?:0\\d|80)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "222123456", "nationalNumberPattern": "222[1-589]\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "061234567", "nationalNumberPattern": "026(?:1[0-5]|6[6-9])\\d{4}|0(?:[14-6]\\d\\d|2(?:40|5[5-8]|6[07-9]))\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80(?:0\\d\\d|11[0-4])\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "CH", "countryCode": "41", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8[047]|90", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-79]|81", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3 $4 $5"}]}, "generalDesc": {"nationalNumberPattern": "8\\d{11}|[2-9]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "212345678", "nationalNumberPattern": "(?:2[12467]|3[1-4]|4[134]|5[256]|6[12]|[7-9]1)\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "781234567", "nationalNumberPattern": "7[35-9]\\d{7}"}, "pager": {"possibleLengths": {"national": "9"}, "exampleNumber": "740123456", "nationalNumberPattern": "74[0248]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "90[016]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "840123456", "nationalNumberPattern": "84[0248]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "878123456", "nationalNumberPattern": "878\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "581234567", "nationalNumberPattern": "5[18]\\d{7}"}, "voicemail": {"possibleLengths": {"national": "12"}, "exampleNumber": "860123456789", "nationalNumberPattern": "860\\d{9}"}}, {"internationalPrefix": "00", "id": "CI", "countryCode": "225", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[02-9]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "[02-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:2(?:0[023]|1[02357]|[23][045]|4[03-5])|3(?:0[06]|1[069]|[2-4][07]|5[09]|6[08]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "01234567", "nationalNumberPattern": "2[0-3]80\\d{4}|(?:0[1-9]|[457]\\d|6[014-9]|8[4-9]|9[4-8])\\d{6}"}}, {"internationalPrefix": "00", "id": "CK", "countryCode": "682", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})", "leadingDigits": "[2-578]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "[2-578]\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "21234", "nationalNumberPattern": "(?:2\\d|3[13-7]|4[1-5])\\d{3}"}, "mobile": {"possibleLengths": {"national": "5"}, "exampleNumber": "71234", "nationalNumberPattern": "[578]\\d{4}"}}, {"internationalPrefix": "(?:0|1(?:1[0-69]|2[02-5]|5[13-58]|69|7[0167]|8[018]))0", "id": "CL", "countryCode": "56", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})", "leadingDigits": "1(?:[03-589]|21)|[29]0|78", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{5})(\\d{4})", "nationalPrefixFormattingRule": "($FG)", "leadingDigits": ["219", "2196"], "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "leadingDigits": "44", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "($FG)", "leadingDigits": "2[1-3]", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "leadingDigits": "9[2-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "($FG)", "leadingDigits": "3[2-5]|[47]|5[1-3578]|6[13-57]|8(?:0[1-9]|[1-9])", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "leadingDigits": "60|8", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{2})(\\d{3})", "leadingDigits": "60", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "12300\\d{6}|6\\d{9,10}|[2-9]\\d{8}"}, "noInternationalDialling": {"possibleLengths": {"national": "10,11"}, "nationalNumberPattern": "600\\d{7,8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "221234567", "nationalNumberPattern": "2(?:1982[0-6]|3314[05-9])\\d{3}|(?:2(?:1(?:160|962)|3(?:2\\d\\d|3(?:0\\d|1[0-35-9]|2[1-9]|3[0-29]|40)))|80[1-9]\\d\\d|9(?:3(?:[0-57-9]\\d\\d|6(?:0[02-9]|[1-9]\\d))|6(?:[0-8]\\d\\d|9(?:[02-79]\\d|1[05-9]))|7[1-9]\\d\\d|9(?:[03-9]\\d\\d|1(?:[0235-9]\\d|4[0-24-9])|2(?:[0-79]\\d|8[0-46-9]))))\\d{4}|(?:22|3[2-5]|[47][1-35]|5[1-3578]|6[13-57]|8[1-9]|9[2458])\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "221234567", "nationalNumberPattern": "2(?:1982[0-6]|3314[05-9])\\d{3}|(?:2(?:1(?:160|962)|3(?:2\\d\\d|3(?:0\\d|1[0-35-9]|2[1-9]|3[0-29]|40)))|80[1-9]\\d\\d|9(?:3(?:[0-57-9]\\d\\d|6(?:0[02-9]|[1-9]\\d))|6(?:[0-8]\\d\\d|9(?:[02-79]\\d|1[05-9]))|7[1-9]\\d\\d|9(?:[03-9]\\d\\d|1(?:[0235-9]\\d|4[0-24-9])|2(?:[0-79]\\d|8[0-46-9]))))\\d{4}|(?:22|3[2-5]|[47][1-35]|5[1-3578]|6[13-57]|8[1-9]|9[2458])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9,11"}, "exampleNumber": "800123456", "nationalNumberPattern": "(?:123|8)00\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "6001234567", "nationalNumberPattern": "600\\d{7,8}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "441234567", "nationalNumberPattern": "44\\d{7}"}}, {"internationalPrefix": "00", "id": "CM", "countryCode": "237", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "88", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d)(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[26]", "format": "$1 $2 $3 $4 $5"}]}, "generalDesc": {"nationalNumberPattern": "(?:[26]\\d\\d|88)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "222123456", "nationalNumberPattern": "2(?:22|33)\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "671234567", "nationalNumberPattern": "(?:24[23]|6[5-9]\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "88012345", "nationalNumberPattern": "88\\d{6}"}}, {"nationalPrefixForParsing": "0|(1(?:[12]\\d|79)\\d\\d)", "countryCode": "86", "nationalPrefix": "0", "preferredInternationalPrefix": "00", "internationalPrefix": "00|1(?:[12]\\d|79)\\d\\d00", "id": "CN", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5,6})", "leadingDigits": "96", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{5,6})", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["(?:10|2[0-57-9])[19]", "(?:10|2[0-57-9])(?:10|9[56])", "(?:10|2[0-57-9])(?:100|9[56])"], "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": ["[1-9]", "1[1-9]|26|[3-9]|(?:10|2[0-57-9])(?:[0-8]|9[0-47-9])", "1[1-9]|26|[3-9]|(?:10|2[0-57-9])(?:[02-8]|1(?:0[1-9]|[1-9])|9[0-47-9])"], "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "16[08]", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{5,6})", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["3(?:[157]|35|49|9[1-68])|4(?:[17]|2[179]|6[47-9]|8[23])|5(?:[1357]|2[37]|4[36]|6[1-46]|80)|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])|(?:4[35]|59|85)[1-9]", "(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[1-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))[19]", "85[23](?:10|95)|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:10|9[56])", "85[23](?:100|95)|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:100|9[56])"], "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": ["[1-9]", "1[1-9]|26|[3-9]|(?:10|2[0-57-9])(?:[0-8]|9[0-47-9])", "26|3(?:[0268]|9[079])|4(?:[049]|2[02-68]|[35]0|6[0-356]|8[014-9])|5(?:0|2[0-24-689]|4[0-2457-9]|6[057-9]|90)|6(?:[0-24578]|6[14-79]|9[03-9])|7(?:0[02-9]|2[0135-79]|3[23]|4[0-27-9]|6[1457]|8)|8(?:[046]|1[01459]|2[0-489]|50|8[0-2459]|9[09])|9(?:0[0457]|1[08]|[268]|4[024-9])|(?:34|85[23])[0-8]|(?:1|58)[1-9]|(?:63|95)[06-9]|(?:33|85[23]9)[0-46-9]|(?:10|2[0-57-9]|3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:[0-8]|9[0-47-9])", "26|3(?:[0268]|3[0-46-9]|4[0-8]|9[079])|4(?:[049]|2[02-68]|[35]0|6[0-356]|8[014-9])|5(?:0|2[0-24-689]|4[0-2457-9]|6[057-9]|90)|6(?:[0-24578]|3[06-9]|6[14-79]|9[03-9])|7(?:0[02-9]|2[0135-79]|3[23]|4[0-27-9]|6[1457]|8)|8(?:[046]|1[01459]|2[0-489]|5(?:0|[23](?:[02-8]|1[1-9]|9[0-46-9]))|8[0-2459]|9[09])|9(?:0[0457]|1[08]|[268]|4[024-9]|5[06-9])|(?:1|58|85[23]10)[1-9]|(?:10|2[0-57-9])(?:[0-8]|9[0-47-9])|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:[02-8]|1(?:0[1-9]|[1-9])|9[0-47-9])"], "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "(?:4|80)0", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["10|2(?:[02-57-9]|1[1-9])", "10|2(?:[02-57-9]|1[1-9])", "10[0-79]|2(?:[02-57-9]|1[1-79])|(?:10|21)8(?:0[1-9]|[1-9])"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3(?:[3-59]|7[02-68])|4(?:[26-8]|3[3-9]|5[2-9])|5(?:3[03-9]|[468]|7[028]|9[2-46-9])|6|7(?:[0-247]|3[04-9]|5[0-4689]|6[2368])|8(?:[1-358]|9[1-7])|9(?:[013479]|5[1-5])|(?:[34]1|55|79|87)[02-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{7,8})", "leadingDigits": "9", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "80", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3-578]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "1[3-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "1[127]\\d{8,9}|2\\d{9}(?:\\d{2})?|[12]\\d{6,7}|86\\d{6}|(?:1[03-689]\\d|6)\\d{7,9}|(?:[3-579]\\d|8[0-57-9])\\d{6,9}"}, "noInternationalDialling": {"possibleLengths": {"national": "[10-12]"}, "nationalNumberPattern": "(?:(?:10|21)8|[48])00\\d{7}|950\\d{7,8}"}, "fixedLine": {"possibleLengths": {"national": "[7-11]", "localOnly": "5,6"}, "exampleNumber": "1012345678", "nationalNumberPattern": "(?:10(?:[02-79]\\d\\d|[18](?:0[1-9]|[1-9]\\d))|21(?:[18](?:0[1-9]|[1-9]\\d)|[2-79]\\d\\d))\\d{5}|(?:43[35]|754)\\d{7,8}|8(?:078\\d{7}|51\\d{7,8})|(?:10|(?:2|85)1|43[35]|754)(?:100\\d\\d|95\\d{3,4})|(?:2[02-57-9]|3(?:11|7[179])|4(?:[15]1|3[12])|5(?:1\\d|2[37]|3[12]|51|7[13-79]|9[15])|7(?:[39]1|5[57]|6[09])|8(?:71|98))(?:[02-8]\\d{7}|1(?:0(?:0\\d\\d(?:\\d{3})?|[1-9]\\d{5})|[1-9]\\d{6})|9(?:[0-46-9]\\d{6}|5\\d{3}(?:\\d(?:\\d{2})?)?))|(?:3(?:1[02-9]|35|49|5\\d|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|3[46-9]|5[2-9]|6[47-9]|7\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[17]\\d|2[248]|3[04-9]|4[3-6]|5[0-3689]|6[2368]|9[02-9])|8(?:1[236-8]|2[5-7]|3\\d|5[2-9]|7[02-9]|8[36-8]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:[02-8]\\d{6}|1(?:0(?:0\\d\\d(?:\\d{2})?|[1-9]\\d{4})|[1-9]\\d{5})|9(?:[0-46-9]\\d{5}|5\\d{3,5}))"}, "mobile": {"possibleLengths": {"national": "11"}, "exampleNumber": "13123456789", "nationalNumberPattern": "1740[0-5]\\d{6}|1(?:[38]\\d|4[57]|5[0-35-9]|6[25-7]|7[0-35-8]|9[0135-9])\\d{8}"}, "tollFree": {"possibleLengths": {"national": "10,12"}, "exampleNumber": "8001234567", "nationalNumberPattern": "(?:(?:10|21)8|8)00\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "16812345", "nationalNumberPattern": "16[08]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "[7-11]", "localOnly": "5,6"}, "exampleNumber": "4001234567", "nationalNumberPattern": "400\\d{7}|950\\d{7,8}|(?:10|2[0-57-9]|3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))96\\d{3,4}"}}, {"nationalPrefixForParsing": "0([3579]|4(?:[14]4|56))?", "countryCode": "57", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "internationalPrefix": "00(?:4(?:[14]4|56)|[579])", "id": "CO", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{7})", "carrierCodeFormattingRule": "$NP$CC $FG", "nationalPrefixFormattingRule": "($FG)", "leadingDigits": "[14][2-9]|[25-8]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{7})", "carrierCodeFormattingRule": "$NP$CC $FG", "leadingDigits": "3", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1-$2-$3", "intlFormat": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:1\\d|3)\\d{9}|[124-8]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "12345678", "nationalNumberPattern": "[124-8][2-9]\\d{6}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "3211234567", "nationalNumberPattern": "3333(?:0(?:0\\d|1[0-5])|[4-9]\\d\\d)\\d{3}|3(?:24[2-6]|3(?:00|3[0-24-9]))\\d{6}|3(?:0[0-5]|1\\d|2[0-3]|5[01]|70)\\d{7}"}, "tollFree": {"possibleLengths": {"national": "11"}, "exampleNumber": "18001234567", "nationalNumberPattern": "1800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "11"}, "exampleNumber": "19001234567", "nationalNumberPattern": "19(?:0[01]|4[78])\\d{7}"}}, {"nationalPrefixForParsing": "(19(?:0[0-2468]|1[09]|20|66|77|99))", "internationalPrefix": "00", "id": "CR", "countryCode": "506", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{4})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "[2-7]|8[3-9]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "[89]", "format": "$1-$2-$3"}]}, "generalDesc": {"nationalNumberPattern": "(?:8\\d|90)\\d{8}|(?:[24-8]\\d{3}|3005)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22123456", "nationalNumberPattern": "210[7-9]\\d{4}|2(?:[024-7]\\d|1[1-9])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "83123456", "nationalNumberPattern": "(?:3005\\d|6500[01])\\d{3}|(?:5[07]|6[0-4]|7[0-3]|8[3-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9001234567", "nationalNumberPattern": "90[059]\\d{7}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "40001234", "nationalNumberPattern": "(?:210[0-6]|4\\d{3}|5100)\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "119", "id": "CU", "countryCode": "53", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{4,6})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2[1-4]|[34]", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{6,7})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "7", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[27]\\d{6,7}|[34]\\d{5,7}|(?:5|8\\d\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "[6-8],10", "localOnly": "4,5"}, "exampleNumber": "71234567", "nationalNumberPattern": "(?:3[23]|48)\\d{4,6}|(?:31|4[36]|8(?:0[25]|78)\\d)\\d{6}|(?:2[1-4]|4[1257]|7\\d)\\d{5,6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "51234567", "nationalNumberPattern": "5\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "8071234567", "nationalNumberPattern": "807\\d{7}"}}, {"internationalPrefix": "0", "id": "CV", "countryCode": "238", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{2})(\\d{2})", "leadingDigits": "[2-589]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "(?:[2-59]\\d\\d|800)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2211234", "nationalNumberPattern": "2(?:2[1-7]|3[0-8]|4[12]|5[1256]|6\\d|7[1-3]|8[1-5])\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "9911234", "nationalNumberPattern": "(?:[34][36]|5[1-389]|9\\d)\\d{5}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4}"}}, {"mainCountryForCode": "true", "internationalPrefix": "00", "id": "CW", "countryCode": "599", "leadingDigits": "[69]", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[3467]", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "leadingDigits": "9[4-8]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[34]1|60|(?:7|9\\d)\\d)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "94351234", "nationalNumberPattern": "9(?:4(?:3[0-5]|4[14]|6\\d)|50\\d|7(?:2[014]|3[02-9]|4[4-9]|6[357]|77|8[7-9])|8(?:3[39]|[46]\\d|7[01]|8[57-9]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "95181234", "nationalNumberPattern": "953[01]\\d{4}|9(?:5[12467]|6[5-9])\\d{5}"}, "pager": {"possibleLengths": {"national": "8"}, "exampleNumber": "95581234", "nationalNumberPattern": "955\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "7"}, "exampleNumber": "6001234", "nationalNumberPattern": "60[0-2]\\d{4}"}}, {"nationalPrefixForParsing": "0|([59]\\d{7})$", "countryCode": "61", "nationalPrefix": "0", "preferredInternationalPrefix": "0011", "nationalPrefixTransformRule": "8$1", "internationalPrefix": "001[14-689]|14(?:1[14]|34|4[17]|[56]6|7[47]|88)0011", "id": "CX", "generalDesc": {"nationalNumberPattern": "1(?:[0-79]\\d|8[0-24-9])\\d{7}|[148]\\d{8}|1\\d{5,7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "8"}, "exampleNumber": "891641234", "nationalNumberPattern": "8(?:51(?:0(?:01|30|59|88)|1(?:17|46|75)|235)|91(?:00[6-9]|1(?:[28]1|49|78)|2(?:09|63)|3(?:12|26|75)|4(?:56|97)|64\\d|7(?:0[01]|1[0-2])|958))\\d{3}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "412345678", "nationalNumberPattern": "4(?:83[0-38]|93[0-4])\\d{5}|4(?:[0-3]\\d|4[047-9]|5[0-25-9]|6[06-9]|7[02-9]|8[0-24-9]|9[0-27-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "180(?:0\\d{3}|2)\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1900123456", "nationalNumberPattern": "190[0-26]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "6,8,10"}, "exampleNumber": "1300123456", "nationalNumberPattern": "13(?:00\\d{3}|45[0-4])\\d{3}|13\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "147101234", "nationalNumberPattern": "14(?:5(?:1[0458]|[23][458])|71\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "CY", "countryCode": "357", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{6})", "leadingDigits": "[257-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[279]\\d|[58]0)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22345678", "nationalNumberPattern": "2[2-6]\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "96123456", "nationalNumberPattern": "9[4-79]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80001234", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "90[09]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80112345", "nationalNumberPattern": "80[1-9]\\d{5}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "70012345", "nationalNumberPattern": "700\\d{5}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "77123456", "nationalNumberPattern": "(?:50|77)\\d{6}"}}, {"internationalPrefix": "00", "id": "CZ", "countryCode": "420", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[2-8]|9[015-7]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "9", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "9", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:[2-578]\\d|60)\\d{7}|9\\d{8,11}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "212345678", "nationalNumberPattern": "(?:2\\d|3[1257-9]|4[16-9]|5[13-9])\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "601123456", "nationalNumberPattern": "(?:60[1-8]|7(?:0[2-5]|[2379]\\d))\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "9(?:0[05689]|76)\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "811234567", "nationalNumberPattern": "8[134]\\d{7}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "700123456", "nationalNumberPattern": "70[01]\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "910123456", "nationalNumberPattern": "9[17]0\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "972123456", "nationalNumberPattern": "9(?:5\\d|7[2-4])\\d{6}"}, "voicemail": {"possibleLengths": {"national": "[9-12]"}, "exampleNumber": "93123456789", "nationalNumberPattern": "9(?:3\\d{9}|6\\d{7,10})"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "DE", "countryCode": "49", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3,13})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3[02]|40|[68]9", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3,12})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["2(?:0[1-389]|1[124]|2[18]|3[14])|3(?:[35-9][15]|4[015])|906|(?:2[4-9]|4[2-9]|[579][1-9]|[68][1-8])1", "2(?:0[1-389]|12[0-8])|3(?:[35-9][15]|4[015])|906|2(?:[13][14]|2[18])|(?:2[4-9]|4[2-9]|[579][1-9]|[68][1-8])1"], "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{2,11})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["[24-6]|3(?:[3569][02-46-9]|4[2-4679]|7[2-467]|8[2-46-8])|70[2-8]|8(?:0[2-9]|[1-8])|90[7-9]|[79][1-9]", "[24-6]|3(?:3(?:0[1-467]|2[127-9]|3[124578]|7[1257-9]|8[1256]|9[145])|4(?:2[135]|4[13578]|9[1346])|5(?:0[14]|2[1-3589]|6[1-4]|7[13468]|8[13568])|6(?:2[1-489]|3[124-6]|6[13]|7[12579]|8[1-356]|9[135])|7(?:2[1-7]|4[145]|6[1-5]|7[1-4])|8(?:21|3[1468]|6|7[1467]|8[136])|9(?:0[12479]|2[1358]|4[134679]|6[1-9]|7[136]|8[147]|9[1468]))|70[2-8]|8(?:0[2-9]|[1-8])|90[7-9]|[79][1-9]|3[68]4[1347]|3(?:47|60)[1356]|3(?:3[46]|46|5[49])[1246]|3[4579]3[1357]"], "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "138", "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{2,10})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5,11})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "181", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d)(\\d{4,10})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1(?:3|80)|9", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{7,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[67]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{7,12})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["185", "1850", "18500"], "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "18[68]", "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "15[0568]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "15[1279]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "18", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{2})(\\d{7,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1(?:6[023]|7)", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "15[279]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "15", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[2579]\\d{5,14}|49(?:[34]0|69|8\\d)\\d\\d?|49(?:37|49|60|7[089]|9\\d)\\d{1,3}|49(?:[12]\\d|3[2-689]|7[1-7])\\d{1,8}|(?:1|[368]\\d|4[0-8])\\d{3,13}|49(?:[05]\\d|31|[46][1-8])\\d{1,9}"}, "fixedLine": {"possibleLengths": {"national": "[5-15]", "localOnly": "[2-4]"}, "exampleNumber": "30123456", "nationalNumberPattern": "32\\d{9,11}|49[3-6]\\d{10}|49[0-7]\\d{3,9}|(?:[34]0|[68]9)\\d{3,13}|(?:2(?:0[1-689]|[1-3569]\\d|4[0-8]|7[1-7]|8[0-7])|3(?:[3569]\\d|4[0-79]|7[1-7]|8[1-8])|4(?:1[02-9]|[2-48]\\d|5[0-6]|6[0-8]|7[0-79])|5(?:0[2-8]|[124-6]\\d|[38][0-8]|[79][0-7])|6(?:0[02-9]|[1-358]\\d|[47][0-8]|6[1-9])|7(?:0[2-8]|1[1-9]|[27][0-7]|3\\d|[4-6][0-8]|8[0-5]|9[013-7])|8(?:0[2-9]|1[0-79]|2\\d|3[0-46-9]|4[0-6]|5[013-9]|6[1-8]|7[0-8]|8[0-24-6])|9(?:0[6-9]|[1-4]\\d|[589][0-7]|6[0-8]|7[0-467]))\\d{3,12}"}, "mobile": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "15123456789", "nationalNumberPattern": "15[0-25-9]\\d{8}|1(?:6[023]|7\\d)\\d{7,8}"}, "pager": {"possibleLengths": {"national": "[4-14]"}, "exampleNumber": "16412345", "nationalNumberPattern": "16(?:4\\d{1,10}|[89]\\d{1,11})"}, "tollFree": {"possibleLengths": {"national": "[10-15]"}, "exampleNumber": "8001234567890", "nationalNumberPattern": "800\\d{7,12}"}, "premiumRate": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "9001234567", "nationalNumberPattern": "(?:137[7-9]|900(?:[135]|9\\d))\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "[7-14]"}, "exampleNumber": "18012345", "nationalNumberPattern": "180\\d{5,11}|13(?:7[1-6]\\d\\d|8)\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "11"}, "exampleNumber": "70012345678", "nationalNumberPattern": "700\\d{8}"}, "uan": {"possibleLengths": {"national": "[8-14]"}, "exampleNumber": "18500123456", "nationalNumberPattern": "18(?:1\\d{5,11}|[2-9]\\d{8})"}, "voicemail": {"possibleLengths": {"national": "12,13"}, "exampleNumber": "177991234567", "nationalNumberPattern": "1(?:6(?:013|255|399)|7(?:(?:[015]1|[69]3)3|[2-4]55|[78]99))\\d{7,8}|15(?:(?:[03-68]00|113)\\d|2\\d55|7\\d99|9\\d33)\\d{7}"}}, {"internationalPrefix": "00", "id": "DJ", "countryCode": "253", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[27]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:2\\d|77)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21360003", "nationalNumberPattern": "2(?:1[2-5]|7[45])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "77831001", "nationalNumberPattern": "77\\d{6}"}}, {"internationalPrefix": "00", "id": "DK", "countryCode": "45", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[2-9]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "[2-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "32123456", "nationalNumberPattern": "(?:[2-7]\\d|8[126-9]|9[1-46-9])\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "32123456", "nationalNumberPattern": "(?:[2-7]\\d|8[126-9]|9[1-46-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "80\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "90\\d{6}"}}, {"nationalPrefixForParsing": "1|([2-7]\\d{6})$", "countryCode": "1", "leadingDigits": "767", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "767$1", "internationalPrefix": "011", "id": "DM", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|767|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7674201234", "nationalNumberPattern": "767(?:2(?:55|66)|4(?:2[01]|4[0-25-9])|50[0-4])\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7672251234", "nationalNumberPattern": "767(?:2(?:[2-4689]5|7[5-7])|31[5-7]|61[1-8]|70[1-6])\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"countryCode": "1", "leadingDigits": "8001|8[024]9", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "internationalPrefix": "011", "id": "DO", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8092345678", "nationalNumberPattern": "8(?:[04]9[2-9]\\d\\d|29(?:2(?:[0-59]\\d|6[04-9]|7[0-27]|8[0237-9])|3(?:[0-35-9]\\d|4[7-9])|[45]\\d\\d|6(?:[0-27-9]\\d|[3-5][1-9]|6[0135-8])|7(?:0[013-9]|[1-37]\\d|4[1-35689]|5[1-4689]|6[1-57-9]|8[1-79]|9[1-8])|8(?:0[146-9]|1[0-48]|[248]\\d|3[1-79]|5[01589]|6[013-68]|7[124-8]|9[0-8])|9(?:[0-24]\\d|3[02-46-9]|5[0-79]|60|7[0169]|8[57-9]|9[02-9])))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8092345678", "nationalNumberPattern": "8[024]9[2-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00(?:14|[2-9]\\d)|(?:33|44|55|66|77|88)[2-9]\\d)\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "DZ", "countryCode": "213", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-4]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[5-8]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:[1-4]|[5-79]\\d|80)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "12345678", "nationalNumberPattern": "9619\\d{5}|(?:1\\d|2[013-79]|3[0-8]|4[0135689])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "551234567", "nationalNumberPattern": "(?:5(?:4[0-29]|5\\d|6[01])|6(?:[569]\\d|7[0-6])|7[7-9]\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "808123456", "nationalNumberPattern": "80[3-689]1\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "801123456", "nationalNumberPattern": "80[12]1\\d{5}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "983123456", "nationalNumberPattern": "98[23]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "EC", "countryCode": "593", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-7]", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[2-7]", "format": "$1 $2-$3", "intlFormat": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3,4})", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{9,10}|(?:[2-7]|9\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "22123456", "nationalNumberPattern": "[2-7][2-7]\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "991234567", "nationalNumberPattern": "964[0-2]\\d{5}|9(?:39|[57][89]|6[0-36-9]|[89]\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "18001234567", "nationalNumberPattern": "1800\\d{7}|1[78]00\\d{6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "28901234", "nationalNumberPattern": "[2-7]890\\d{4}"}}, {"internationalPrefix": "00", "id": "EE", "countryCode": "372", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": ["[369]|4[3-8]|5(?:[0-2]|5[0-478]|6[45])|7[1-9]|88", "[369]|4[3-8]|5(?:[02]|1(?:[0-8]|95)|5[0-478]|6(?:4[0-4]|5[1-589]))|7[1-9]|88"], "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{3,4})", "leadingDigits": ["[45]|8(?:00|[1-49])", "[45]|8(?:00[1-9]|[1-49])"], "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{2})(\\d{4})", "leadingDigits": "7", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "8\\d{9}|[4578]\\d{7}|(?:[3-8]\\d|90)\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "7"}, "nationalNumberPattern": "800[2-9]\\d{3}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "3212345", "nationalNumberPattern": "(?:3[23589]|4[3-8]|6\\d|7[1-9]|88)\\d{5}"}, "mobile": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "51234567", "nationalNumberPattern": "5(?:[0-35-9]\\d{6}|4(?:[0-57-9]\\d{5}|6(?:[0-24-9]\\d{4}|3(?:[0-35-9]\\d{3}|4000))))|8(?:1(?:0(?:000|[3-9]\\d\\d)|(?:1(?:0[236]|1\\d)|(?:23|[3-79]\\d)\\d)\\d)|2(?:0(?:000|(?:19|[24-7]\\d)\\d)|(?:(?:[124-6]\\d|3[5-9]|8[2-4])\\d|7(?:[679]\\d|8[13-9]))\\d)|[349]\\d{4})\\d\\d|5(?:(?:[02]\\d|5[0-478])\\d|1(?:[0-8]\\d|95)|6(?:4[0-4]|5[1-589]))\\d{3}"}, "tollFree": {"possibleLengths": {"national": "7,8,10"}, "exampleNumber": "80012345", "nationalNumberPattern": "800(?:(?:0\\d\\d|1)\\d|[2-9])\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "9001234", "nationalNumberPattern": "(?:40\\d\\d|900)\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "70012345", "nationalNumberPattern": "70[0-2]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "EG", "countryCode": "20", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{7,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{6,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[35]|[4-6]|8[2468]|9[235-7]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[189]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[189]\\d{8,9}|[24-6]\\d{8}|[135]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8,9", "localOnly": "6,7"}, "exampleNumber": "234567890", "nationalNumberPattern": "13[23]\\d{6}|(?:15|57)\\d{6,7}|(?:2[2-4]|3|4[05-8]|5[05]|6[24-689]|8[2468]|9[235-7])\\d{7}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "1001234567", "nationalNumberPattern": "1[0-25]\\d{8}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9001234567", "nationalNumberPattern": "900\\d{7}"}}, {"nationalPrefix": "0", "leadingDigits": "528[89]", "internationalPrefix": "00", "id": "EH", "countryCode": "212", "generalDesc": {"nationalNumberPattern": "[5-8]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "528812345", "nationalNumberPattern": "528[89]\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "650123456", "nationalNumberPattern": "(?:6(?:[0-79]\\d|8[0-247-9])|7(?:0[0-8]|6[1267]|7[0-37]))\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "80\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "891234567", "nationalNumberPattern": "89\\d{7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "592401234", "nationalNumberPattern": "592(?:4[0-2]|93)\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "ER", "countryCode": "291", "availableFormats": {"numberFormat": {"pattern": "(\\d)(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[178]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[178]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7", "localOnly": "6"}, "exampleNumber": "8370362", "nationalNumberPattern": "(?:1(?:1[12568]|[24]0|55|6[146])|8\\d\\d)\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "7123456", "nationalNumberPattern": "(?:17[1-3]|7\\d\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "ES", "countryCode": "34", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})", "leadingDigits": "905", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{6})", "leadingDigits": "[79]9", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[89]00", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[5-9]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[5-9]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "810123456", "nationalNumberPattern": "96906(?:0[0-8]|1[1-9]|[2-9]\\d)\\d\\d|9(?:69(?:0[0-57-9]|[1-9]\\d)|73(?:[0-8]\\d|9[1-9]))\\d{4}|(?:8(?:[1356]\\d|[28][0-8]|[47][1-9])|9(?:[135]\\d|[268][0-8]|4[1-9]|7[124-9]))\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "612345678", "nationalNumberPattern": "(?:590[16]00\\d|9(?:6906(?:09|10)|7390\\d\\d))\\d\\d|(?:6\\d|7[1-48])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "[89]00\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "803123456", "nationalNumberPattern": "80[367]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "901123456", "nationalNumberPattern": "90[12]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "701234567", "nationalNumberPattern": "70\\d{7}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "511234567", "nationalNumberPattern": "51\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "ET", "countryCode": "251", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-59]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "(?:11|[2-59]\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "111112345", "nationalNumberPattern": "11667[01]\\d{3}|(?:11(?:1(?:1[124]|2[2-7]|3[1-5]|5[5-8]|8[6-8])|2(?:13|3[6-8]|5[89]|7[05-9]|8[2-6])|3(?:2[01]|3[0-289]|4[1289]|7[1-4]|87)|4(?:1[69]|3[2-49]|4[0-3]|6[5-8])|5(?:1[578]|44|5[0-4])|6(?:1[78]|2[69]|39|4[5-7]|5[1-5]|6[0-59]|8[015-8]))|2(?:2(?:11[1-9]|22[0-7]|33\\d|44[1467]|66[1-68])|5(?:11[124-6]|33[2-8]|44[1467]|55[14]|66[1-3679]|77[124-79]|880))|3(?:3(?:11[0-46-8]|(?:22|55)[0-6]|33[0134689]|44[04]|66[01467])|4(?:44[0-8]|55[0-69]|66[0-3]|77[1-5]))|4(?:6(?:119|22[0-24-7]|33[1-5]|44[13-69]|55[14-689]|660|88[1-4])|7(?:(?:11|22)[1-9]|33[13-7]|44[13-6]|55[1-689]))|5(?:7(?:227|55[05]|(?:66|77)[14-8])|8(?:11[149]|22[013-79]|33[0-68]|44[013-8]|550|66[1-5]|77\\d)))\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "911234567", "nationalNumberPattern": "9\\d{8}"}}, {"mainCountryForCode": "true", "countryCode": "358", "leadingDigits": "1[03-79]|[2-9]", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredInternationalPrefix": "00", "internationalPrefix": "00|99(?:[01469]|5(?:[14]1|3[23]|5[59]|77|88|9[09]))", "id": "FI", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "75[12]", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d)(\\d{4,9})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2568][1-8]|3(?:0[1-9]|[1-9])|9", "format": "$1 $2"}, {"pattern": "(\\d{6})", "leadingDigits": "11", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]00|[368]|70[07-9]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{4,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1245]|7[135]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{6,10})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[1-35689]\\d{4}|7\\d{10,11}|(?:[124-7]\\d|3[0-46-9])\\d{8}|[1-9]\\d{5,8}"}, "noInternationalDialling": {"possibleLengths": {"national": "[5-12]"}, "nationalNumberPattern": "20(?:2[023]|9[89])\\d{1,6}|(?:60[12]\\d|7099)\\d{4,5}|(?:606|7(?:0[78]|1|3\\d))\\d{7}|(?:[1-3]00|7(?:0[1-5]\\d\\d|5[03-9]))\\d{3,7}"}, "fixedLine": {"possibleLengths": {"national": "[5-9]"}, "exampleNumber": "131234567", "nationalNumberPattern": "(?:1[3-79][1-8]|[235689][1-8]\\d)\\d{2,6}"}, "mobile": {"possibleLengths": {"national": "[6-10]"}, "exampleNumber": "412345678", "nationalNumberPattern": "(?:4[0-8]|50)\\d{4,8}"}, "tollFree": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{4,6}"}, "premiumRate": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "600123456", "nationalNumberPattern": "[67]00\\d{5,6}"}, "uan": {"possibleLengths": {"national": "[5-12]"}, "exampleNumber": "10112345", "nationalNumberPattern": "20\\d{4,8}|60[12]\\d{5,6}|7(?:099\\d{4,5}|5[03-9]\\d{3,7})|20[2-59]\\d\\d|(?:606|7(?:0[78]|1|3\\d))\\d{7}|(?:10|29|3[09]|70[1-5]\\d)\\d{4,8}"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "0(?:0|52)", "id": "FJ", "countryCode": "679", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[235-9]|45", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "0", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "45\\d{5}|(?:0800\\d|[235-9])\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "3212345", "nationalNumberPattern": "603\\d{4}|(?:3[0-5]|6[25-7]|8[58])\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "7012345", "nationalNumberPattern": "(?:[279]\\d|45|5[01568]|8[034679])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "11"}, "exampleNumber": "08001234567", "nationalNumberPattern": "0800\\d{7}"}}, {"internationalPrefix": "00", "id": "FK", "countryCode": "500", "generalDesc": {"nationalNumberPattern": "[2-7]\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "31234", "nationalNumberPattern": "[2-47]\\d{4}"}, "mobile": {"possibleLengths": {"national": "5"}, "exampleNumber": "51234", "nationalNumberPattern": "[56]\\d{4}"}}, {"internationalPrefix": "00", "id": "FM", "countryCode": "691", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[389]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[39]\\d\\d|820)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "3201234", "nationalNumberPattern": "31(?:00[67]|208|309)\\d\\d|(?:3(?:[2357]0[1-9]|602|804|905)|(?:820|9[2-6]\\d)\\d)\\d{3}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "3501234", "nationalNumberPattern": "31(?:00[67]|208|309)\\d\\d|(?:3(?:[2357]0[1-9]|602|804|905)|(?:820|9[2-7]\\d)\\d)\\d{3}"}}, {"nationalPrefixForParsing": "(10(?:01|[12]0|88))", "internationalPrefix": "00", "id": "FO", "countryCode": "298", "availableFormats": {"numberFormat": {"pattern": "(\\d{6})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "[2-9]", "format": "$1"}}, "generalDesc": {"nationalNumberPattern": "[2-9]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6"}, "exampleNumber": "201234", "nationalNumberPattern": "(?:20|[34]\\d|8[19])\\d{4}"}, "mobile": {"possibleLengths": {"national": "6"}, "exampleNumber": "211234", "nationalNumberPattern": "(?:[27][1-9]|5\\d|91)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "6"}, "exampleNumber": "802123", "nationalNumberPattern": "80[257-9]\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "6"}, "exampleNumber": "901123", "nationalNumberPattern": "90(?:[13-5][15-7]|2[125-7]|9\\d)\\d\\d"}, "voip": {"possibleLengths": {"national": "6"}, "exampleNumber": "601234", "nationalNumberPattern": "(?:6[0-36]|88)\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "FR", "countryCode": "33", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})", "leadingDigits": "10", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "1", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "8", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d)(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-79]", "format": "$1 $2 $3 $4 $5"}]}, "generalDesc": {"nationalNumberPattern": "[1-9]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "123456789", "nationalNumberPattern": "(?:[1-35]\\d|4[1-9])\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "612345678", "nationalNumberPattern": "(?:6(?:[0-24-8]\\d|3[0-8]|9[589])|7(?:00|[3-9]\\d))\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "80[0-5]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "891123456", "nationalNumberPattern": "836(?:0[0-36-9]|[1-9]\\d)\\d{4}|8(?:1[2-9]|2[2-47-9]|3[0-57-9]|[569]\\d|8[0-35-9])\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "884012345", "nationalNumberPattern": "8(?:1[01]|2[0156]|84)\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "9\\d{8}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "806123456", "nationalNumberPattern": "80[6-9]\\d{6}"}}, {"nationalPrefixForParsing": "0(11\\d{6}|6[256]\\d{6}|7[47]\\d{6})", "internationalPrefix": "00", "id": "GA", "countryCode": "241", "nationalPrefixTransformRule": "$1", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "0$FG", "leadingDigits": "[2-7]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "0$FG", "leadingDigits": "11|[67]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "0", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:[067]\\d|11)\\d{6}|[2-7]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "01441234", "nationalNumberPattern": "[01]1\\d{6}"}, "mobile": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "06031234", "nationalNumberPattern": "(?:0[2-7]|6[256]|7[47])\\d{6}|[2-7]\\d{6}"}}, {"mainCountryForCode": "true", "countryCode": "44", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredExtnPrefix": " x", "internationalPrefix": "00", "id": "GB", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["800", "8001", "80011", "800111", "8001111"], "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["845", "8454", "84546", "845464"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "800", "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["1(?:38|5[23]|69|76|94)", "1(?:(?:38|69)7|5(?:24|39)|768|946)", "1(?:3873|5(?:242|39[4-6])|(?:697|768)[347]|9467)"], "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{5,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1(?:[2-69][02-9]|[78])", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["[25]|7(?:0|6[02-9])", "[25]|7(?:0|6(?:[03-9]|2[356]))"], "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1389]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[1-357-9]\\d{9}|[18]\\d{8}|8\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9,10", "localOnly": "[4-8]"}, "exampleNumber": "1212345678", "nationalNumberPattern": "(?:1(?:1(?:3(?:[0-58]\\d\\d|73[03])|4(?:[0-5]\\d\\d|69[7-9])|(?:5[0-26-9]|6[0-4]|[78][0-49])\\d\\d)|(?:2(?:(?:0[024-9]|2[3-9]|3[3-79]|4[1-689]|[58][02-9]|6[0-47-9]|7[013-9]|9\\d)\\d|1(?:[0-7]\\d|8[02]))|(?:3(?:0\\d|1[0-8]|[25][02-9]|3[02-579]|[468][0-46-9]|7[1-35-79]|9[2-578])|4(?:0[03-9]|[137]\\d|[28][02-57-9]|4[02-69]|5[0-8]|[69][0-79])|5(?:0[1-35-9]|[16]\\d|2[024-9]|3[015689]|4[02-9]|5[03-9]|7[0-35-9]|8[0-468]|9[0-57-9])|6(?:0[034689]|1\\d|2[0-35689]|[38][013-9]|4[1-467]|5[0-69]|6[13-9]|7[0-8]|9[0-24578])|7(?:0[0246-9]|2\\d|3[0236-8]|4[03-9]|5[0-46-9]|6[013-9]|7[0-35-9]|8[024-9]|9[02-9])|8(?:0[35-9]|2[1-57-9]|3[02-578]|4[0-578]|5[124-9]|6[2-69]|7\\d|8[02-9]|9[02569])|9(?:0[02-589]|[18]\\d|2[02-689]|3[1-57-9]|4[2-9]|5[0-579]|6[2-47-9]|7[0-24578]|9[2-57]))\\d)\\d)|2(?:0[013478]|3[0189]|4[017]|8[0-46-9]|9[0-2])\\d{3})\\d{4}|1(?:2(?:0(?:46[1-4]|87[2-9])|545[1-79]|76(?:2\\d|3[1-8]|6[1-6])|9(?:7(?:2[0-4]|3[2-5])|8(?:2[2-8]|7[0-47-9]|8[3-5])))|3(?:6(?:38[2-5]|47[23])|8(?:47[04-9]|64[0157-9]))|4(?:044[1-7]|20(?:2[23]|8\\d)|6(?:0(?:30|5[2-57]|6[1-8]|7[2-8])|140)|8(?:052|87[1-3]))|5(?:2(?:4(?:3[2-79]|6\\d)|76\\d)|6(?:26[06-9]|686))|6(?:06(?:4\\d|7[4-79])|295[5-7]|35[34]\\d|47(?:24|61)|59(?:5[08]|6[67]|74)|9(?:55[0-4]|77[23]))|7(?:26(?:6[13-9]|7[0-7])|(?:442|688)\\d|50(?:2[0-3]|[3-68]2|76))|8(?:27[56]\\d|37(?:5[2-5]|8[239])|843[2-58])|9(?:0(?:0(?:6[1-8]|85)|52\\d)|3583|4(?:66[1-8]|9(?:2[01]|81))|63(?:23|3[1-4])|9561))\\d{3}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "7400123456", "nationalNumberPattern": "7(?:457[0-57-9]|700[01]|911[028])\\d{5}|7(?:[1-3]\\d\\d|4(?:[0-46-9]\\d|5[0-689])|5(?:0[0-8]|[13-9]\\d|2[0-35-9])|7(?:0[1-9]|[1-7]\\d|8[02-9]|9[0-689])|8(?:[014-9]\\d|[23][0-8])|9(?:[024-9]\\d|1[02-9]|3[0-689]))\\d{6}"}, "pager": {"possibleLengths": {"national": "10"}, "exampleNumber": "7640123456", "nationalNumberPattern": "76(?:464|652)\\d{5}|76(?:0[0-2]|2[356]|34|4[01347]|5[49]|6[0-369]|77|81|9[139])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7,9,10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "80[08]\\d{7}|800\\d{6}|8001111"}, "premiumRate": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "9012345678", "nationalNumberPattern": "(?:8(?:4[2-5]|7[0-3])|9(?:[01]\\d|8[2-49]))\\d{7}|845464\\d"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "7012345678", "nationalNumberPattern": "70\\d{8}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5612345678", "nationalNumberPattern": "56\\d{8}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "5512345678", "nationalNumberPattern": "(?:3[0347]|55)\\d{8}"}}, {"nationalPrefixForParsing": "1|([2-9]\\d{6})$", "countryCode": "1", "leadingDigits": "473", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "473$1", "internationalPrefix": "011", "id": "GD", "generalDesc": {"nationalNumberPattern": "(?:473|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "4732691234", "nationalNumberPattern": "473(?:2(?:3[0-2]|69)|3(?:2[89]|86)|4(?:[06]8|3[5-9]|4[0-49]|5[5-79]|73|90)|63[68]|7(?:58|84)|800|938)\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "4734031234", "nationalNumberPattern": "473(?:4(?:0[2-79]|1[04-9]|2[0-5]|58)|5(?:2[01]|3[3-8])|901)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "GE", "countryCode": "995", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "70", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "32", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[57]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[348]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:[3-57]\\d\\d|800)\\d{6}"}, "noInternationalDialling": {"possibleLengths": {"national": "9"}, "nationalNumberPattern": "70[67]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "6,7"}, "exampleNumber": "322123456", "nationalNumberPattern": "(?:3(?:[256]\\d|4[124-9]|7[0-4])|4(?:1\\d|2[2-7]|3[1-79]|4[2-8]|7[239]|9[1-7]))\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "555123456", "nationalNumberPattern": "5(?:0(?:0(?:0\\d|50)\\d|555[5-9])|(?:111\\d|8(?:58[89]|888))\\d|(?:2222|3333)[0-4]|52(?:00\\d|22[0-4])|75(?:00\\d|7(?:7[7-9]|8[01])))\\d{3}|(?:5(?:[14]4|5[0157-9]|68|7[0147-9]|9[1-35-9])|790)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "706123456", "nationalNumberPattern": "70[67]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "GF", "countryCode": "594", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[569]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:[56]94|976)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "594101234", "nationalNumberPattern": "594(?:[023]\\d|1[01]|4[03-9]|5[6-9]|6[0-3]|80|9[014])\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "694201234", "nationalNumberPattern": "694(?:[0-249]\\d|3[0-48])\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "976012345", "nationalNumberPattern": "976\\d{6}"}}, {"nationalPrefixForParsing": "0|([25-9]\\d{5})$", "countryCode": "44", "nationalPrefix": "0", "nationalPrefixTransformRule": "1481$1", "internationalPrefix": "00", "id": "GG", "generalDesc": {"nationalNumberPattern": "(?:1481|[357-9]\\d{3})\\d{6}|8\\d{6}(?:\\d{2})?"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "6"}, "exampleNumber": "1481256789", "nationalNumberPattern": "1481[25-9]\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "7781123456", "nationalNumberPattern": "7(?:(?:781|839)\\d|911[17])\\d{5}"}, "pager": {"possibleLengths": {"national": "10"}, "exampleNumber": "7640123456", "nationalNumberPattern": "76(?:464|652)\\d{5}|76(?:0[0-2]|2[356]|34|4[01347]|5[49]|6[0-369]|77|81|9[139])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7,9,10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "80[08]\\d{7}|800\\d{6}|8001111"}, "premiumRate": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "9012345678", "nationalNumberPattern": "(?:8(?:4[2-5]|7[0-3])|9(?:[01]\\d|8[0-3]))\\d{7}|845464\\d"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "7012345678", "nationalNumberPattern": "70\\d{8}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5612345678", "nationalNumberPattern": "56\\d{8}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "5512345678", "nationalNumberPattern": "(?:3[0347]|55)\\d{8}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "GH", "countryCode": "233", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[237]|8[0-2]", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[235]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[235]\\d{3}|800)\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "800\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "302345678", "nationalNumberPattern": "3082[0-5]\\d{4}|3(?:0(?:[237]\\d|8[01])|[167](?:2[0-6]|7\\d|80)|2(?:2[0-5]|7\\d|80)|3(?:2[0-3]|7\\d|80)|4(?:2[013-9]|3[01]|7\\d|80)|5(?:2[0-7]|7\\d|80)|8(?:2[0-2]|7\\d|80)|9(?:[28]0|7\\d))\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "231234567", "nationalNumberPattern": "(?:2[0346-8]\\d|5(?:[0457]\\d|6[01]|9[1-6]))\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}}, {"internationalPrefix": "00", "id": "GI", "countryCode": "350", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{5})", "leadingDigits": "2", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[25]\\d\\d|606)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "20012345", "nationalNumberPattern": "21(?:6[24-7]\\d|90[0-2])\\d{3}|2(?:00|2[25])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "57123456", "nationalNumberPattern": "(?:5[146-8]\\d|606)\\d{5}"}}, {"internationalPrefix": "00", "id": "GL", "countryCode": "299", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "19|[2-689]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "(?:19|[2-689]\\d)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "6"}, "exampleNumber": "321000", "nationalNumberPattern": "(?:19|3[1-7]|6[14689]|8[14-79]|9\\d)\\d{4}"}, "mobile": {"possibleLengths": {"national": "6"}, "exampleNumber": "221234", "nationalNumberPattern": "[245]\\d{5}"}, "tollFree": {"possibleLengths": {"national": "6"}, "exampleNumber": "801234", "nationalNumberPattern": "80\\d{4}"}, "voip": {"possibleLengths": {"national": "6"}, "exampleNumber": "381234", "nationalNumberPattern": "3[89]\\d{4}"}}, {"internationalPrefix": "00", "id": "GM", "countryCode": "220", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "[2-9]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "5661234", "nationalNumberPattern": "(?:4(?:[23]\\d\\d|4(?:1[024679]|[6-9]\\d))|5(?:5(?:3\\d|4[0-7])|6[67]\\d|7(?:1[04]|2[035]|3[58]|48))|8\\d{3})\\d{3}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "3012345", "nationalNumberPattern": "(?:[23679]\\d|5[0-389])\\d{5}"}}, {"internationalPrefix": "00", "id": "GN", "countryCode": "224", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "3", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[67]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "722\\d{6}|(?:3|6\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "30241234", "nationalNumberPattern": "3(?:0(?:24|3[12]|4[1-35-7]|5[13]|6[189]|[78]1|9[1478])|1\\d\\d)\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "601123456", "nationalNumberPattern": "6[0-356]\\d{7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "722123456", "nationalNumberPattern": "722\\d{6}"}}, {"mainCountryForCode": "true", "countryCode": "590", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "internationalPrefix": "00", "id": "GP", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[569]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:590|69\\d|976)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "590201234", "nationalNumberPattern": "590(?:0[1-68]|1[0-2]|2[0-68]|3[1289]|4[0-24-9]|5[3-579]|6[0189]|7[08]|8[0-689]|9\\d)\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "690001234", "nationalNumberPattern": "69(?:0\\d\\d|1(?:2[29]|3[0-5]))\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "976012345", "nationalNumberPattern": "976[01]\\d{5}"}}, {"internationalPrefix": "00", "id": "GQ", "countryCode": "240", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[235]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{6})", "leadingDigits": "[89]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "222\\d{6}|(?:3\\d|55|[89]0)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "333091234", "nationalNumberPattern": "33[0-24-9]\\d[46]\\d{4}|3(?:33|5\\d)\\d[7-9]\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "222123456", "nationalNumberPattern": "(?:222|55\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80\\d[1-9]\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "90\\d[1-9]\\d{5}"}}, {"internationalPrefix": "00", "id": "GR", "countryCode": "30", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{4})(\\d{4})", "leadingDigits": "21|7", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{6})", "leadingDigits": "2(?:2|3[2-57-9]|4[2-469]|5[2-59]|6[2-9]|7[2-69]|8[2-49])|5", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "[2689]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "5005000\\d{3}|(?:[2689]\\d|70)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "10"}, "exampleNumber": "2123456789", "nationalNumberPattern": "2(?:1\\d\\d|2(?:2[1-46-9]|[36][1-8]|4[1-7]|5[1-4]|7[1-5]|[89][1-9])|3(?:1\\d|2[1-57]|[35][1-3]|4[13]|7[1-7]|8[124-6]|9[1-79])|4(?:1\\d|2[1-8]|3[1-4]|4[13-5]|6[1-578]|9[1-5])|5(?:1\\d|[29][1-4]|3[1-5]|4[124]|5[1-6])|6(?:1\\d|[269][1-6]|3[1245]|4[1-7]|5[13-9]|7[14]|8[1-5])|7(?:1\\d|2[1-5]|3[1-6]|4[1-7]|5[1-57]|6[135]|9[125-7])|8(?:1\\d|2[1-5]|[34][1-4]|9[1-57]))\\d{6}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "6912345678", "nationalNumberPattern": "68[57-9]\\d{7}|(?:69|94)\\d{8}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9091234567", "nationalNumberPattern": "90[19]\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "8011234567", "nationalNumberPattern": "8(?:0[16]|12|[27]5|50)\\d{7}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "7012345678", "nationalNumberPattern": "70\\d{8}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "5005000123", "nationalNumberPattern": "5005000\\d{3}"}}, {"internationalPrefix": "00", "id": "GT", "countryCode": "502", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[2-7]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:1\\d{3}|[2-7])\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22456789", "nationalNumberPattern": "[267][2-9]\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "51234567", "nationalNumberPattern": "[3-5]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "11"}, "exampleNumber": "18001112222", "nationalNumberPattern": "18[01]\\d{8}"}, "premiumRate": {"possibleLengths": {"national": "11"}, "exampleNumber": "19001112222", "nationalNumberPattern": "19\\d{9}"}}, {"nationalPrefixForParsing": "1|([3-9]\\d{6})$", "countryCode": "1", "leadingDigits": "671", "nationalPrefix": "1", "nationalPrefixTransformRule": "671$1", "internationalPrefix": "011", "id": "GU", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|671|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6713001234", "nationalNumberPattern": "671(?:3(?:00|3[39]|4[349]|55|6[26])|4(?:00|56|7[1-9]|8[0236-9])|5(?:55|6[2-5]|88)|6(?:3[2-578]|4[24-9]|5[34]|78|8[235-9])|7(?:[0479]7|2[0167]|3[45]|8[7-9])|8(?:[2-57-9]8|6[48])|9(?:2[29]|6[79]|7[1279]|8[7-9]|9[78]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6713001234", "nationalNumberPattern": "671(?:3(?:00|3[39]|4[349]|55|6[26])|4(?:00|56|7[1-9]|8[0236-9])|5(?:55|6[2-5]|88)|6(?:3[2-578]|4[24-9]|5[34]|78|8[235-9])|7(?:[0479]7|2[0167]|3[45]|8[7-9])|8(?:[2-57-9]8|6[48])|9(?:2[29]|6[79]|7[1279]|8[7-9]|9[78]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"internationalPrefix": "00", "id": "GW", "countryCode": "245", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "40", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[49]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[49]\\d{8}|4\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "443201234", "nationalNumberPattern": "443\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "955012345", "nationalNumberPattern": "9(?:5\\d|6[569]|77)\\d{6}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "4012345", "nationalNumberPattern": "40\\d{5}"}}, {"internationalPrefix": "001", "id": "GY", "countryCode": "592", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-46-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:862\\d|9008)\\d{3}|(?:[2-46]\\d|77)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2201234", "nationalNumberPattern": "(?:2(?:1[6-9]|2[0-35-9]|3[1-4]|5[3-9]|6\\d|7[0-24-79])|3(?:2[25-9]|3\\d)|4(?:4[0-24]|5[56])|77[1-57])\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "6091234", "nationalNumberPattern": "6\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "2891234", "nationalNumberPattern": "(?:289|862)\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9008123", "nationalNumberPattern": "9008\\d{3}"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "00(?:30|5[09]|[126-9]?)", "id": "HK", "countryCode": "852", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2,5})", "leadingDigits": ["900", "9003"], "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[2-7]|8[1-4]|9(?:0[1-9]|[1-8])", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "8", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})(\\d{3})", "leadingDigits": "9", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "8[0-46-9]\\d{6,7}|9\\d{4}(?:\\d(?:\\d(?:\\d{4})?)?)?|(?:[235-79]\\d|46)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:2(?:[13-9]\\d|2[013-9])\\d|3(?:(?:[1569][0-24-9]|4[0-246-9]|7[0-24-69])\\d|8(?:4[0-6]|5[0-5]|9\\d))|58(?:0[1-8]|1[2-9]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "51234567", "nationalNumberPattern": "(?:46(?:0[0-7]|1[0-6]|4[0-57-9]|5[0-8]|6[0-4])|5730|6(?:26[013-7]|66[0-3])|70(?:7[1-5]|8[0-4])|848[015-9]|929[03-9])\\d{4}|(?:46[23]|5(?:[1-59][0-46-9]|6[0-4689]|7[0-2469])|6(?:0[1-9]|[13-59]\\d|[268][0-57-9]|7[0-79])|849|9(?:0[1-9]|1[02-9]|[2358][0-8]|[467]\\d))\\d{5}"}, "pager": {"possibleLengths": {"national": "8"}, "exampleNumber": "71123456", "nationalNumberPattern": "7(?:1(?:0[0-38]|1[0-3679]|3[013]|69|9[0136])|2(?:[02389]\\d|1[18]|7[27-9])|3(?:[0-38]\\d|7[0-369]|9[2357-9])|47\\d|5(?:[178]\\d|5[0-5])|6(?:0[0-7]|2[236-9]|[35]\\d)|7(?:[27]\\d|8[7-9])|8(?:[23689]\\d|7[1-9])|9(?:[025]\\d|6[0-246-8]|7[0-36-9]|8[238]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "[5-8],11"}, "exampleNumber": "90012345678", "nationalNumberPattern": "900(?:[0-24-9]\\d{7}|3\\d{1,4})"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "81123456", "nationalNumberPattern": "8(?:1[0-4679]\\d|2(?:[0-36]\\d|7[0-4])|3(?:[034]\\d|2[09]|70))\\d{4}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "30161234", "nationalNumberPattern": "30(?:0[1-9]|[15-7]\\d|2[047]|89)\\d{4}"}}, {"internationalPrefix": "00", "id": "HN", "countryCode": "504", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[237-9]", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4})", "leadingDigits": "8", "format": "$1 $2 $3", "intlFormat": "NA"}]}, "generalDesc": {"nationalNumberPattern": "8\\d{10}|[237-9]\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "11"}, "nationalNumberPattern": "8002\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22123456", "nationalNumberPattern": "2(?:2(?:0[0-39]|1[1-36]|[23]\\d|4[04-6]|5[57]|6[245]|7[0135689]|8[01346-9]|9[0-2])|4(?:0[78]|2[3-59]|3[13-689]|4[0-68]|5[1-35])|5(?:0[7-9]|16|4[03-5]|5\\d|6[014-6]|74|80)|6(?:[056]\\d|17|2[07]|3[04]|4[0-378]|[78][0-8]|9[01])|7(?:6[46-9]|7[02-9]|8[034]|91)|8(?:79|8[0-357-9]|9[1-57-9]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "91234567", "nationalNumberPattern": "[37-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "11"}, "exampleNumber": "80021234567", "nationalNumberPattern": "8002\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "HR", "countryCode": "385", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6[01]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{4})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[67]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-5]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[24-69]\\d|3[0-79])\\d{7}|80\\d{5,7}|[1-79]\\d{7}|6\\d{5,6}"}, "fixedLine": {"possibleLengths": {"national": "8,9", "localOnly": "6,7"}, "exampleNumber": "12345678", "nationalNumberPattern": "1\\d{7}|(?:2[0-3]|3[1-5]|4[02-47-9]|5[1-3])\\d{6,7}"}, "mobile": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "921234567", "nationalNumberPattern": "9(?:751\\d{5}|8\\d{6,7})|9(?:0[1-9]|[1259]\\d|7[0679])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "800123456", "nationalNumberPattern": "80[01]\\d{4,6}"}, "premiumRate": {"possibleLengths": {"national": "[6-8]"}, "exampleNumber": "611234", "nationalNumberPattern": "6[01459]\\d{6}|6[01]\\d{4,5}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "74123456", "nationalNumberPattern": "7[45]\\d{6}"}, "uan": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "62123456", "nationalNumberPattern": "62\\d{6,7}|72\\d{6}"}}, {"internationalPrefix": "00", "id": "HT", "countryCode": "509", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{4})", "leadingDigits": "[2-489]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[2-489]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22453300", "nationalNumberPattern": "2(?:2\\d|5[1-5]|81|9[149])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "34101234", "nationalNumberPattern": "[34]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "8\\d{7}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "98901234", "nationalNumberPattern": "9(?:[67][0-4]|8[0-3589]|9\\d)\\d{5}"}}, {"nationalPrefix": "06", "internationalPrefix": "00", "id": "HU", "countryCode": "36", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "($NP $FG)", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "($NP $FG)", "leadingDigits": "[27][2-9]|3[2-7]|4[24-9]|5[2-79]|6|8[2-57-9]|9[2-69]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "[2-9]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[235-7]\\d{8}|[1-9]\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "8,9"}, "nationalNumberPattern": "(?:[48]0\\d|6802)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6,7"}, "exampleNumber": "12345678", "nationalNumberPattern": "(?:1\\d|[27][2-9]|3[2-7]|4[24-9]|5[2-79]|6[23689]|8[2-57-9]|9[2-69])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "201234567", "nationalNumberPattern": "(?:[257]0|3[01])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "80123456", "nationalNumberPattern": "(?:[48]0\\d|6802)\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "9[01]\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "211234567", "nationalNumberPattern": "21\\d{7}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "381234567", "nationalNumberPattern": "38\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00[89]", "id": "ID", "countryCode": "62", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{3})", "leadingDigits": "15", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{5,9})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2[124]|[36]1", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "800", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5,8})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[2-79]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3,4})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8[1-35-9]", "format": "$1-$2-$3"}, {"pattern": "(\\d{3})(\\d{6,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "804", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d)(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "80", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1-$2-$3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "001", "format": "$1 $2 $3 $4", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "0", "format": "$1 $2 $3 $4", "intlFormat": "NA"}]}, "generalDesc": {"nationalNumberPattern": "(?:(?:00[1-9]|8\\d)\\d{4}|[1-36])\\d{6}|00\\d{10}|[1-9]\\d{8,10}|[2-9]\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "10,12,13"}, "nationalNumberPattern": "001803\\d{6,7}|(?:007803\\d|8071)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "[7-11]", "localOnly": "5,6"}, "exampleNumber": "218350123", "nationalNumberPattern": "2[124]\\d{7,8}|619\\d{8}|2(?:1(?:14|500)|2\\d{3})\\d{3}|61\\d{5,8}|(?:2(?:[35][1-4]|6[0-8]|7[1-6]|8\\d|9[1-8])|3(?:1|[25][1-8]|3[1-68]|4[1-3]|6[1-3568]|7[0-469]|8\\d)|4(?:0[1-589]|1[01347-9]|2[0-36-8]|3[0-24-68]|43|5[1-378]|6[1-5]|7[134]|8[1245])|5(?:1[1-35-9]|2[25-8]|3[124-9]|4[1-3589]|5[1-46]|6[1-8])|6(?:[25]\\d|3[1-69]|4[1-6])|7(?:02|[125][1-9]|[36]\\d|4[1-8]|7[0-36-9])|9(?:0[12]|1[013-8]|2[0-479]|5[125-8]|6[23679]|7[159]|8[01346]))\\d{5,8}"}, "mobile": {"possibleLengths": {"national": "[9-12]"}, "exampleNumber": "812345678", "nationalNumberPattern": "8[1-35-9]\\d{7,10}"}, "tollFree": {"possibleLengths": {"national": "[8-13]"}, "exampleNumber": "8001234567", "nationalNumberPattern": "00[17]803\\d{7}|(?:177\\d|800)\\d{5,7}|001803\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "8091234567", "nationalNumberPattern": "809\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "8041234567", "nationalNumberPattern": "804\\d{7}"}, "uan": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "8071123456", "nationalNumberPattern": "(?:1500|8071\\d{3})\\d{3}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "IE", "countryCode": "353", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2[24-9]|47|58|6[237-9]|9[35-9]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[45]0", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3,4})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[2569]|4[1-69]|7[14]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "70", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "81", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[78]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "4", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:1\\d|[2569])\\d{6,8}|4\\d{6,9}|7\\d{8}|8\\d{8,9}"}, "noInternationalDialling": {"possibleLengths": {"national": "10"}, "nationalNumberPattern": "18[59]0\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "[7-10]", "localOnly": "5,6"}, "exampleNumber": "2212345", "nationalNumberPattern": "(?:1\\d|21)\\d{6,7}|(?:2[24-9]|4(?:0[24]|5\\d|7)|5(?:0[45]|1\\d|8)|6(?:1\\d|[237-9])|9(?:1\\d|[35-9]))\\d{5}|(?:23|4(?:[1-469]|8\\d)|5[23679]|6[4-6]|7[14]|9[04])\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "850123456", "nationalNumberPattern": "8(?:22|[35-9]\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "1800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1520123456", "nationalNumberPattern": "15(?:1[2-8]|[2-8]0|9[089])\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "1850123456", "nationalNumberPattern": "18[59]0\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "700123456", "nationalNumberPattern": "700\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "761234567", "nationalNumberPattern": "76\\d{7}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "818123456", "nationalNumberPattern": "818\\d{6}"}, "voicemail": {"possibleLengths": {"national": "10"}, "exampleNumber": "8551234567", "nationalNumberPattern": "88210[1-9]\\d{4}|8(?:[35-79]5\\d\\d|8(?:[013-9]\\d\\d|2(?:[01][1-9]|[2-9]\\d)))\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "0(?:0|1[2-9])", "id": "IL", "countryCode": "972", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{3})", "leadingDigits": "125", "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{2})(\\d{2})", "leadingDigits": "121", "format": "$1-$2-$3"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-489]", "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[57]", "format": "$1-$2-$3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "12", "format": "$1-$2-$3"}, {"pattern": "(\\d{4})(\\d{6})", "leadingDigits": "159", "format": "$1-$2"}, {"pattern": "(\\d)(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "1[7-9]", "format": "$1-$2-$3-$4"}, {"pattern": "(\\d{3})(\\d{1,2})(\\d{3})(\\d{4})", "leadingDigits": "15", "format": "$1-$2 $3-$4"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{6}(?:\\d{3,5})?|[57]\\d{8}|[1-489]\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "10"}, "nationalNumberPattern": "1700\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8,11,12", "localOnly": "7"}, "exampleNumber": "21234567", "nationalNumberPattern": "153\\d{8,9}|29[1-9]\\d{5}|(?:2[0-8]|[3489]\\d)\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "502345678", "nationalNumberPattern": "5(?:(?:[02368]\\d|[19][2-9]|4[1-9])\\d|5(?:01|1[79]|2[2-9]|3[0-3]|4[34]|5[015689]|6[6-8]|7[0-267]|8[7-9]|9[1-9]))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "1(?:255|80[019]\\d{3})\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "8,10"}, "exampleNumber": "1919123456", "nationalNumberPattern": "1212\\d{4}|1(?:200|9(?:0[01]|19))\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "1700123456", "nationalNumberPattern": "1700\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "771234567", "nationalNumberPattern": "7(?:380|8(?:33|55|77|81))\\d{5}|7(?:18|2[23]|3[237]|47|6[58]|7\\d|82|9[235-9])\\d{6}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "1599123456", "nationalNumberPattern": "1599\\d{6}"}, "voicemail": {"possibleLengths": {"national": "11,12"}, "exampleNumber": "15112340000", "nationalNumberPattern": "151\\d{8,9}"}}, {"nationalPrefixForParsing": "0|([5-8]\\d{5})$", "countryCode": "44", "leadingDigits": "74576|(?:16|7[56])24", "nationalPrefix": "0", "nationalPrefixTransformRule": "1624$1", "internationalPrefix": "00", "id": "IM", "generalDesc": {"nationalNumberPattern": "1624\\d{6}|(?:[3578]\\d|90)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "6"}, "exampleNumber": "1624756789", "nationalNumberPattern": "1624[5-8]\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "7924123456", "nationalNumberPattern": "76245[06]\\d{4}|7(?:4576|[59]24\\d|624[0-4689])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8081624567", "nationalNumberPattern": "808162\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9016247890", "nationalNumberPattern": "8(?:440[49]06|72299\\d)\\d{3}|(?:8(?:45|70)|90[0167])624\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "7012345678", "nationalNumberPattern": "70\\d{8}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5612345678", "nationalNumberPattern": "56\\d{8}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "5512345678", "nationalNumberPattern": "3440[49]06\\d{3}|(?:3(?:08162|3\\d{4}|45624|7(?:0624|2299))|55\\d{4})\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "IN", "countryCode": "91", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{7})", "leadingDigits": "575", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{8})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": ["5(?:0|2[23]|3[03]|[67]1|88)", "5(?:0|2(?:21|3)|3(?:0|3[23])|616|717|888)", "5(?:0|2(?:21|3)|3(?:0|3[23])|616|717|8888)"], "format": "$1"}, {"pattern": "(\\d{4})(\\d{4,5})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": ["180", "1800"], "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "140", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["11|2[02]|33|4[04]|79[1-7]|80[2-46]", "11|2[02]|33|4[04]|79(?:[1-6]|7[19])|80(?:[2-4]|6[0-589])", "11|2[02]|33|4[04]|79(?:[124-6]|3(?:[02-9]|1[0-24-9])|7(?:1|9[1-6]))|80(?:[2-4]|6[0-589])"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["1(?:2[0-249]|3[0-25]|4[145]|[68]|7[1257])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|5[12]|[78]1)|6(?:12|[2-4]1|5[17]|6[13]|80)|7(?:12|3[134]|4[47]|61|88)|8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91)|(?:43|59|75)[15]|(?:1[59]|29|67|72)[14]", "1(?:2[0-24]|3[0-25]|4[145]|[59][14]|6[1-9]|7[1257]|8[1-57-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[058]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|[578]1|9[15])|674|7(?:(?:2[14]|3[34]|5[15])[2-6]|61[346]|88[0-8])|8(?:70[2-6]|84[235-7]|91[3-7])|(?:1(?:29|60|8[06])|261|552|6(?:12|[2-47]1|5[17]|6[13]|80)|7(?:12|31|4[47])|8(?:16|2[014]|3[126]|6[136]|7[78]|83))[2-7]", "1(?:2[0-24]|3[0-25]|4[145]|[59][14]|6[1-9]|7[1257]|8[1-57-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[058]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|[578]1|9[15])|6(?:12(?:[2-6]|7[0-8])|74[2-7])|7(?:(?:2[14]|5[15])[2-6]|3171|61[346]|88(?:[2-7]|82))|8(?:70[2-6]|84(?:[2356]|7[19])|91(?:[3-6]|7[19]))|73[134][2-6]|(?:74[47]|8(?:16|2[014]|3[126]|6[136]|7[78]|83))(?:[2-6]|7[19])|(?:1(?:29|60|8[06])|261|552|6(?:[2-4]1|5[17]|6[13]|7(?:1|4[0189])|80)|7(?:12|88[01]))[2-7]"], "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["1(?:[2-479]|5[0235-9])|[2-5]|6(?:1[1358]|2[2457-9]|3[2-5]|4[235-7]|5[2-689]|6[24578]|7[235689]|8[1-6])|7(?:1[013-9]|28|3[129]|4[1-35689]|5[29]|6[02-5]|70)|807", "1(?:[2-479]|5[0235-9])|[2-5]|6(?:1[1358]|2(?:[2457]|84|95)|3(?:[2-4]|55)|4[235-7]|5[2-689]|6[24578]|7[235689]|8[1-6])|7(?:1(?:[013-8]|9[6-9])|28[6-8]|3(?:17|2[0-49]|9[2-57])|4(?:1[2-4]|[29][0-7]|3[0-8]|[56]|8[0-24-7])|5(?:2[1-3]|9[0-6])|6(?:0[5689]|2[5-9]|3[02-8]|4|5[0-367])|70[13-7])|807[19]", "1(?:[2-479]|5(?:[0236-9]|5[013-9]))|[2-5]|6(?:2(?:84|95)|355|83)|73179|807(?:1|9[1-3])|(?:1552|6(?:1[1358]|2[2457]|3[2-4]|4[235-7]|5[2-689]|6[24578]|7[235689]|8[124-6])\\d|7(?:1(?:[013-8]\\d|9[6-9])|28[6-8]|3(?:2[0-49]|9[2-57])|4(?:1[2-4]|[29][0-7]|3[0-8]|[56]\\d|8[0-24-7])|5(?:2[1-3]|9[0-6])|6(?:0[5689]|2[5-9]|3[02-8]|4\\d|5[0-367])|70[13-7]))[2-7]"], "format": "$1 $2 $3"}, {"pattern": "(\\d{5})(\\d{5})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[6-9]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{2,4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": ["1(?:6|8[06])", "1(?:6|8[06]0)"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "0", "format": "$1 $2 $3 $4", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "18", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:000800|[2-9]\\d\\d)\\d{7}|1\\d{7,12}"}, "noInternationalDialling": {"possibleLengths": {"national": "[8-13]"}, "nationalNumberPattern": "1(?:600\\d{6}|800\\d{4,9})|(?:000800|18(?:03\\d\\d|6(?:0|[12]\\d\\d)))\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "[6-8]"}, "exampleNumber": "7410410123", "nationalNumberPattern": "2717(?:[2-7]\\d|95)\\d{4}|(?:271[0-689]|782[0-6])[2-7]\\d{5}|(?:170[24]|2(?:(?:[02][2-79]|90)\\d|80[13468])|(?:3(?:23|80)|683|79[1-7])\\d|4(?:20[24]|72[2-8])|552[1-7])\\d{6}|(?:11|33|4[04]|80)[2-7]\\d{7}|(?:342|674|788)(?:[0189][2-7]|[2-7]\\d)\\d{5}|(?:1(?:2[0-249]|3[0-25]|4[145]|[59][14]|6[014]|7[1257]|8[01346])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568]|9[14])|3(?:26|4[13]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[014-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|[578]1|9[15])|6(?:12|[2-47]1|5[17]|6[13]|80)|7(?:12|2[14]|3[134]|4[47]|5[15]|[67]1)|8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91))[2-7]\\d{6}|(?:1(?:2[35-8]|3[346-9]|4[236-9]|[59][0235-9]|6[235-9]|7[34689]|8[257-9])|2(?:1[134689]|3[24-8]|4[2-8]|5[25689]|6[2-4679]|7[3-79]|8[2-479]|9[235-9])|3(?:01|1[79]|2[1245]|4[5-8]|5[125689]|6[235-7]|7[157-9]|8[2-46-8])|4(?:1[14578]|2[5689]|3[2-467]|5[4-7]|6[35]|73|8[2689]|9[2389])|5(?:[16][146-9]|2[14-8]|3[1346]|4[14-69]|5[46]|7[2-4]|8[2-8]|9[246])|6(?:1[1358]|2[2457]|3[2-4]|4[235-7]|5[2-689]|6[24578]|7[235689]|8[124-6])|7(?:1[013-9]|2[0235-9]|3[2679]|4[1-35689]|5[2-46-9]|[67][02-9]|8[013-7]|9[089])|8(?:1[1357-9]|2[235-8]|3[03-57-9]|4[0-24-9]|5\\d|6[2457-9]|7[1-6]|8[1256]|9[2-4]))\\d[2-7]\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "8123456789", "nationalNumberPattern": "(?:61279|7(?:887[02-9]|9(?:313|79[07-9]))|8(?:079[04-9]|(?:84|91)7[02-8]))\\d{5}|(?:6(?:12|[2-47]1|5[17]|6[13]|80)[0189]|7(?:1(?:2[0189]|9[0-5])|2(?:[14][017-9]|8[0-59])|3(?:2[5-8]|[34][017-9]|9[016-9])|4(?:1[015-9]|[29][89]|39|8[389])|5(?:[15][017-9]|2[04-9]|9[7-9])|6(?:0[0-47]|1[0-257-9]|2[0-4]|3[19]|5[4589])|70[0289]|88[089]|97[02-8])|8(?:0(?:6[67]|7[02-8])|70[017-9]|84[01489]|91[0-289]))\\d{6}|(?:7(?:31|4[47])|8(?:16|2[014]|3[126]|6[136]|7[78]|83))(?:[0189]\\d|7[02-8])\\d{5}|(?:6(?:[09]\\d|1[04679]|2[03689]|3[05-9]|4[0489]|50|6[069]|7[07]|8[7-9])|7(?:0\\d|2[0235-79]|3[05-8]|40|5[0346-8]|6[6-9]|7[1-9]|8[0-79]|9[089])|8(?:0[01589]|1[0-57-9]|2[235-9]|3[03-57-9]|[45]\\d|6[02457-9]|7[1-69]|8[0-25-9]|9[02-9])|9\\d\\d)\\d{7}|(?:6(?:(?:1[1358]|2[2457]|3[2-4]|4[235-7]|5[2-689]|6[24578]|8[124-6])\\d|7(?:[235689]\\d|4[0189]))|7(?:1(?:[013-8]\\d|9[6-9])|28[6-8]|3(?:2[0-49]|9[2-5])|4(?:1[2-4]|[29][0-7]|3[0-8]|[56]\\d|8[0-24-7])|5(?:2[1-3]|9[0-6])|6(?:0[5689]|2[5-9]|3[02-8]|4\\d|5[0-367])|70[13-7]|881))[0189]\\d{5}"}, "tollFree": {"possibleLengths": {"national": "[8-13]"}, "exampleNumber": "1800123456", "nationalNumberPattern": "000800\\d{7}|1(?:600\\d{6}|80(?:0\\d{4,9}|3\\d{9}))"}, "premiumRate": {"possibleLengths": {"national": "13"}, "exampleNumber": "1861123456789", "nationalNumberPattern": "186[12]\\d{9}"}, "sharedCost": {"possibleLengths": {"national": "11"}, "exampleNumber": "18603451234", "nationalNumberPattern": "1860\\d{7}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "1409305260", "nationalNumberPattern": "140\\d{7}"}}, {"internationalPrefix": "00", "id": "IO", "countryCode": "246", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "3", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "3\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "3709100", "nationalNumberPattern": "37\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "3801234", "nationalNumberPattern": "38\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "IQ", "countryCode": "964", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-6]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:1|7\\d\\d)\\d{7}|[2-6]\\d{7,8}"}, "fixedLine": {"possibleLengths": {"national": "8,9", "localOnly": "6,7"}, "exampleNumber": "12345678", "nationalNumberPattern": "1\\d{7}|(?:2[13-5]|3[02367]|4[023]|5[03]|6[026])\\d{6,7}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "7912345678", "nationalNumberPattern": "7[3-9]\\d{8}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "IR", "countryCode": "98", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "96", "format": "$1"}, {"pattern": "(\\d{2})(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:1[137]|2[13-68]|3[1458]|4[145]|5[1468]|6[16]|7[1467]|8[13467])[12689]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-8]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[1-9]\\d{9}|(?:[1-8]\\d\\d|9)\\d{3,4}"}, "noInternationalDialling": {"possibleLengths": {"national": "4,5,10"}, "nationalNumberPattern": "9(?:4440\\d{5}|6(?:0[12]|2[16-8]|3(?:08|[14]5|[23]|66)|4(?:0|80)|5[01]|6[89]|86|9[19]))"}, "fixedLine": {"possibleLengths": {"national": "6,7,10", "localOnly": "4,5,8"}, "exampleNumber": "2123456789", "nationalNumberPattern": "(?:1[137]|2[13-68]|3[1458]|4[145]|5[1468]|6[16]|7[1467]|8[13467])(?:[03-57]\\d{7}|[16]\\d{3}(?:\\d{4})?|[289]\\d{3}(?:\\d(?:\\d{3})?)?)|94(?:000[09]|2(?:121|[2689]0\\d)|30[0-2]\\d|4(?:111|40\\d))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "9123456789", "nationalNumberPattern": "99(?:5[15]0|888|9(?:0[013]|21|77|88))\\d{5}|9(?:0(?:[1-35]\\d|4[4-6])|(?:[13]\\d|2[0-3])\\d|9(?:[0-2]\\d|3[01]|4[45]|81|9[19]))\\d{6}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "9932123456", "nationalNumberPattern": "993[2-9]\\d{6}"}, "uan": {"possibleLengths": {"national": "4,5"}, "exampleNumber": "9601", "nationalNumberPattern": "96(?:0[12]|2[16-8]|3(?:08|[14]5|[23]|66)|4(?:0|80)|5[01]|6[89]|86|9[19])"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "00|1(?:0(?:01|[12]0)|100)", "id": "IS", "countryCode": "354", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[4-9]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "3", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:38\\d|[4-9])\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "4101234", "nationalNumberPattern": "(?:4(?:1[0-24-69]|2[0-7]|[37][0-8]|4[0-245]|5[0-68]|6\\d|8[0-36-8])|5(?:05|[156]\\d|2[02578]|3[0-579]|4[03-7]|7[0-2578]|8[0-35-9]|9[013-689])|872)\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "6111234", "nationalNumberPattern": "(?:38[589]\\d\\d|6(?:1[1-8]|2[0-6]|3[027-9]|4[014679]|5[0159]|6[0-69]|70|8[06-8]|9\\d)|7(?:5[057]|[6-9]\\d)|8(?:2[0-59]|[3-69]\\d|8[28]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "80[08]\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9001234", "nationalNumberPattern": "90(?:0\\d|1[5-79]|2[015-79]|3[135-79]|4[125-7]|5[25-79]|7[1-37]|8[0-35-7])\\d{3}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "4921234", "nationalNumberPattern": "49[0-24-79]\\d{4}"}, "uan": {"possibleLengths": {"national": "7"}, "exampleNumber": "8091234", "nationalNumberPattern": "809\\d{4}"}, "voicemail": {"possibleLengths": {"national": "7"}, "exampleNumber": "6891234", "nationalNumberPattern": "(?:689|8(?:7[18]|80)|95[48])\\d{4}"}}, {"mainCountryForCode": "true", "internationalPrefix": "00", "id": "IT", "countryCode": "39", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4,5})", "leadingDigits": ["1(?:0|9[246])", "1(?:0|9(?:2[2-9]|[46]))"], "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{6})", "leadingDigits": "1(?:1|92)", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{4,6})", "leadingDigits": "0[26]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3,6})", "leadingDigits": ["0[13-57-9][0159]|8(?:03|4[17]|9[245])", "0[13-57-9][0159]|8(?:03|4[17]|9(?:2|[45][0-4]))"], "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{2,6})", "leadingDigits": "0(?:[13-579][2-46-8]|8[236-8])", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "894", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3,4})(\\d{4})", "leadingDigits": "0[26]|5", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "leadingDigits": "1[4679]|[38]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3,4})(\\d{4})", "leadingDigits": "0[13-57-9][0159]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{5})", "leadingDigits": "0[26]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "0", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4,5})", "leadingDigits": "3", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "0\\d{5,10}|3[0-8]\\d{7,10}|55\\d{8}|8\\d{5}(?:\\d{2,4})?|(?:1\\d|39)\\d{7,8}"}, "noInternationalDialling": {"possibleLengths": {"national": "9"}, "nationalNumberPattern": "848\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "[6-11]"}, "exampleNumber": "0212345678", "nationalNumberPattern": "0669[0-79]\\d{1,6}|0(?:1(?:[0159]\\d|[27][1-5]|31|4[1-4]|6[1356]|8[2-57])|2\\d\\d|3(?:[0159]\\d|2[1-4]|3[12]|[48][1-6]|6[2-59]|7[1-7])|4(?:[0159]\\d|[23][1-9]|4[245]|6[1-5]|7[1-4]|81)|5(?:[0159]\\d|2[1-5]|3[2-6]|4[1-79]|6[4-6]|7[1-578]|8[3-8])|6(?:[0-57-9]\\d|6[0-8])|7(?:[0159]\\d|2[12]|3[1-7]|4[2-46]|6[13569]|7[13-6]|8[1-59])|8(?:[0159]\\d|2[3-578]|3[1-356]|[6-8][1-5])|9(?:[0159]\\d|[238][1-5]|4[12]|6[1-8]|7[1-6]))\\d{2,7}"}, "mobile": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "3123456789", "nationalNumberPattern": "3[1-9]\\d{8}|3[2-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "6,9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80(?:0\\d{3}|3)\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "6,[8-10]"}, "exampleNumber": "899123456", "nationalNumberPattern": "(?:0878\\d\\d|89(?:2|4[5-9]\\d))\\d{3}|89[45][0-4]\\d\\d|(?:1(?:44|6[346])|89(?:5[5-9]|9))\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "6,9"}, "exampleNumber": "848123456", "nationalNumberPattern": "84(?:[08]\\d{3}|[17])\\d{3}"}, "personalNumber": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "1781234567", "nationalNumberPattern": "1(?:78\\d|99)\\d{6}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5512345678", "nationalNumberPattern": "55\\d{8}"}, "voicemail": {"possibleLengths": {"national": "11,12"}, "exampleNumber": "33101234501", "nationalNumberPattern": "3[2-8]\\d{9,10}"}}, {"nationalPrefixForParsing": "0|([0-24-8]\\d{5})$", "countryCode": "44", "nationalPrefix": "0", "nationalPrefixTransformRule": "1534$1", "internationalPrefix": "00", "id": "JE", "generalDesc": {"nationalNumberPattern": "1534\\d{6}|(?:[3578]\\d|90)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "6"}, "exampleNumber": "1534456789", "nationalNumberPattern": "1534[0-24-8]\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "7797712345", "nationalNumberPattern": "7(?:(?:(?:50|82)9|937)\\d|7(?:00[378]|97[7-9]))\\d{5}"}, "pager": {"possibleLengths": {"national": "10"}, "exampleNumber": "7640123456", "nationalNumberPattern": "76(?:464|652)\\d{5}|76(?:0[0-2]|2[356]|34|4[01347]|5[49]|6[0-369]|77|81|9[139])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8007354567", "nationalNumberPattern": "80(?:07(?:35|81)|8901)\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9018105678", "nationalNumberPattern": "(?:8(?:4(?:4(?:4(?:05|42|69)|703)|5(?:041|800))|7(?:0002|1206))|90(?:066[59]|1810|71(?:07|55)))\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "7015115678", "nationalNumberPattern": "701511\\d{4}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5612345678", "nationalNumberPattern": "56\\d{8}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "5512345678", "nationalNumberPattern": "(?:3(?:0(?:07(?:35|81)|8901)|3\\d{4}|4(?:4(?:4(?:05|42|69)|703)|5(?:041|800))|7(?:0002|1206))|55\\d{4})\\d{4}"}}, {"countryCode": "1", "leadingDigits": "658|876", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "internationalPrefix": "011", "id": "JM", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|658|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8765230123", "nationalNumberPattern": "8766060\\d{3}|(?:658(?:2(?:[0-8]\\d|9[0-46-9])|[3-9]\\d\\d)|876(?:5(?:02|1[0-468]|2[35]|63)|6(?:0[1-3579]|1[0237-9]|[23]\\d|40|5[06]|6[2-589]|7[05]|8[04]|9[4-9])|7(?:0[2-689]|[1-6]\\d|8[056]|9[45])|9(?:0[1-8]|1[02378]|[2-8]\\d|9[2-468])))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8762101234", "nationalNumberPattern": "(?:658295|876(?:2(?:[14-9]\\d|2[013-9]|3[7-9])|[348]\\d\\d|5(?:0[13-9]|1[579]|[2-57-9]\\d|6[0-24-9])|6(?:4[89]|6[67])|7(?:0[07]|7\\d|8[1-47-9]|9[0-36-9])|9(?:[01]9|9[0579])))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "JO", "countryCode": "962", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[2356]|87", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{5,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "70", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:(?:[2689]|7\\d)\\d|32|53)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "62001234", "nationalNumberPattern": "87(?:000|90[01])\\d{3}|(?:2(?:6(?:2[0-35-9]|3[0-578]|4[24-7]|5[0-24-8]|[6-8][023]|9[0-3])|7(?:0[1-79]|10|2[014-7]|3[0-689]|4[019]|5[0-3578]))|32(?:0[1-69]|1[1-35-7]|2[024-7]|3\\d|4[0-3]|[5-7][023])|53(?:0[0-3]|[13][023]|2[0-59]|49|5[0-35-9]|6[15]|7[45]|8[1-6]|9[0-36-9])|6(?:2(?:[05]0|22)|3(?:00|33)|4(?:0[0-25]|1[2-7]|2[0569]|[38][07-9]|4[025689]|6[0-589]|7\\d|9[0-2])|5(?:[01][056]|2[034]|3[0-57-9]|4[178]|5[0-69]|6[0-35-9]|7[1-379]|8[0-68]|9[0239]))|87(?:20|7[078]|99))\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "790123456", "nationalNumberPattern": "7(?:[78][0-25-9]|9\\d)\\d{6}"}, "pager": {"possibleLengths": {"national": "9"}, "exampleNumber": "746612345", "nationalNumberPattern": "74(?:66|77)\\d{5}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "80\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "9\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "85012345", "nationalNumberPattern": "85\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "700123456", "nationalNumberPattern": "70\\d{7}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "88101234", "nationalNumberPattern": "8(?:10|8\\d)\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "010", "id": "JP", "countryCode": "81", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{4})", "leadingDigits": ["007", "0077", "00777", "00777[01]"], "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:12|57|99)0", "format": "$1-$2-$3"}, {"pattern": "(\\d{4})(\\d)(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["1(?:26|3[79]|4[56]|5[4-68]|6[3-5])|499|5(?:76|97)|746|8(?:3[89]|47|51|63)|9(?:49|80|9[16])", "1(?:267|3(?:7[247]|9[278])|466|5(?:47|58|64)|6(?:3[245]|48|5[4-68]))|499[2468]|5(?:76|97)9|7468|8(?:3(?:8[7-9]|96)|477|51[2-9]|636)|9(?:496|802|9(?:1[23]|69))|1(?:45|58)[67]", "1(?:267|3(?:7[247]|9[278])|466|5(?:47|58|64)|6(?:3[245]|48|5[4-68]))|499[2468]|5(?:769|979[2-69])|7468|8(?:3(?:8[7-9]|96[2457-9])|477|51[2-9]|636[457-9])|9(?:496|802|9(?:1[23]|69))|1(?:45|58)[67]"], "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "60", "format": "$1-$2-$3"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["[36]|4(?:2[09]|7[01])", "[36]|4(?:2(?:0|9[02-69])|7(?:0[019]|1))"], "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["1(?:1|5[45]|77|88|9[69])|2(?:2[1-37]|3[0-269]|4[59]|5|6[24]|7[1-358]|8[1369]|9[0-38])|4(?:[28][1-9]|3[0-57]|[45]|6[248]|7[2-579]|9[29])|5(?:2|3[045]|4[0-369]|5[29]|8[02389]|9[0-389])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9[2-6])|8(?:2[124589]|3[27-9]|49|51|6|7[0-468]|8[68]|9[019])|9(?:[23][1-9]|4[15]|5[138]|6[1-3]|7[156]|8[189]|9[1-489])", "1(?:1|5(?:4[018]|5[017])|77|88|9[69])|2(?:2(?:[127]|3[014-9])|3[0-269]|4[59]|5(?:[1-3]|5[0-69]|9[19])|62|7(?:[1-35]|8[0189])|8(?:[16]|3[0134]|9[0-5])|9(?:[028]|17))|4(?:2(?:[13-79]|8[014-6])|3[0-57]|[45]|6[248]|7[2-47]|8[1-9])|5(?:2|3[045]|4[0-369]|8[02389]|9[0-3])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9(?:[23]|4[0-59]|5[01569]|6[0167]))|8(?:2(?:[1258]|4[0-39]|9[0-2469])|49|51|6(?:[0-24]|36|5[0-3589]|72|9[01459])|7[0-468]|8[68])|9(?:[23][1-9]|4[15]|5[138]|6[1-3]|7[156]|8[189]|9(?:[1289]|3[34]|4[0178]))|(?:49|55|83)[29]|(?:264|837)[016-9]|2(?:57|93)[015-9]|(?:25[0468]|422|838)[01]|(?:47[59]|59[89]|8(?:6[68]|9))[019]", "1(?:1|5(?:4[018]|5[017])|77|88|9[69])|2(?:2[127]|3[0-269]|4[59]|5(?:[1-3]|5[0-69]|9(?:17|99))|6(?:2|4[016-9])|7(?:[1-35]|8[0189])|8(?:[16]|3[0134]|9[0-5])|9(?:[028]|17))|4(?:2(?:[13-79]|8[014-6])|3[0-57]|[45]|6[248]|7[2-47]|9[29])|5(?:2|3[045]|4[0-369]|5[29]|8[02389]|9[0-3])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9(?:[23]|4[0-59]|5[01569]|6[0167]))|8(?:2(?:[1258]|4[0-39]|9[0169])|3(?:[29]|7(?:[017-9]|6[6-8]))|49|51|6(?:[0-24]|36[23]|5(?:[0-389]|5[23])|6(?:[01]|9[178])|72|9[0145])|7[0-468]|8[68])|9(?:4[15]|5[138]|7[156]|8[189]|9(?:[1289]|3(?:31|4[357])|4[0178]))|(?:8294|96)[1-3]|2(?:57|93)[015-9]|(?:223|8699)[014-9]|(?:25[0468]|422|838)[01]|(?:48|8292|9[23])[1-9]|(?:47[59]|59[89]|8(?:68|9))[019]", "1(?:1|5(?:4[018]|5[017])|77|88|9[69])|2(?:2[127]|3[0-269]|4[59]|5(?:[1-3]|5[0-69]|7[015-9]|9(?:17|99))|6(?:2|4[016-9])|7(?:[1-35]|8[0189])|8(?:[16]|3[0134]|9[0-5])|9(?:[028]|17|3[015-9]))|4(?:2(?:[13-79]|8[014-6])|3[0-57]|[45]|6[248]|7[2-47]|9[29])|5(?:2|3[045]|4[0-369]|5[29]|8[02389]|9[0-3])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9(?:[23]|4[0-59]|5[01569]|6[0167]))|8(?:2(?:[1258]|4[0-39]|9(?:[019]|4[1-3]|6(?:[0-47-9]|5[01346-9])))|3(?:[29]|7(?:[017-9]|6[6-8]))|49|51|6(?:[0-24]|36[23]|5(?:[0-389]|5[23])|6(?:[01]|9[178])|72|9[0145])|7[0-468]|8[68])|9(?:4[15]|5[138]|6[1-3]|7[156]|8[189]|9(?:[1289]|3(?:31|4[357])|4[0178]))|(?:223|8699)[014-9]|(?:25[0468]|422|838)[01]|(?:48|829(?:2|66)|9[23])[1-9]|(?:47[59]|59[89]|8(?:68|9))[019]"], "format": "$1-$2-$3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[14]|[289][2-9]|5[3-9]|7[2-4679]", "format": "$1-$2-$3"}, {"pattern": "(\\d{4})(\\d{2})(\\d{3,4})", "leadingDigits": "007", "format": "$1-$2-$3", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{2})(\\d{4})", "leadingDigits": "008", "format": "$1-$2-$3", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "800", "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[257-9]", "format": "$1-$2-$3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3,4})", "leadingDigits": "0", "format": "$1-$2-$3", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{4})(\\d{4,5})", "leadingDigits": "0", "format": "$1-$2-$3", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{5})(\\d{5,6})", "leadingDigits": "0", "format": "$1-$2-$3", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{6})(\\d{6,7})", "leadingDigits": "0", "format": "$1-$2-$3", "intlFormat": "NA"}]}, "generalDesc": {"nationalNumberPattern": "00[1-9]\\d{6,14}|[257-9]\\d{9}|(?:00|[1-9]\\d\\d)\\d{6}"}, "noInternationalDialling": {"possibleLengths": {"national": "[8-17]"}, "nationalNumberPattern": "00(?:777(?:[01]|(?:5|8\\d)\\d)|882[1245]\\d\\d)\\d\\d|00(?:37|66)\\d{6,13}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "312345678", "nationalNumberPattern": "(?:1(?:1[235-8]|2[3-6]|3[3-9]|4[2-6]|[58][2-8]|6[2-7]|7[2-9]|9[1-9])|(?:2[2-9]|[36][1-9])\\d|4(?:[2-578]\\d|6[02-8]|9[2-59])|5(?:[2-589]\\d|6[1-9]|7[2-8])|7(?:[25-9]\\d|3[4-9]|4[02-9])|8(?:[2679]\\d|3[2-9]|4[5-9]|5[1-9]|8[03-9])|9(?:[2-58]\\d|[679][1-9]))\\d{6}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "9012345678", "nationalNumberPattern": "[7-9]0[1-9]\\d{7}"}, "pager": {"possibleLengths": {"national": "10"}, "exampleNumber": "2012345678", "nationalNumberPattern": "20[1-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "[8-17]"}, "exampleNumber": "120123456", "nationalNumberPattern": "00(?:(?:37|66)\\d{6,13}|(?:777(?:[01]|(?:5|8\\d)\\d)|882[1245]\\d\\d)\\d\\d)|(?:120|800\\d)\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "990123456", "nationalNumberPattern": "990\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "601234567", "nationalNumberPattern": "60\\d{7}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5012345678", "nationalNumberPattern": "50[1-9]\\d{7}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "570123456", "nationalNumberPattern": "570\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "000", "id": "KE", "countryCode": "254", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{5,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[24-6]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[17]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[17]\\d\\d|900)\\d{6}|(?:2|80)0\\d{6,7}|[4-6]\\d{6,8}"}, "fixedLine": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "202012345", "nationalNumberPattern": "(?:4[245]|5[1-79]|6[01457-9])\\d{5,7}|(?:4[136]|5[08]|62)\\d{7}|(?:[24]0|66)\\d{6,7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "712123456", "nationalNumberPattern": "(?:1(?:0[0-6]|1[0-5]|2[014])|7\\d\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "800223456", "nationalNumberPattern": "800[24-8]\\d{5,6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900223456", "nationalNumberPattern": "900[02-9]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "KG", "countryCode": "996", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3(?:1[346]|[24-79])", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[235-79]|88", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d)(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "8\\d{9}|(?:[235-8]\\d|99)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "5,6"}, "exampleNumber": "312123456", "nationalNumberPattern": "312(?:5[0-79]\\d|9(?:[0-689]\\d|7[0-24-9]))\\d{3}|(?:3(?:1(?:2[0-46-8]|3[1-9]|47|[56]\\d)|2(?:22|3[0-479]|6[0-7])|4(?:22|5[6-9]|6\\d)|5(?:22|3[4-7]|59|6\\d)|6(?:22|5[35-7]|6\\d)|7(?:22|3[468]|4[1-9]|59|[67]\\d)|9(?:22|4[1-8]|6\\d))|6(?:09|12|2[2-4])\\d)\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "700123456", "nationalNumberPattern": "312(?:58\\d|973)\\d{3}|(?:2(?:0[0-35]|2\\d)|5[0-24-7]\\d|7(?:[07]\\d|55)|880|99[05-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6,7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00[14-9]", "id": "KH", "countryCode": "855", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{9}|[1-9]\\d{7,8}"}, "fixedLine": {"possibleLengths": {"national": "8,9", "localOnly": "6,7"}, "exampleNumber": "23756789", "nationalNumberPattern": "23(?:4(?:[2-4]|[56]\\d)|[568]\\d\\d)\\d{4}|23[236-9]\\d{5}|(?:2[4-6]|3[2-6]|4[2-4]|[5-7][2-5])(?:(?:[237-9]|4[56]|5\\d)\\d{5}|6\\d{5,6})"}, "mobile": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "91234567", "nationalNumberPattern": "(?:(?:1[28]|3[18]|9[67])\\d|6[016-9]|7(?:[07-9]|[16]\\d)|8(?:[013-79]|8\\d))\\d{6}|(?:1\\d|9[0-57-9])\\d{6}|(?:2[3-6]|3[2-6]|4[2-4]|[5-7][2-5])48\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "1800(?:1\\d|2[019])\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1900123456", "nationalNumberPattern": "1900(?:1\\d|2[09])\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "KI", "countryCode": "686", "generalDesc": {"nationalNumberPattern": "(?:[37]\\d|6[0-79])\\d{6}|(?:[2-48]\\d|50)\\d{3}"}, "fixedLine": {"possibleLengths": {"national": "5,8"}, "exampleNumber": "31234", "nationalNumberPattern": "(?:[24]\\d|3[1-9]|50|65(?:02[12]|12[56]|22[89]|[3-5]00)|7(?:27\\d\\d|3100|5(?:02[12]|12[56]|22[89]|[34](?:00|81)|500))|8[0-5])\\d{3}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "72001234", "nationalNumberPattern": "(?:63\\d{3}|73(?:0[0-5]\\d|140))\\d{3}|[67]200[01]\\d{3}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "30010000", "nationalNumberPattern": "30(?:0[01]\\d\\d|12(?:11|20))\\d\\d"}}, {"internationalPrefix": "00", "id": "KM", "countryCode": "269", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{2})(\\d{2})", "leadingDigits": "[3478]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[3478]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7", "localOnly": "4"}, "exampleNumber": "7712345", "nationalNumberPattern": "7[4-7]\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "3212345", "nationalNumberPattern": "[34]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "8\\d{6}"}}, {"nationalPrefixForParsing": "1|([2-7]\\d{6})$", "countryCode": "1", "leadingDigits": "869", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "869$1", "internationalPrefix": "011", "id": "KN", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8692361234", "nationalNumberPattern": "869(?:2(?:29|36)|302|4(?:6[015-9]|70)|56[5-7])\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8697652917", "nationalNumberPattern": "869(?:48[89]|55[6-8]|66\\d|76[02-7])\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00|99", "id": "KP", "countryCode": "850", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-7]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "85\\d{6}|(?:19\\d|[2-7])\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "238[02-9]\\d{4}|2(?:[0-24-9]\\d|3[0-79])\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8,10", "localOnly": "6,7"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:(?:195|2)\\d|3[19]|4[159]|5[37]|6[17]|7[39]|85)\\d{6}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "1921234567", "nationalNumberPattern": "19[1-3]\\d{7}"}}, {"nationalPrefixForParsing": "0(8(?:[1-46-8]|5\\d\\d))?", "countryCode": "82", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "internationalPrefix": "00(?:[125689]|3(?:[46]5|91)|7(?:00|27|3|55|6[126]))", "id": "KR", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["1[016-9]1", "1[016-9]11", "1[016-9]114"], "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{3,4})", "carrierCodeFormattingRule": "$NP$CC-$FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:3[1-3]|[46][1-4]|5[1-5])1", "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "1", "format": "$1-$2"}, {"pattern": "(\\d)(\\d{3,4})(\\d{4})", "carrierCodeFormattingRule": "$NP$CC-$FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "carrierCodeFormattingRule": "$NP$CC-$FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "60|8", "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{3,4})(\\d{4})", "carrierCodeFormattingRule": "$NP$CC-$FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1346]|5[1-5]", "format": "$1-$2-$3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "carrierCodeFormattingRule": "$NP$CC-$FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[57]", "format": "$1-$2-$3"}, {"pattern": "(\\d{5})(\\d{3})(\\d{3})", "leadingDigits": ["003", "0030"], "format": "$1 $2 $3", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{5})(\\d{4})", "carrierCodeFormattingRule": "$NP$CC-$FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1-$2-$3"}, {"pattern": "(\\d{5})(\\d{3,4})(\\d{4})", "leadingDigits": "0", "format": "$1 $2 $3", "intlFormat": "NA"}, {"pattern": "(\\d{5})(\\d{2})(\\d{3})(\\d{4})", "leadingDigits": "0", "format": "$1 $2 $3 $4", "intlFormat": "NA"}]}, "generalDesc": {"nationalNumberPattern": "00[1-9]\\d{8,11}|(?:[12]|5\\d{3})\\d{7}|[13-6]\\d{9}|(?:[1-6]\\d|80)\\d{7}|[3-6]\\d{4,5}|(?:00|7)0\\d{8}"}, "noInternationalDialling": {"possibleLengths": {"national": "[11-14]"}, "nationalNumberPattern": "00(?:3(?:08\\d{6,7}|68\\d{7})|798\\d{7,9})"}, "fixedLine": {"possibleLengths": {"national": "5,6,[8-10]", "localOnly": "3,4,7"}, "exampleNumber": "22123456", "nationalNumberPattern": "(?:2|3[1-3]|[46][1-4]|5[1-5])[1-9]\\d{6,7}|(?:3[1-3]|[46][1-4]|5[1-5])1\\d{2,3}"}, "mobile": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "1020000000", "nationalNumberPattern": "1(?:05(?:[0-8]\\d|9[0-6])|22[13]\\d)\\d{4,5}|1(?:0[1-46-9]|[16-9]\\d|2[013-9])\\d{6,7}"}, "pager": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "1523456789", "nationalNumberPattern": "15\\d{7,8}"}, "tollFree": {"possibleLengths": {"national": "9,[11-14]"}, "exampleNumber": "801234567", "nationalNumberPattern": "00(?:308\\d{6,7}|798\\d{7,9})|(?:00368|80)\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "602345678", "nationalNumberPattern": "60[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "5012345678", "nationalNumberPattern": "50\\d{8,9}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "7012345678", "nationalNumberPattern": "70\\d{8}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "15441234", "nationalNumberPattern": "1(?:5(?:22|44|66|77|88|99)|6(?:[07]0|44|6[16]|88)|8(?:00|33|55|77|99))\\d{4}"}}, {"internationalPrefix": "00", "id": "KW", "countryCode": "965", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{3,4})", "leadingDigits": "[169]|2(?:[235]|4[1-35-9])|52", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5})", "leadingDigits": "[25]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:18|[2569]\\d\\d)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22345678", "nationalNumberPattern": "2(?:[23]\\d\\d|4(?:[1-35-9]\\d|44)|5(?:0[034]|[2-46]\\d|5[1-3]|7[1-7]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "50012345", "nationalNumberPattern": "(?:5(?:2(?:22|5[25])|88[58])|6(?:222|333|444|70[013-9]|888|93[039])|9(?:11[01]|3(?:00|33)|500))\\d{4}|(?:5(?:[05]\\d|1[0-7]|6[56])|6(?:0[034679]|5[015-9]|6\\d|7[67]|9[069])|9(?:0[09]|22|[4679]\\d|55|8[057-9]))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "1801234", "nationalNumberPattern": "18\\d{5}"}}, {"nationalPrefixForParsing": "1|([2-9]\\d{6})$", "countryCode": "1", "leadingDigits": "345", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "345$1", "internationalPrefix": "011", "id": "KY", "generalDesc": {"nationalNumberPattern": "(?:345|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "3452221234", "nationalNumberPattern": "345(?:2(?:22|3[23]|44|66)|333|444|6(?:23|38|40)|7(?:30|4[35-79]|6[6-9]|77)|8(?:00|1[45]|25|[48]8)|9(?:14|4[035-9]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "3453231234", "nationalNumberPattern": "345(?:32[1-9]|42[0-4]|5(?:1[67]|2[5-79]|4[6-9]|50|76)|649|9(?:1[679]|2[2-9]|3[06-9]|90))\\d{4}"}, "pager": {"possibleLengths": {"national": "10"}, "exampleNumber": "3458491234", "nationalNumberPattern": "345849\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "(?:345976|900[2-9]\\d\\d)\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"countryCode": "7", "leadingDigits": "33|7", "nationalPrefix": "8", "preferredInternationalPrefix": "8~10", "internationalPrefix": "810", "id": "KZ", "generalDesc": {"nationalNumberPattern": "33622\\d{5}|(?:7\\d|80)\\d{8}"}, "noInternationalDialling": {"possibleLengths": {"national": "10"}, "nationalNumberPattern": "751\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "[5-7]"}, "exampleNumber": "7123456789", "nationalNumberPattern": "(?:33622|7(?:1(?:0(?:[23]\\d|4[0-3]|59|63)|1(?:[23]\\d|4[0-79]|59)|2(?:[23]\\d|59)|3(?:2\\d|3[0-79]|4[0-35-9]|59)|4(?:[24]\\d|3[013-9]|5[1-9])|5(?:2\\d|3[1-9]|4[0-7]|59)|6(?:[2-4]\\d|5[19]|61)|72\\d|8(?:[27]\\d|3[1-46-9]|4[0-5]))|2(?:1(?:[23]\\d|4[46-9]|5[3469])|2(?:2\\d|3[0679]|46|5[12679])|3(?:[2-4]\\d|5[139])|4(?:2\\d|3[1-35-9]|59)|5(?:[23]\\d|4[0-246-8]|59|61)|6(?:2\\d|3[1-9]|4[0-4]|59)|7(?:[2379]\\d|40|5[279])|8(?:[23]\\d|4[0-3]|59)|9(?:2\\d|3[124578]|59))))\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "7710009998", "nationalNumberPattern": "7(?:0[0-25-8]|47|6[02-4]|7[15-8]|85)\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "8091234567", "nationalNumberPattern": "809\\d{7}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "8081234567", "nationalNumberPattern": "808\\d{7}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "7511234567", "nationalNumberPattern": "751\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "LA", "countryCode": "856", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2[13]|3[14]|[4-8]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "30[013-9]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[23]\\d{9}|3\\d{8}|(?:[235-8]\\d|41)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6"}, "exampleNumber": "21212862", "nationalNumberPattern": "(?:2[13]|[35-7][14]|41|8[1468])\\d{6}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "2023123456", "nationalNumberPattern": "(?:20(?:[239]\\d|5[24-9]|7[6-8])|302\\d)\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "301234567", "nationalNumberPattern": "30[013-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "LB", "countryCode": "961", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[13-69]|7(?:[2-57]|62|8[0-7]|9[04-9])|8[02-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "leadingDigits": "[7-9]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[7-9]\\d{7}|[13-9]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "1123456", "nationalNumberPattern": "(?:(?:[14-69]\\d|8[02-9])\\d|7(?:[2-57]\\d|62|8[0-7]|9[04-9]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "71123456", "nationalNumberPattern": "793(?:[01]\\d|2[0-4])\\d{3}|(?:(?:3|81)\\d|7(?:[01]\\d|6[013-9]|8[89]|9[12]))\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "9[01]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "80\\d{6}"}}, {"nationalPrefixForParsing": "1|([2-8]\\d{6})$", "countryCode": "1", "leadingDigits": "758", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "758$1", "internationalPrefix": "011", "id": "LC", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|758|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7584305678", "nationalNumberPattern": "758(?:234|4(?:30|5\\d|6[2-9]|8[0-2])|57[0-2]|(?:63|75)8)\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7582845678", "nationalNumberPattern": "758(?:28[4-7]|384|4(?:6[01]|8[4-9])|5(?:1[89]|20|84)|7(?:1[2-9]|2\\d|3[0-3])|812)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "nationalPrefixForParsing": "0|(1001)", "internationalPrefix": "00", "id": "LI", "countryCode": "423", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{2})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "[237-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "69", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "6", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "90\\d{5}|(?:[2378]|6\\d\\d)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2345678", "nationalNumberPattern": "(?:2(?:01|1[27]|2[02]|3\\d|6[02-578]|96)|3(?:[24]0|33|7[0135-7]|8[048]|9[0269]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "660234567", "nationalNumberPattern": "(?:6(?:4(?:79|[89]\\d)|5[0-4]\\d|6(?:0\\d|10|2[0-26-9]|3[7-9]))\\d|7(?:[37-9]\\d|42|56))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8002222", "nationalNumberPattern": "80(?:02[28]|9\\d\\d)\\d\\d"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9002222", "nationalNumberPattern": "90(?:02[258]|1(?:23|3[14])|66[136])\\d\\d"}, "uan": {"possibleLengths": {"national": "7"}, "exampleNumber": "8702812", "nationalNumberPattern": "870(?:28|87)\\d\\d"}, "voicemail": {"possibleLengths": {"national": "9"}, "exampleNumber": "697861234", "nationalNumberPattern": "697(?:42|56|[78]\\d)\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "LK", "countryCode": "94", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-689]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[1-9]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "112345678", "nationalNumberPattern": "(?:12[2-9]|602|8[12]\\d|9(?:1\\d|22|9[245]))\\d{6}|(?:11|2[13-7]|3[1-8]|4[157]|5[12457]|6[35-7])[2-57]\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "712345678", "nationalNumberPattern": "7(?:[0-25-8]\\d|4[01])\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "197312345", "nationalNumberPattern": "1973\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "LR", "countryCode": "231", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[4-6]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3578]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:2|33|5\\d|77|88)\\d{7}|[4-6]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:2\\d{3}|33333)\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "770123456", "nationalNumberPattern": "(?:(?:330|555|(?:77|88)\\d)\\d|4[67])\\d{5}|[56]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "332021234", "nationalNumberPattern": "332(?:02|[34]\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "LS", "countryCode": "266", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[2568]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[256]\\d\\d|800)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22123456", "nationalNumberPattern": "2\\d{7}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "50123456", "nationalNumberPattern": "[56]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80021234", "nationalNumberPattern": "800[256]\\d{4}"}}, {"nationalPrefixForParsing": "[08]", "countryCode": "370", "mobileNumberPortableRegion": "true", "nationalPrefix": "8", "internationalPrefix": "00", "id": "LT", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "($NP-$FG)", "leadingDigits": "52[0-7]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "[7-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "($NP-$FG)", "leadingDigits": "37|4(?:[15]|6[1-8])", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "($NP-$FG)", "leadingDigits": "[3-6]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:[3469]\\d|52|[78]0)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "31234567", "nationalNumberPattern": "(?:3[1478]|4[124-6]|52)\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "61234567", "nationalNumberPattern": "6\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "80[02]\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "9(?:0[0239]|10)\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80812345", "nationalNumberPattern": "808\\d{5}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "70012345", "nationalNumberPattern": "70[05]\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "[89]01\\d{5}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "70712345", "nationalNumberPattern": "70[67]\\d{5}"}}, {"nationalPrefixForParsing": "(15(?:0[06]|1[12]|[35]5|4[04]|6[26]|77|88|99)\\d)", "internationalPrefix": "00", "id": "LU", "countryCode": "352", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "2(?:0[2-689]|[2-9])|[3-57]|8(?:0[2-9]|[13-9])|9(?:0[89]|[2-579])", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "2(?:0[2-689]|[2-9])|[3-57]|8(?:0[2-9]|[13-9])|9(?:0[89]|[2-579])", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{3})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "20[2-689]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "2(?:[0367]|4[3-8])", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "80[01]|90[015]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{3})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "20", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "6", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "2(?:[0367]|4[3-8])", "format": "$1 $2 $3 $4 $5"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{1,5})", "carrierCodeFormattingRule": "$CC $FG", "leadingDigits": "[3-57]|8[13-9]|9(?:0[89]|[2-579])|(?:2|80)[2-9]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "35[013-9]\\d{4,8}|6\\d{8}|35\\d{2,4}|(?:[2457-9]\\d|3[0-46-9])\\d{2,9}"}, "fixedLine": {"possibleLengths": {"national": "[4-11]"}, "exampleNumber": "27123456", "nationalNumberPattern": "(?:35[013-9]|80[2-9]|90[89])\\d{1,8}|(?:2[2-9]|3[0-46-9]|[457]\\d|8[13-9]|9[2-579])\\d{2,9}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "628123456", "nationalNumberPattern": "6(?:[269][18]|5[158]|7[189]|81)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "90[015]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80112345", "nationalNumberPattern": "801\\d{5}"}, "voip": {"possibleLengths": {"national": "[4-10]"}, "exampleNumber": "20201234", "nationalNumberPattern": "20(?:1\\d{5}|[2-689]\\d{1,7})"}}, {"internationalPrefix": "00", "id": "LV", "countryCode": "371", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "leadingDigits": "[269]|8[01]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "(?:[268]\\d|90)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "63123456", "nationalNumberPattern": "6\\d{7}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "2\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "80\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "90\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "81123456", "nationalNumberPattern": "81\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "LY", "countryCode": "218", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-9]", "format": "$1-$2"}}, "generalDesc": {"nationalNumberPattern": "[2-9]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "212345678", "nationalNumberPattern": "(?:2(?:0[56]|[1-6]\\d|7[124579]|8[124])|3(?:1\\d|2[2356])|4(?:[17]\\d|2[1-357]|5[2-4]|8[124])|5(?:[1347]\\d|2[1-469]|5[13-5]|8[1-4])|6(?:[1-479]\\d|5[2-57]|8[1-5])|7(?:[13]\\d|2[13-79])|8(?:[124]\\d|5[124]|84))\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "9[1-6]\\d{7}"}}, {"mainCountryForCode": "true", "countryCode": "212", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "internationalPrefix": "00", "id": "MA", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["5(?:29|38)", "5(?:29|38)[89]", "5(?:29|38)[89]0"], "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5[45]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{4})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["5(?:2[2-489]|3[5-9]|9)|892", "5(?:2(?:[2-49]|8[235-9])|3[5-9]|9)|892"], "format": "$1-$2"}, {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[5-7]", "format": "$1-$2"}]}, "generalDesc": {"nationalNumberPattern": "[5-8]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "520123456", "nationalNumberPattern": "5(?:29(?:[189][05]|2[29]|3[01])|38[89][05])\\d{4}|5(?:2(?:[015-7]\\d|2[02-9]|3[0-578]|4[02-46-8]|8[0235-7]|90)|3(?:[0-47]\\d|5[02-9]|6[02-8]|80|9[3-9])|(?:4[067]|5[03])\\d)\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "650123456", "nationalNumberPattern": "(?:6(?:[0-79]\\d|8[0-247-9])|7(?:0[0-8]|6[1267]|7[0-37]))\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "80\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "891234567", "nationalNumberPattern": "89\\d{7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "592401234", "nationalNumberPattern": "592(?:4[0-2]|93)\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MC", "countryCode": "377", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{2})", "leadingDigits": "8", "format": "$1 $2 $3", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "4", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[39]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d)(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6", "format": "$1 $2 $3 $4 $5"}]}, "generalDesc": {"nationalNumberPattern": "870\\d{5}|(?:[349]|6\\d)\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "870\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "99123456", "nationalNumberPattern": "(?:870|9[2-47-9]\\d)\\d{5}"}, "mobile": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "612345678", "nationalNumberPattern": "4(?:[46]\\d|5[1-9])\\d{5}|(?:3|6\\d)\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "90123456", "nationalNumberPattern": "90\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MD", "countryCode": "373", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "22|3", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[25-7]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[235-7]\\d|[89]0)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22212345", "nationalNumberPattern": "(?:(?:2[1-9]|3[1-79])\\d|5(?:33|5[257]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "62112345", "nationalNumberPattern": "562\\d{5}|(?:6\\d|7[16-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "90[056]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80812345", "nationalNumberPattern": "808\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "30123456", "nationalNumberPattern": "3[08]\\d{6}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "80312345", "nationalNumberPattern": "803\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "ME", "countryCode": "382", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-9]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "(?:20|[3-79]\\d)\\d{6}|80\\d{6,7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6"}, "exampleNumber": "30234567", "nationalNumberPattern": "(?:20[2-8]|3(?:[0-2][2-7]|3[24-7])|4(?:0[2-467]|1[2467])|5(?:0[2467]|1[24-7]|2[2-467]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "67622901", "nationalNumberPattern": "6(?:[07-9]\\d|3[024]|6[0-25])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "80080002", "nationalNumberPattern": "80(?:[0-2578]|9\\d)\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "94515151", "nationalNumberPattern": "9(?:4[1568]|5[178])\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "78108780", "nationalNumberPattern": "78[1-49]\\d{5}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "77273012", "nationalNumberPattern": "77[1-9]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MF", "countryCode": "590", "mobileNumberPortableRegion": "true", "generalDesc": {"nationalNumberPattern": "(?:590|69\\d|976)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "590271234", "nationalNumberPattern": "590(?:0[079]|[14]3|[27][79]|30|5[0-268]|87)\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "690001234", "nationalNumberPattern": "69(?:0\\d\\d|1(?:2[29]|3[0-5]))\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "976012345", "nationalNumberPattern": "976[01]\\d{5}"}}, {"nationalPrefixForParsing": "0|([24-9]\\d{6})$", "countryCode": "261", "nationalPrefix": "0", "nationalPrefixTransformRule": "20$1", "internationalPrefix": "00", "id": "MG", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "[23]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "202123456", "nationalNumberPattern": "2072[29]\\d{4}|20(?:2\\d|4[47]|5[3467]|6[279]|7[35]|8[268]|9[245])\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "321234567", "nationalNumberPattern": "3[2-49]\\d{7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "221234567", "nationalNumberPattern": "22\\d{7}"}}, {"nationalPrefix": "1", "internationalPrefix": "011", "id": "MH", "countryCode": "692", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-6]", "format": "$1-$2"}}, "generalDesc": {"nationalNumberPattern": "329\\d{4}|(?:[256]\\d|45)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2471234", "nationalNumberPattern": "(?:247|528|625)\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "2351234", "nationalNumberPattern": "(?:(?:23|54)5|329|45[56])\\d{4}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "6351234", "nationalNumberPattern": "635\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MK", "countryCode": "389", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[347]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d)(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[58]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[2-578]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6,7"}, "exampleNumber": "22012345", "nationalNumberPattern": "(?:2(?:[23]\\d|5[0-24578]|6[01]|82)|3(?:1[3-68]|[23][2-68]|4[23568])|4(?:[23][2-68]|4[3-68]|5[2568]|6[25-8]|7[24-68]|8[4-68]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "72345678", "nationalNumberPattern": "7(?:3555|4(?:60\\d|747)|94(?:[01]\\d|2[0-4]))\\d{3}|7(?:[0-25-8]\\d|3[2-4]|42|9[23])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "50012345", "nationalNumberPattern": "5[02-9]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80123456", "nationalNumberPattern": "8(?:0[1-9]|[1-9]\\d)\\d{5}"}}, {"internationalPrefix": "00", "id": "ML", "countryCode": "223", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})", "leadingDigits": ["67[057-9]|74[045]", "67(?:0[09]|[59]9|77|8[89])|74(?:0[02]|44|55)"], "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[24-9]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[24-9]\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "80\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "20212345", "nationalNumberPattern": "2(?:07[0-8]|12[67])\\d{4}|(?:2(?:02|1[4-689])|4(?:0[0-4]|4[1-39]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "65012345", "nationalNumberPattern": "2(?:0(?:01|79)|17\\d)\\d{4}|(?:5[01]|[679]\\d|8[239])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "80\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MM", "countryCode": "95", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "16|2", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[45]|6(?:0[23]|[1-689]|7[235-7])|7(?:[0-4]|5[2-7])|8[1-6]", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[4-7]|8[1-35]", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{4,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9(?:2[0-4]|[35-9]|4[137-9])", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "92", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d)(\\d{5})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{5,7}|95\\d{6}|(?:[4-7]|9[0-46-9])\\d{6,8}|(?:2|8\\d)\\d{5,8}"}, "fixedLine": {"possibleLengths": {"national": "[6-9]", "localOnly": "5"}, "exampleNumber": "1234567", "nationalNumberPattern": "(?:1(?:(?:2\\d|3[56]|[89][0-6])\\d|4(?:2[2-469]|39|46|6[25]|7[0-3]|83)|6)|2(?:2(?:00|8[34])|4(?:0\\d|2[246]|39|46|62|7[0-3]|83)|51\\d\\d)|4(?:2(?:2\\d\\d|48[0-3])|3(?:20\\d|4(?:70|83)|56)|420\\d|5470)|6(?:0(?:[23]|88\\d)|(?:124|[56]2\\d)\\d|247[23]|3(?:20\\d|470)|4(?:2[04]\\d|47[23])|7(?:(?:3\\d|8[01459])\\d|4(?:39|60|7[013]))))\\d{4}|5(?:2(?:2\\d{5,6}|47[023]\\d{4})|(?:347[23]|4(?:2(?:1|86)|470)|522\\d|6(?:20\\d|483)|7(?:20\\d|48[0-2])|8(?:20\\d|47[02])|9(?:20\\d|47[01]))\\d{4})|7(?:(?:0470|4(?:25\\d|470)|5(?:202|470|96\\d))\\d{4}|1(?:20\\d{4,5}|4(?:70|83)\\d{4}))|8(?:1(?:2\\d{5,6}|4(?:10|7[01]\\d)\\d{3})|2(?:2\\d{5,6}|(?:320|490\\d)\\d{3})|(?:3(?:2\\d\\d|470)|4[24-7]|5(?:2\\d|4[1-9]|51)\\d|6[23])\\d{4})|(?:1[2-6]\\d|4(?:2[24-8]|3[2-7]|[46][2-6]|5[3-5])|5(?:[27][2-8]|3[2-68]|4[24-8]|5[23]|6[2-4]|8[24-7]|9[2-7])|6(?:[19]20|42[03-6]|(?:52|7[45])\\d)|7(?:[04][24-8]|[15][2-7]|22|3[2-4])|8(?:1[2-689]|2[2-8]|[35]2\\d))\\d{4}|25\\d{5,6}|(?:2[2-9]|6(?:1[2356]|[24][2-6]|3[24-6]|5[2-4]|6[2-8]|7[235-7]|8[245]|9[24])|8(?:3[24]|5[245]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "[7-10]"}, "exampleNumber": "92123456", "nationalNumberPattern": "(?:17[01]|9(?:2(?:[0-4]|[56]\\d\\d)|(?:3(?:[0-36]|4\\d)|(?:6\\d|8[89]|9[4-8])\\d|7(?:3|40|[5-9]\\d))\\d|4(?:(?:[0245]\\d|[1379])\\d|88)|5[0-6])\\d)\\d{4}|9[69]1\\d{6}|9(?:[68]\\d|9[089])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8008001234", "nationalNumberPattern": "80080(?:[01][1-9]|2\\d)\\d{3}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "13331234", "nationalNumberPattern": "1333\\d{4}|[12]468\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "001", "id": "MN", "countryCode": "976", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]1", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[57-9]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]2[1-3]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{5,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["[12](?:27|3[2-8]|4[2-68]|5[1-4689])", "[12](?:27|3[2-8]|4[2-68]|5[1-4689])[0-3]"], "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[12]\\d{7,9}|[57-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "[8-10]", "localOnly": "[4-6]"}, "exampleNumber": "53123456", "nationalNumberPattern": "[12]2[1-3]\\d{5,6}|7(?:0[0-5]\\d|128)\\d{4}|(?:[12](?:1|27)|5[368])\\d{6}|[12](?:3[2-8]|4[2-68]|5[1-4689])\\d{6,7}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "88123456", "nationalNumberPattern": "(?:83[01]|920)\\d{5}|(?:5[05]|8[05689]|9[013-9])\\d{6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "75123456", "nationalNumberPattern": "712[0-79]\\d{4}|7(?:1[013-9]|[5-8]\\d)\\d{5}"}}, {"internationalPrefix": "00", "id": "MO", "countryCode": "853", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[268]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:28|[68]\\d)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "28212345", "nationalNumberPattern": "(?:28[2-9]|8(?:11|[2-57-9]\\d))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "66123456", "nationalNumberPattern": "6800[0-79]\\d{3}|6(?:[235]\\d\\d|6(?:0[0-5]|[1-9]\\d)|8(?:0[1-9]|[146-8]\\d|2[5-9]|[35][0-4]))\\d{4}"}}, {"nationalPrefixForParsing": "1|([2-9]\\d{6})$", "countryCode": "1", "leadingDigits": "670", "nationalPrefix": "1", "nationalPrefixTransformRule": "670$1", "internationalPrefix": "011", "id": "MP", "generalDesc": {"nationalNumberPattern": "[58]\\d{9}|(?:67|90)0\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6702345678", "nationalNumberPattern": "670(?:2(?:3[3-7]|56|8[4-8])|32[1-38]|4(?:33|8[348])|5(?:32|55|88)|6(?:64|70|82)|78[3589]|8[3-9]8|989)\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6702345678", "nationalNumberPattern": "670(?:2(?:3[3-7]|56|8[4-8])|32[1-38]|4(?:33|8[348])|5(?:32|55|88)|6(?:64|70|82)|78[3589]|8[3-9]8|989)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MQ", "countryCode": "596", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[569]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "69\\d{7}|(?:59|97)6\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "596301234", "nationalNumberPattern": "596(?:0[0-7]|10|2[7-9]|3[05-9]|4[0-46-8]|[5-7]\\d|8[09]|9[4-8])\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "696201234", "nationalNumberPattern": "69(?:6(?:[0-47-9]\\d|5[0-6]|6[0-4])|727)\\d{4}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "976612345", "nationalNumberPattern": "976(?:6[1-9]|7[0-367])\\d{4}"}}, {"internationalPrefix": "00", "id": "MR", "countryCode": "222", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[2-48]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:[2-4]\\d\\d|800)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "35123456", "nationalNumberPattern": "(?:25[08]|35\\d|45[1-7])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "22123456", "nationalNumberPattern": "[2-4][0-46-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}}, {"nationalPrefixForParsing": "1|([34]\\d{6})$", "countryCode": "1", "leadingDigits": "664", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "664$1", "internationalPrefix": "011", "id": "MS", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|664|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6644912345", "nationalNumberPattern": "6644(?:1[0-3]|91)\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6644923456", "nationalNumberPattern": "664(?:3(?:49|9[1-6])|49[2-6])\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"internationalPrefix": "00", "id": "MT", "countryCode": "356", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[2357-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "3550\\d{4}|(?:[2579]\\d\\d|800)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21001234", "nationalNumberPattern": "2(?:0(?:[19]\\d|3[1-4]|6[059])|[1-357]\\d\\d)\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "96961234", "nationalNumberPattern": "(?:7(?:210|[79]\\d\\d)|9(?:[29]\\d\\d|69[67]|8(?:1[1-3]|89|97)))\\d{4}"}, "pager": {"possibleLengths": {"national": "8"}, "exampleNumber": "71171234", "nationalNumberPattern": "7117\\d{4}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80071234", "nationalNumberPattern": "800[3467]\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "50037123", "nationalNumberPattern": "5(?:0(?:0(?:37|43)|(?:6\\d|70|9[0168])\\d)|[12]\\d0[1-5])\\d{3}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "35501234", "nationalNumberPattern": "3550\\d{4}"}, "uan": {"possibleLengths": {"national": "8"}, "exampleNumber": "50112345", "nationalNumberPattern": "501\\d{5}"}}, {"preferredInternationalPrefix": "020", "internationalPrefix": "0(?:0|[24-7]0|3[03])", "id": "MU", "countryCode": "230", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-46]|8[013]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "5", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:[2-468]|5\\d)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "54480123", "nationalNumberPattern": "(?:2(?:[0346-8]\\d|1[0-7])|4(?:[013568]\\d|2[4-7])|54(?:[3-5]\\d|71)|6\\d\\d|8(?:14|3[129]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "52512345", "nationalNumberPattern": "5(?:4(?:2[1-389]|7[1-9])|87[15-8])\\d{4}|5(?:2[5-9]|4[3-589]|5[1-9]|7\\d|8[0-689]|9[0-8])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "80[0-2]\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "3012345", "nationalNumberPattern": "30\\d{5}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "3201234", "nationalNumberPattern": "3(?:20|9\\d)\\d{4}"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "0(?:0|19)", "id": "MV", "countryCode": "960", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[3467]|9[13-9]", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "[89]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:800|9[0-57-9]\\d)\\d{7}|[34679]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "6701234", "nationalNumberPattern": "(?:3(?:0[0-3]|3[0-59])|6(?:[57][02468]|6[024-68]|8[024689]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "7712345", "nationalNumberPattern": "46[46]\\d{4}|(?:7\\d|9[13-9])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9001234567", "nationalNumberPattern": "900\\d{7}"}, "uan": {"possibleLengths": {"national": "7"}, "exampleNumber": "4001234", "nationalNumberPattern": "4[05]0\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MW", "countryCode": "265", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[2-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[137-9]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{6}(?:\\d{2})?|(?:[23]1|77|88|99)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "1234567", "nationalNumberPattern": "(?:1[2-9]|21\\d\\d)\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "991234567", "nationalNumberPattern": "111\\d{6}|(?:31|77|88|99)\\d{7}"}}, {"nationalPrefixForParsing": "0(?:[12]|4[45])|1", "countryCode": "52", "mobileNumberPortableRegion": "true", "nationalPrefix": "01", "preferredInternationalPrefix": "00", "internationalPrefix": "0[09]", "id": "MX", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5})", "leadingDigits": "53", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "33|5[56]|81", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "[2-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "1(?:33|5[56]|81)", "format": "$2 $3 $4"}, {"pattern": "(\\d)(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "1", "format": "$2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:1(?:[01467]\\d|[2359][1-9]|8[1-79])|[2-9]\\d)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7,8"}, "exampleNumber": "2001234567", "nationalNumberPattern": "(?:2(?:0[01]|2[1-9]|3[1-35-8]|4[13-9]|7[1-689]|8[1-578]|9[467])|3(?:1[1-79]|[2458][1-9]|3\\d|7[1-8]|9[1-5])|4(?:1[1-57-9]|[24-7][1-9]|3[1-8]|8[1-35-9]|9[2-689])|5(?:[56]\\d|88|9[1-79])|6(?:1[2-68]|[2-4][1-9]|5[1-3689]|6[1-57-9]|7[1-7]|8[67]|9[4-8])|7(?:[1-467][1-9]|5[13-9]|8[1-69]|9[17])|8(?:1\\d|2[13-689]|3[1-6]|4[124-6]|6[1246-9]|7[1-378]|9[12479])|9(?:1[346-9]|2[1-4]|3[2-46-8]|5[1348]|[69][1-9]|7[12]|8[1-8]))\\d{7}"}, "mobile": {"possibleLengths": {"national": "10,11", "localOnly": "7,8"}, "exampleNumber": "12221234567", "nationalNumberPattern": "(?:1(?:2(?:2[1-9]|3[1-35-8]|4[13-9]|7[1-689]|8[1-578]|9[467])|3(?:1[1-79]|[2458][1-9]|3\\d|7[1-8]|9[1-5])|4(?:1[1-57-9]|[24-7][1-9]|3[1-8]|8[1-35-9]|9[2-689])|5(?:[56]\\d|88|9[1-79])|6(?:1[2-68]|[2-4][1-9]|5[1-3689]|6[1-57-9]|7[1-7]|8[67]|9[4-8])|7(?:[1-467][1-9]|5[13-9]|8[1-69]|9[17])|8(?:1\\d|2[13-689]|3[1-6]|4[124-6]|6[1246-9]|7[1-378]|9[12479])|9(?:1[346-9]|2[1-4]|3[2-46-8]|5[1348]|[69][1-9]|7[12]|8[1-8]))|2(?:2[1-9]|3[1-35-8]|4[13-9]|7[1-689]|8[1-578]|9[467])|3(?:1[1-79]|[2458][1-9]|3\\d|7[1-8]|9[1-5])|4(?:1[1-57-9]|[24-7][1-9]|3[1-8]|8[1-35-9]|9[2-689])|5(?:[56]\\d|88|9[1-79])|6(?:1[2-68]|[2-4][1-9]|5[1-3689]|6[1-57-9]|7[1-7]|8[67]|9[4-8])|7(?:[1-467][1-9]|5[13-9]|8[1-69]|9[17])|8(?:1\\d|2[13-689]|3[1-6]|4[124-6]|6[1246-9]|7[1-378]|9[12479])|9(?:1[346-9]|2[1-4]|3[2-46-8]|5[1348]|[69][1-9]|7[12]|8[1-8]))\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "8(?:00|88)\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9001234567", "nationalNumberPattern": "900\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "3001234567", "nationalNumberPattern": "300\\d{7}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5001234567", "nationalNumberPattern": "500\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "MY", "countryCode": "60", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[4-79]", "format": "$1-$2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1(?:[02469]|[378][1-9])|8", "format": "$1-$2 $3"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3", "format": "$1-$2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{2})(\\d{4})", "leadingDigits": "1[36-8]", "format": "$1-$2-$3-$4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "15", "format": "$1-$2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1-$2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{8,9}|(?:3\\d|[4-9])\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8,9", "localOnly": "6,7"}, "exampleNumber": "323856789", "nationalNumberPattern": "(?:3(?:2[0-36-9]|3[0-368]|4[0-278]|5[0-24-8]|6[0-467]|7[1246-9]|8\\d|9[0-57])\\d|4(?:2[0-689]|[3-79]\\d|8[1-35689])|5(?:2[0-589]|[3468]\\d|5[0-489]|7[1-9]|9[23])|6(?:2[2-9]|3[1357-9]|[46]\\d|5[0-6]|7[0-35-9]|85|9[015-8])|7(?:[2579]\\d|3[03-68]|4[0-8]|6[5-9]|8[0-35-9])|8(?:[24][2-8]|3[2-5]|5[2-7]|6[2-589]|7[2-578]|[89][2-9])|9(?:0[57]|13|[25-7]\\d|[3489][0-8]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "123456789", "nationalNumberPattern": "1(?:4400|8(?:47|8[27])[0-4])\\d{4}|1(?:0(?:[23568]\\d|4[0-6]|7[016-9]|9[0-8])|1(?:[1-5]\\d\\d|6(?:0[5-9]|[1-9]\\d)|7(?:[0134]\\d|2[2-9]|5[0-6]))|(?:(?:[269]|59)\\d|[37][1-9]|4[235-9])\\d|8(?:1[23]|[236]\\d|4[06]|5[7-9]|7[016-9]|8[01]|9[0-8]))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "1300123456", "nationalNumberPattern": "1[378]00\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1600123456", "nationalNumberPattern": "1600\\d{6}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "1546012345", "nationalNumberPattern": "15(?:4(?:6[0-4]\\d|8(?:0[125]|[17]\\d|21|3[01]|4[01589]|5[014]|6[02]))|6(?:32[0-6]|78\\d))\\d{4}"}}, {"internationalPrefix": "00", "id": "MZ", "countryCode": "258", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "leadingDigits": "2|8[2-79]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:2|8\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21123456", "nationalNumberPattern": "2(?:[1346]\\d|5[0-2]|[78][12]|93)\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "821234567", "nationalNumberPattern": "8[2-79]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "NA", "countryCode": "264", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "88", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "87", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[68]\\d{7,8}"}, "fixedLine": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "61221234", "nationalNumberPattern": "64426\\d{3}|6(?:1(?:2[2-7]|3[01378]|4[0-4])|254|32[0237]|4(?:27|41|5[25])|52[236-8]|626|7(?:2[2-4]|30))\\d{4,5}|6(?:1(?:(?:0\\d|2[0189]|3[24-69]|4[5-9])\\d|17|69|7[014])|2(?:17|5[0-36-8]|69|70)|3(?:17|2[14-689]|34|6[289]|7[01]|81)|4(?:17|2[0-2]|4[06]|5[0137]|69|7[01])|5(?:17|2[0459]|69|7[01])|6(?:17|25|38|42|69|7[01])|7(?:17|2[569]|3[13]|6[89]|7[01]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "811234567", "nationalNumberPattern": "(?:60|8[1245])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "870123456", "nationalNumberPattern": "8701\\d{5}"}, "voip": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "88612345", "nationalNumberPattern": "8(?:3\\d\\d|86)\\d{5}"}}, {"internationalPrefix": "00", "id": "NC", "countryCode": "687", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})", "leadingDigits": "5[6-8]", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[2-57-9]", "format": "$1.$2.$3"}]}, "generalDesc": {"nationalNumberPattern": "[2-57-9]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6"}, "exampleNumber": "201234", "nationalNumberPattern": "(?:2[03-9]|3[0-5]|4[1-7]|88)\\d{4}"}, "mobile": {"possibleLengths": {"national": "6"}, "exampleNumber": "751234", "nationalNumberPattern": "(?:5[0-4]|[79]\\d|8[0-79])\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "6"}, "exampleNumber": "366711", "nationalNumberPattern": "36\\d{4}"}}, {"internationalPrefix": "00", "id": "NE", "countryCode": "227", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3})", "leadingDigits": "08", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[089]|2[013]|7[04]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[027-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "20201234", "nationalNumberPattern": "2(?:0(?:20|3[1-8]|4[13-5]|5[14]|6[14578]|7[1-578])|1(?:4[145]|5[14]|6[14-68]|7[169]|88))\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "93123456", "nationalNumberPattern": "(?:23|7[04]|[89]\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "08123456", "nationalNumberPattern": "08\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "09123456", "nationalNumberPattern": "09\\d{6}"}}, {"nationalPrefixForParsing": "([0-258]\\d{4})$", "internationalPrefix": "00", "id": "NF", "countryCode": "672", "nationalPrefixTransformRule": "3$1", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{4})", "leadingDigits": "1[0-3]", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{5})", "leadingDigits": "[13]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[13]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6", "localOnly": "5"}, "exampleNumber": "106609", "nationalNumberPattern": "(?:1(?:06|17|28|39)|3[0-2]\\d)\\d{3}"}, "mobile": {"possibleLengths": {"national": "6", "localOnly": "5"}, "exampleNumber": "381234", "nationalNumberPattern": "(?:14|3[58])\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "009", "id": "NG", "countryCode": "234", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "78", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12]|9(?:0[3-9]|[1-9])", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3-7]|8[2-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[7-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[78]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{5})(\\d{5,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[78]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[124-7]|9\\d{3})\\d{6}|[1-9]\\d{7}|[78]\\d{9,13}"}, "fixedLine": {"possibleLengths": {"national": "7,8", "localOnly": "5,6"}, "exampleNumber": "18040123", "nationalNumberPattern": "(?:(?:[1-356]\\d|4[02-8]|8[2-9])\\d|9(?:0[3-9]|[1-9]\\d))\\d{5}|7(?:0(?:[013-689]\\d|2[0-24-9])\\d{3,4}|[1-79]\\d{6})|(?:[12]\\d|4[147]|5[14579]|6[1578]|7[1-3578])\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "8021234567", "nationalNumberPattern": "(?:702[0-24-9]|8(?:01|19)[01])\\d{6}|(?:70[13-689]|8(?:0[2-9]|1[0-8])|9(?:0[1-9]|1[235]))\\d{7}"}, "tollFree": {"possibleLengths": {"national": "[10-14]"}, "exampleNumber": "80017591759", "nationalNumberPattern": "800\\d{7,11}"}, "uan": {"possibleLengths": {"national": "[10-14]"}, "exampleNumber": "7001234567", "nationalNumberPattern": "700\\d{7,11}"}}, {"internationalPrefix": "00", "id": "NI", "countryCode": "505", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[125-8]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:1800|[25-8]\\d{3})\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "2\\d{7}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "81234567", "nationalNumberPattern": "(?:5(?:5[0-7]|[78]\\d)|6(?:20|3[035]|4[045]|5[05]|77|8[1-9]|9[059])|(?:7[5-8]|8\\d)\\d)\\d{5}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "18001234", "nationalNumberPattern": "1800\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "NL", "countryCode": "31", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})", "leadingDigits": "1[238]|[34]", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{3,4})", "leadingDigits": "14", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{6})", "leadingDigits": "1", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{4,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]0", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "66", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "6", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[16-8]|2[259]|3[124]|4[17-9]|5[124679]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-57-9]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[124-7]\\d\\d|3(?:[02-9]\\d|1[0-8]))\\d{6}|[89]\\d{6,9}|1\\d{4,5}"}, "noInternationalDialling": {"possibleLengths": {"national": "5,6"}, "nationalNumberPattern": "140(?:1[035]|2[0346]|3[03568]|4[0356]|5[0358]|8[458])|140(?:1[16-8]|2[259]|3[124]|4[17-9]|5[124679]|7)\\d"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "101234567", "nationalNumberPattern": "(?:1(?:[035]\\d|1[13-578]|6[124-8]|7[24]|8[0-467])|2(?:[0346]\\d|2[2-46-9]|5[125]|9[479])|3(?:[03568]\\d|1[3-8]|2[01]|4[1-8])|4(?:[0356]\\d|1[1-368]|7[58]|8[15-8]|9[23579])|5(?:[0358]\\d|[19][1-9]|2[1-57-9]|4[13-8]|6[126]|7[0-3578])|7\\d\\d)\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "612345678", "nationalNumberPattern": "6[1-58]\\d{7}"}, "pager": {"possibleLengths": {"national": "9"}, "exampleNumber": "662345678", "nationalNumberPattern": "66\\d{7}"}, "tollFree": {"possibleLengths": {"national": "[7-10]"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4,7}"}, "premiumRate": {"possibleLengths": {"national": "[7-10]"}, "exampleNumber": "9061234", "nationalNumberPattern": "90[069]\\d{4,7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "851234567", "nationalNumberPattern": "(?:85|91)\\d{7}"}, "uan": {"possibleLengths": {"national": "5,6,9"}, "exampleNumber": "14020", "nationalNumberPattern": "140(?:1[035]|2[0346]|3[03568]|4[0356]|5[0358]|8[458])|(?:140(?:1[16-8]|2[259]|3[124]|4[17-9]|5[124679]|7)|8[478]\\d{6})\\d"}}, {"mainCountryForCode": "true", "countryCode": "47", "leadingDigits": "[02-689]|7[0-8]", "mobileNumberPortableRegion": "true", "internationalPrefix": "00", "id": "NO", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{3})", "leadingDigits": "[489]|5[89]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[235-7]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:0|[2-9]\\d{3})\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:2[1-4]|3[1-3578]|5[1-35-7]|6[1-4679]|7[0-8])\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "40612345", "nationalNumberPattern": "(?:4[015-8]|5[89]|9\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "80[01]\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "82012345", "nationalNumberPattern": "82[09]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "81021234", "nationalNumberPattern": "810(?:0[0-6]|[2-8]\\d)\\d{3}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "88012345", "nationalNumberPattern": "880\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "85012345", "nationalNumberPattern": "85[0-5]\\d{5}"}, "uan": {"possibleLengths": {"national": "5,8"}, "exampleNumber": "02000", "nationalNumberPattern": "(?:0[2-9]|81(?:0(?:0[7-9]|1\\d)|5\\d\\d))\\d{3}"}, "voicemail": {"possibleLengths": {"national": "8"}, "exampleNumber": "81212345", "nationalNumberPattern": "81[23]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "NP", "countryCode": "977", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[2-6]", "format": "$1-$2"}, {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[01]|[2-8]|9(?:[1-579]|6[2-6])", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{7})", "leadingDigits": "9", "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{2})(\\d{5})", "leadingDigits": "1", "format": "$1-$2-$3", "intlFormat": "NA"}]}, "generalDesc": {"nationalNumberPattern": "(?:1\\d|9)\\d{9}|[1-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6,7"}, "exampleNumber": "14567890", "nationalNumberPattern": "(?:1[0-6]\\d|99[02-6])\\d{5}|(?:2[13-79]|3[135-8]|4[146-9]|5[135-7]|6[13-9]|7[15-9]|8[1-46-9]|9[1-7])[2-6]\\d{5}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "9841234567", "nationalNumberPattern": "9(?:6[0-3]|7[245]|8[0-24-68])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "11"}, "exampleNumber": "16600101234", "nationalNumberPattern": "1(?:66001|800\\d\\d)\\d{5}"}}, {"internationalPrefix": "00", "id": "NR", "countryCode": "674", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[4-68]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:444|(?:55|8\\d)\\d|666)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "4441234", "nationalNumberPattern": "444\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "5551234", "nationalNumberPattern": "(?:55[3-9]|666|8\\d\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "NU", "countryCode": "683", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "8", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[47]|888\\d)\\d{3}"}, "fixedLine": {"possibleLengths": {"national": "4"}, "exampleNumber": "7012", "nationalNumberPattern": "[47]\\d{3}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "8884012", "nationalNumberPattern": "888[4-9]\\d{3}"}}, {"countryCode": "64", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredInternationalPrefix": "00", "internationalPrefix": "0(?:0|161)", "id": "NZ", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3,8})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8[1-579]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["50[036-8]|[89]0", "50(?:[0367]|88)|[89]0"], "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "24|[346]|7[2-57-9]|9[2-9]", "format": "$1-$2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2(?:10|74)|[59]|80", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3,4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1|2[028]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2(?:[169]|7[0-35-9])|7|86", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[29]\\d{7,9}|50\\d{5}(?:\\d{2,3})?|6[0-35-9]\\d{6}|7\\d{7,8}|8\\d{4,9}|(?:11\\d|[34])\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "32345678", "nationalNumberPattern": "24099\\d{3}|(?:3[2-79]|[49][2-9]|6[235-9]|7[2-57-9])\\d{6}"}, "mobile": {"possibleLengths": {"national": "[8-10]"}, "exampleNumber": "211234567", "nationalNumberPattern": "2[0-27-9]\\d{7,8}|21\\d{6}"}, "pager": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "26123456", "nationalNumberPattern": "[28]6\\d{6,7}"}, "tollFree": {"possibleLengths": {"national": "[8-10]"}, "exampleNumber": "800123456", "nationalNumberPattern": "508\\d{6,7}|80\\d{6,8}"}, "premiumRate": {"possibleLengths": {"national": "[7-10]"}, "exampleNumber": "900123456", "nationalNumberPattern": "(?:11\\d{5}|50(?:0[08]|30|66|77|88))\\d{3}|90\\d{6,8}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "701234567", "nationalNumberPattern": "70\\d{7}"}, "uan": {"possibleLengths": {"national": "[5-10]"}, "exampleNumber": "83012378", "nationalNumberPattern": "8(?:1[6-9]|22|3\\d|4[045]|5[459]|7[0-3579]|90)\\d{2,7}"}}, {"internationalPrefix": "00", "id": "OM", "countryCode": "968", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4,6})", "leadingDigits": "[58]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{6})", "leadingDigits": "2", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[179]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:1505|[279]\\d{3}|500)\\d{4}|800\\d{5,6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "23123456", "nationalNumberPattern": "2[2-6]\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "92123456", "nationalNumberPattern": "(?:1505|90[1-9]\\d)\\d{4}|(?:7[1289]|9[1-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "80071234", "nationalNumberPattern": "8007\\d{4,5}|(?:500|800[05])\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "900\\d{5}"}}, {"internationalPrefix": "00", "id": "PA", "countryCode": "507", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[1-57-9]", "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[68]", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "8\\d{9}|[68]\\d{7}|[1-57-9]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2001234", "nationalNumberPattern": "(?:1(?:0\\d|1[479]|2[37]|3[0137]|4[17]|5[05]|6[58]|7[0167]|8[258]|9[139])|2(?:[0235-79]\\d|1[0-7]|4[013-9]|8[026-9])|3(?:[089]\\d|1[014-7]|2[0-5]|33|4[0-79]|55|6[068]|7[03-8])|4(?:00|3[0-579]|4\\d|7[0-57-9])|5(?:[01]\\d|2[0-7]|[56]0|79)|7(?:0[09]|2[0-26-8]|3[03]|4[04]|5[05-9]|6[056]|7[0-24-9]|8[6-9]|90)|8(?:09|2[89]|3\\d|4[0-24-689]|5[014]|8[02])|9(?:0[5-9]|1[0135-8]|2[036-9]|3[35-79]|40|5[0457-9]|6[05-9]|7[04-9]|8[35-8]|9\\d))\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "61234567", "nationalNumberPattern": "(?:1[16]1|21[89]|6(?:[02-9]\\d|1[0-7])\\d|8(?:1[01]|7[23]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "7,8,10"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4}(?:\\d(?:\\d{2})?)?"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "8601234", "nationalNumberPattern": "(?:8(?:22|55|60|7[78]|86)|9(?:00|81))\\d{4}"}}, {"countryCode": "51", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredExtnPrefix": " Anexo ", "internationalPrefix": "19(?:1[124]|77|90)00", "id": "PE", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "80", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{7})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "1", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[4-8]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "9", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[14-8]|9\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6,7"}, "exampleNumber": "11234567", "nationalNumberPattern": "(?:(?:4[34]|5[14])[0-8]\\d|7(?:173|3[0-8]\\d)|8(?:10[05689]|6(?:0[06-9]|1[6-9]|29)|7(?:0[569]|[56]0)))\\d{4}|(?:1[0-8]|4[12]|5[236]|6[1-7]|7[246]|8[2-4])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "9\\d{8}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "80512345", "nationalNumberPattern": "805\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "80112345", "nationalNumberPattern": "801\\d{5}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "80212345", "nationalNumberPattern": "80[24]\\d{5}"}}, {"internationalPrefix": "00", "id": "PF", "countryCode": "689", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "44", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[48]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[48]\\d{7}|4\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "6"}, "nationalNumberPattern": "44\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "40412345", "nationalNumberPattern": "4(?:0[4-689]|9[4-68])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "87123456", "nationalNumberPattern": "8[7-9]\\d{6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "49901234", "nationalNumberPattern": "499\\d{5}"}, "uan": {"possibleLengths": {"national": "6"}, "exampleNumber": "440123", "nationalNumberPattern": "44\\d{4}"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "00|140[1-3]", "id": "PG", "countryCode": "675", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "18|[2-69]|85", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[78]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:180|[78]\\d{3})\\d{4}|(?:[2-589]\\d|64)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "3123456", "nationalNumberPattern": "(?:64[1-9]|7730|85[02-46-9])\\d{4}|(?:3[0-2]|4[257]|5[34]|77[0-24]|9[78])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "70123456", "nationalNumberPattern": "77(?:3[1-9]|[5-9]\\d)\\d{4}|(?:7[0-689]|8[18])\\d{6}"}, "pager": {"possibleLengths": {"national": "7"}, "exampleNumber": "2700123", "nationalNumberPattern": "27[01]\\d{4}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "1801234", "nationalNumberPattern": "180\\d{4}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "2751234", "nationalNumberPattern": "2(?:0[0-47]|7[568])\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "PH", "countryCode": "63", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{4,6})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": ["3(?:23|39|46)|4(?:2[3-6]|[35]9|4[26]|76)|544|88[245]|(?:52|64|86)2", "3(?:230|397|461)|4(?:2(?:35|[46]4|51)|396|4(?:22|63)|59[347]|76[15])|5(?:221|446)|642[23]|8(?:622|8(?:[24]2|5[13]))"], "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": ["346|4(?:27|9[35])|883", "3469|4(?:279|9(?:30|56))|8834"], "format": "$1 $2"}, {"pattern": "(\\d)(\\d{4})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[3-7]|8[2-8]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{1,2})(\\d{3})(\\d{4})", "leadingDigits": "1", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "1800\\d{7,9}|(?:2|[89]\\d{4})\\d{5}|[2-8]\\d{8}|[28]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "6,[8-10]", "localOnly": "4,5,7"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:(?:2[3-8]|3[2-68]|4[2-9]|5[2-6]|6[2-58]|7[24578])\\d{3}|88(?:22\\d\\d|42))\\d{4}|2\\d{5}(?:\\d{2})?|8[2-8]\\d{7}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "9051234567", "nationalNumberPattern": "(?:81[37]|9(?:0[5-9]|1[0-24-9]|2[0-35-9]|[35]\\d|4[235-9]|6[0-35-8]|7[1-9]|8[189]|9[4-9]))\\d{7}"}, "tollFree": {"possibleLengths": {"national": "[11-13]"}, "exampleNumber": "180012345678", "nationalNumberPattern": "1800\\d{7,9}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "PK", "countryCode": "92", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{2,7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]0", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{5})", "leadingDigits": "1", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{6,7})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": ["2(?:3[2358]|4[2-4]|9[2-8])|45[3479]|54[2-467]|60[468]|72[236]|8(?:2[2-689]|3[23578]|4[3478]|5[2356])|9(?:2[2-8]|3[27-9]|4[2-6]|6[3569]|9[25-8])", "9(?:2[3-8]|98)|(?:2(?:3[2358]|4[2-4]|9[2-8])|45[3479]|54[2-467]|60[468]|72[236]|8(?:2[2-689]|3[23578]|4[3478]|5[2356])|9(?:22|3[27-9]|4[2-6]|6[3569]|9[25-7]))[2-9]"], "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{7,8})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]", "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "58", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "3", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[24-9]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "122\\d{6}|[24-8]\\d{10,11}|9(?:[013-9]\\d{8,10}|2(?:[01]\\d\\d|2(?:[06-8]\\d|1[01]))\\d{7})|(?:[2-8]\\d{3}|92(?:[0-7]\\d|8[1-9]))\\d{6}|[24-9]\\d{8}|[89]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9,10", "localOnly": "[5-8]"}, "exampleNumber": "2123456789", "nationalNumberPattern": "(?:(?:21|42)[2-9]|58[126])\\d{7}|(?:2[25]|4[0146-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]\\d{6,7}|(?:2(?:3[2358]|4[2-4]|9[2-8])|45[3479]|54[2-467]|60[468]|72[236]|8(?:2[2-689]|3[23578]|4[3478]|5[2356])|9(?:2[2-8]|3[27-9]|4[2-6]|6[3569]|9[25-8]))[2-9]\\d{5,6}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "3012345678", "nationalNumberPattern": "3(?:[014]\\d|2[0-5]|3[0-7]|55|64)\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8,11"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{5}(?:\\d{3})?"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90012345", "nationalNumberPattern": "900\\d{5}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "122044444", "nationalNumberPattern": "122\\d{6}"}, "uan": {"possibleLengths": {"national": "11,12"}, "exampleNumber": "21111825888", "nationalNumberPattern": "(?:2(?:[125]|3[2358]|4[2-4]|9[2-8])|4(?:[0-246-9]|5[3479])|5(?:[1-35-7]|4[2-467])|6(?:0[468]|[1-8])|7(?:[14]|2[236])|8(?:[16]|2[2-689]|3[23578]|4[3478]|5[2356])|9(?:1|22|3[27-9]|4[2-6]|6[3569]|9[2-7]))111\\d{6}"}}, {"internationalPrefix": "00", "id": "PL", "countryCode": "48", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5})", "leadingDigits": "19", "format": "$1"}, {"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "11|64", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{2})(\\d{3})", "leadingDigits": ["(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])1", "(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])19"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2,3})", "leadingDigits": "64", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "39|45|5[0137]|6[0469]|7[02389]|8(?:0[14]|8)", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "leadingDigits": "1[2-8]|[2-7]|8[1-79]|9[145]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "6\\d{5}(?:\\d{2})?|8\\d{9}|[1-9]\\d{6}(?:\\d{2})?"}, "fixedLine": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "123456789", "nationalNumberPattern": "47\\d{7}|(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])(?:[02-9]\\d{6}|1(?:[0-8]\\d{5}|9\\d{3}(?:\\d{2})?))"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "512345678", "nationalNumberPattern": "(?:45|5[0137]|6[069]|7[2389]|88)\\d{7}"}, "pager": {"possibleLengths": {"national": "[6-9]"}, "exampleNumber": "641234567", "nationalNumberPattern": "64\\d{4,7}"}, "tollFree": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6,7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "701234567", "nationalNumberPattern": "70[01346-8]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "801\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "391234567", "nationalNumberPattern": "39\\d{7}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "804123456", "nationalNumberPattern": "804\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "PM", "countryCode": "508", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[45]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[45]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6"}, "exampleNumber": "430123", "nationalNumberPattern": "(?:4[1-3]|50)\\d{4}"}, "mobile": {"possibleLengths": {"national": "6"}, "exampleNumber": "551234", "nationalNumberPattern": "(?:4[02-4]|5[05])\\d{4}"}}, {"countryCode": "1", "leadingDigits": "787|939", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "internationalPrefix": "011", "id": "PR", "generalDesc": {"nationalNumberPattern": "(?:[589]\\d\\d|787)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7872345678", "nationalNumberPattern": "(?:787|939)[2-9]\\d{6}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7872345678", "nationalNumberPattern": "(?:787|939)[2-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "PS", "countryCode": "970", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2489]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[2489]2\\d{6}|(?:1\\d|5)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "22234567", "nationalNumberPattern": "(?:22[2-47-9]|42[45]|82[014-68]|92[3569])\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "599123456", "nationalNumberPattern": "5[69]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "1800\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "10"}, "exampleNumber": "1700123456", "nationalNumberPattern": "1700\\d{6}"}}, {"internationalPrefix": "00", "id": "PT", "countryCode": "351", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{4})", "leadingDigits": "2[12]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[236-9]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[26-9]\\d|30)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "212345678", "nationalNumberPattern": "2(?:[12]\\d|[35][1-689]|4[1-59]|6[1-35689]|7[1-9]|8[1-69]|9[1256])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "6[356]9230\\d{3}|(?:6[036]93|9(?:[1-36]\\d\\d|480))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80[02]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "760123456", "nationalNumberPattern": "(?:6(?:0[178]|4[68])\\d|76(?:0[1-57]|1[2-47]|2[237]))\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "808123456", "nationalNumberPattern": "80(?:8\\d|9[1579])\\d{5}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "884123456", "nationalNumberPattern": "884[0-4689]\\d{5}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "301234567", "nationalNumberPattern": "30\\d{7}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "707123456", "nationalNumberPattern": "70(?:7\\d|8[17])\\d{5}"}, "voicemail": {"possibleLengths": {"national": "9"}, "exampleNumber": "600110000", "nationalNumberPattern": "600\\d{6}"}}, {"internationalPrefix": "01[12]", "id": "PW", "countryCode": "680", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[24-8]\\d\\d|345|900)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2771234", "nationalNumberPattern": "(?:2(?:55|77)|345|488|5(?:35|44|87)|6(?:22|54|79)|7(?:33|47)|8(?:24|55|76)|900)\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "6201234", "nationalNumberPattern": "(?:46[0-5]|6[2-4689]0)\\d{4}|(?:45|77|88)\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "PY", "countryCode": "595", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-9]0", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[26]1|3[289]|4[1246-8]|7[1-3]|8[1-36]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4,5})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2[279]|3[13-5]|4[359]|5|6(?:[34]|7[1-46-8])|7[46-8]|85", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "2[14-68]|3[26-9]|4[1246-8]|6(?:1|75)|7[1-35]|8[1-36]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "leadingDigits": "87", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9(?:[5-79]|8[1-6])", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-8]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "9", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "59\\d{4,6}|9\\d{5,10}|(?:[2-46-8]\\d|5[0-8])\\d{4,7}"}, "fixedLine": {"possibleLengths": {"national": "[7-9]", "localOnly": "5,6"}, "exampleNumber": "212345678", "nationalNumberPattern": "(?:[26]1|3[289]|4[1246-8]|7[1-3]|8[1-36])\\d{5,7}|(?:2(?:2[4-68]|[4-68]\\d|7[15]|9[1-5])|3(?:18|3[167]|4[2357]|51|[67]\\d)|4(?:3[12]|5[13]|9[1-47])|5(?:[1-4]\\d|5[02-4])|6(?:3[1-3]|44|7[1-8])|7(?:4[0-4]|5\\d|6[1-578]|75|8[0-8])|858)\\d{5,6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "961456789", "nationalNumberPattern": "9(?:51|6[129]|[78][1-6]|9[1-5])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "[9-11]"}, "exampleNumber": "98000123456", "nationalNumberPattern": "9800\\d{5,7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "870012345", "nationalNumberPattern": "8700[0-4]\\d{4}"}, "uan": {"possibleLengths": {"national": "[6-9]"}, "exampleNumber": "201234567", "nationalNumberPattern": "[2-9]0\\d{4,7}"}}, {"internationalPrefix": "00", "id": "QA", "countryCode": "974", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "2[126]|8", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[2-7]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[2-7]\\d{7}|(?:2\\d\\d|800)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "44123456", "nationalNumberPattern": "(?:23|4[04])\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "33123456", "nationalNumberPattern": "(?:28|[35-7]\\d)\\d{6}"}, "pager": {"possibleLengths": {"national": "7"}, "exampleNumber": "2123456", "nationalNumberPattern": "2(?:[12]\\d|61)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4}"}}, {"mainCountryForCode": "true", "countryCode": "262", "leadingDigits": "26[23]|69|[89]", "nationalPrefix": "0", "internationalPrefix": "00", "id": "RE", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2689]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "9769\\d{5}|(?:26|[68]\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "262161234", "nationalNumberPattern": "26(?:2\\d\\d|30[01])\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "692123456", "nationalNumberPattern": "(?:69(?:2\\d\\d|3(?:0[0-46]|1[013]|2[0-2]|3[0-39]|4\\d|5[05]|6[0-36]|7[0-27]|8[0-8]|9[0-479]))|9769\\d)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "80\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "891123456", "nationalNumberPattern": "89[1-37-9]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "810123456", "nationalNumberPattern": "8(?:1[019]|2[0156]|84|90)\\d{6}"}}, {"countryCode": "40", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredExtnPrefix": " int ", "internationalPrefix": "00", "id": "RO", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["2[3-6]", "2[3-6]\\d9"], "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "219|31", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23]1", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[237-9]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[237]\\d|[89]0)\\d{7}|[23]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6,9"}, "exampleNumber": "211234567", "nationalNumberPattern": "[23][13-6]\\d{7}|(?:2(?:19\\d|[3-6]\\d9)|31\\d\\d)\\d\\d"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "712034567", "nationalNumberPattern": "7[01]20\\d{5}|7(?:0[013-9]|1[01]|[2-7]\\d|8[03-8]|9[09])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "90[0136]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "801123456", "nationalNumberPattern": "801\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "372123456", "nationalNumberPattern": "(?:37\\d|80[578])\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "RS", "countryCode": "381", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3,9})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "(?:2[389]|39)0|[7-9]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{5,10})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-36]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "38[02-9]\\d{6,9}|6\\d{7,9}|90\\d{4,8}|38\\d{5,6}|(?:7\\d\\d|800)\\d{3,9}|(?:[12]\\d|3[0-79])\\d{5,10}"}, "fixedLine": {"possibleLengths": {"national": "[7-12]", "localOnly": "[4-6]"}, "exampleNumber": "10234567", "nationalNumberPattern": "(?:11[1-9]\\d|(?:2[389]|39)(?:0[2-9]|[2-9]\\d))\\d{3,8}|(?:1[02-9]|2[0-24-7]|3[0-8])[2-9]\\d{4,9}"}, "mobile": {"possibleLengths": {"national": "[8-10]"}, "exampleNumber": "601234567", "nationalNumberPattern": "6(?:[0-689]|7\\d)\\d{6,7}"}, "tollFree": {"possibleLengths": {"national": "[6-12]"}, "exampleNumber": "80012345", "nationalNumberPattern": "800\\d{3,9}"}, "premiumRate": {"possibleLengths": {"national": "[6-10]"}, "exampleNumber": "90012345", "nationalNumberPattern": "(?:78\\d|90[0169])\\d{3,7}"}, "uan": {"possibleLengths": {"national": "[6-12]"}, "exampleNumber": "700123456", "nationalNumberPattern": "7[06]\\d{4,10}"}}, {"mainCountryForCode": "true", "countryCode": "7", "leadingDigits": "3[04-689]|[489]", "nationalPrefix": "8", "preferredInternationalPrefix": "8~10", "internationalPrefix": "810", "id": "RU", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{2})", "leadingDigits": "[0-79]", "format": "$1-$2-$3", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP ($FG)", "leadingDigits": ["7(?:1[0-8]|2[1-9])", "7(?:1(?:[0-6]2|7|8[27])|2(?:1[23]|[2-9]2))", "7(?:1(?:[0-6]2|7|8[27])|2(?:13[03-69]|62[013-9]))|72[1-57-9]2"], "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{5})(\\d)(\\d{2})(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP ($FG)", "leadingDigits": ["7(?:1[0-68]|2[1-9])", "7(?:1(?:[06][3-6]|[18]|2[35]|[3-5][3-5])|2(?:[13][3-5]|[24-689]|7[457]))", "7(?:1(?:0(?:[356]|4[023])|[18]|2(?:3[013-9]|5)|3[45]|43[013-79]|5(?:3[1-8]|4[1-7]|5)|6(?:3[0-35-9]|[4-6]))|2(?:1(?:3[178]|[45])|[24-689]|3[35]|7[457]))|7(?:14|23)4[0-8]|71(?:33|45)[1-79]"], "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP ($FG)", "leadingDigits": "7", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP ($FG)", "leadingDigits": "[3489]", "format": "$1 $2-$3-$4"}]}, "generalDesc": {"nationalNumberPattern": "[347-9]\\d{9}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "3011234567", "nationalNumberPattern": "(?:3(?:0[12]|4[1-35-79]|5[1-3]|65|8[1-58]|9[0145])|4(?:01|1[1356]|2[13467]|7[1-5]|8[1-7]|9[1-689])|8(?:1[1-8]|2[01]|3[13-6]|4[0-8]|5[15]|6[1-35-79]|7[1-37-9]))\\d{7}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "9123456789", "nationalNumberPattern": "9\\d{9}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "80[04]\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "8091234567", "nationalNumberPattern": "80[39]\\d{7}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "8081234567", "nationalNumberPattern": "808\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "RW", "countryCode": "250", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "0", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[7-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "2", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:06|[27]\\d\\d|[89]00)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "250123456", "nationalNumberPattern": "(?:06|2[23568]\\d)\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "720123456", "nationalNumberPattern": "7[238]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "900\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SA", "countryCode": "966", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{5})", "leadingDigits": "9", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "5", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "81", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "92\\d{7}|(?:[15]|8\\d)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "7"}, "exampleNumber": "112345678", "nationalNumberPattern": "1(?:1\\d|2[24-8]|3[35-8]|4[3-68]|6[2-5]|7[235-7])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "512345678", "nationalNumberPattern": "579[01]\\d{5}|5(?:[013-689]\\d|7[0-36-8])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "925012345", "nationalNumberPattern": "925\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "920012345", "nationalNumberPattern": "920\\d{6}"}, "uan": {"possibleLengths": {"national": "10"}, "exampleNumber": "8110123456", "nationalNumberPattern": "811\\d{7}"}}, {"internationalPrefix": "0[01]", "id": "SB", "countryCode": "677", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{5})", "leadingDigits": "7|8[4-9]|9(?:[1-8]|9[0-8])", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[1-6]|[7-9]\\d\\d)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "40123", "nationalNumberPattern": "(?:1[4-79]|[23]\\d|4[0-2]|5[03]|6[0-37])\\d{3}"}, "mobile": {"possibleLengths": {"national": "5,7"}, "exampleNumber": "7421234", "nationalNumberPattern": "48\\d{3}|(?:(?:7[1-9]|8[4-9])\\d|9(?:1[2-9]|2[013-9]|3[0-2]|[46]\\d|5[0-46-9]|7[0-689]|8[0-79]|9[0-8]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "5"}, "exampleNumber": "18123", "nationalNumberPattern": "1[38]\\d{3}"}, "voip": {"possibleLengths": {"national": "5"}, "exampleNumber": "51123", "nationalNumberPattern": "5[12]\\d{3}"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "010|0[0-2]", "id": "SC", "countryCode": "248", "availableFormats": {"numberFormat": {"pattern": "(\\d)(\\d{3})(\\d{3})", "leadingDigits": "[246]|9[57]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "8000\\d{3}|(?:[249]\\d|64)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "4217123", "nationalNumberPattern": "4[2-46]\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "2510123", "nationalNumberPattern": "2[5-8]\\d{5}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8000000", "nationalNumberPattern": "8000\\d{3}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "6412345", "nationalNumberPattern": "971\\d{4}|(?:64|95)\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SD", "countryCode": "249", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[19]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[19]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "153123456", "nationalNumberPattern": "1(?:5\\d|8[35-7])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "911231234", "nationalNumberPattern": "(?:1[0-2]|9[0-3569])\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SE", "countryCode": "46", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2,3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "20", "format": "$1-$2 $3", "intlFormat": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9(?:00|39|44)", "format": "$1-$2", "intlFormat": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[12][136]|3[356]|4[0246]|6[03]|90[1-9]", "format": "$1-$2 $3", "intlFormat": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{2,3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1-$2 $3 $4", "intlFormat": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2,3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[125689]|4[02-57]|7[0-2])|9(?:[125-8]|3[02-5]|4[0-3])", "format": "$1-$2 $3", "intlFormat": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2,3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9(?:00|39|44)", "format": "$1-$2 $3", "intlFormat": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2,3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1[13689]|2[0136]|3[1356]|4[0246]|54|6[03]|90[1-9]", "format": "$1-$2 $3 $4", "intlFormat": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "10|7", "format": "$1-$2 $3 $4", "intlFormat": "$1 $2 $3 $4"}, {"pattern": "(\\d)(\\d{3})(\\d{3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1-$2 $3 $4", "intlFormat": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[13-5]|2(?:[247-9]|5[0138])|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[02-5]|4[0-3])", "format": "$1-$2 $3 $4", "intlFormat": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1-$2 $3 $4", "intlFormat": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[26]", "format": "$1-$2 $3 $4 $5", "intlFormat": "$1 $2 $3 $4 $5"}]}, "generalDesc": {"nationalNumberPattern": "(?:[26]\\d\\d|9)\\d{9}|[1-9]\\d{8}|[1-689]\\d{7}|[1-4689]\\d{6}|2\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "8123456", "nationalNumberPattern": "(?:(?:[12][136]|3[356]|4[0246]|6[03]|8\\d)\\d|90[1-9])\\d{4,6}|(?:1(?:2[0-35]|4[0-4]|5[0-25-9]|7[13-6]|[89]\\d)|2(?:2[0-7]|4[0136-8]|5[0138]|7[018]|8[01]|9[0-57])|3(?:0[0-4]|1\\d|2[0-25]|4[056]|7[0-2]|8[0-3]|9[023])|4(?:1[013-8]|3[0135]|5[14-79]|7[0-246-9]|8[0156]|9[0-689])|5(?:0[0-6]|[15][0-5]|2[0-68]|3[0-4]|4\\d|6[03-5]|7[013]|8[0-79]|9[01])|6(?:1[1-3]|2[0-4]|4[02-57]|5[0-37]|6[0-3]|7[0-2]|8[0247]|9[0-356])|9(?:1[0-68]|2\\d|3[02-5]|4[0-3]|5[0-4]|[68][01]|7[0135-8]))\\d{5,6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "701234567", "nationalNumberPattern": "7[02369]\\d{7}"}, "pager": {"possibleLengths": {"national": "9"}, "exampleNumber": "740123456", "nationalNumberPattern": "74[02-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "[6-9]"}, "exampleNumber": "20123456", "nationalNumberPattern": "20\\d{4,7}"}, "premiumRate": {"possibleLengths": {"national": "[7-10]"}, "exampleNumber": "9001234567", "nationalNumberPattern": "649\\d{6}|9(?:00|39|44)[1-8]\\d{3,6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "771234567", "nationalNumberPattern": "77[0-7]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "751234567", "nationalNumberPattern": "75[1-8]\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "102345678", "nationalNumberPattern": "10[1-8]\\d{6}"}, "voicemail": {"possibleLengths": {"national": "12"}, "exampleNumber": "254123456789", "nationalNumberPattern": "(?:25[245]|67[3-68])\\d{9}"}}, {"internationalPrefix": "0[0-3]\\d", "id": "SG", "countryCode": "65", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4,5})", "leadingDigits": ["1[013-9]|77", "1(?:[013-8]|9(?:0[1-9]|[1-9]))|77"], "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[369]|8(?:0[1-3]|[1-9])", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "leadingDigits": "8", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{4})(\\d{3})", "leadingDigits": "7", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{4})", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:(?:1\\d|8)\\d\\d|7000)\\d{7}|[3689]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "61234567", "nationalNumberPattern": "662[0-24-9]\\d{4}|6(?:[1-578]\\d|6[013-57-9]|9[0-35-9])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "81234567", "nationalNumberPattern": "(?:8(?:0(?:1\\d|2[0147-9]|3[013-5])|[1-8]\\d\\d|9(?:[0-4]\\d|5[0-2]))|9[0-8]\\d\\d)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "18001234567", "nationalNumberPattern": "(?:18|8)00\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "11"}, "exampleNumber": "19001234567", "nationalNumberPattern": "1900\\d{7}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "31234567", "nationalNumberPattern": "(?:3[12]\\d|666)\\d{5}"}, "uan": {"possibleLengths": {"national": "11"}, "exampleNumber": "70001234567", "nationalNumberPattern": "7000\\d{7}"}}, {"mainCountryForCode": "true", "internationalPrefix": "00", "id": "SH", "countryCode": "290", "leadingDigits": "[256]", "generalDesc": {"nationalNumberPattern": "(?:[256]\\d|8)\\d{3}"}, "fixedLine": {"possibleLengths": {"national": "4,5"}, "exampleNumber": "22158", "nationalNumberPattern": "2(?:[0-57-9]\\d|6[4-9])\\d\\d"}, "mobile": {"possibleLengths": {"national": "5"}, "exampleNumber": "51234", "nationalNumberPattern": "[56]\\d{4}"}, "voip": {"possibleLengths": {"national": "5"}, "exampleNumber": "26212", "nationalNumberPattern": "262\\d\\d"}}, {"countryCode": "386", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredInternationalPrefix": "00", "internationalPrefix": "00|10(?:22|66|88|99)", "id": "SI", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3,6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8[09]|9", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "59|8", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[37][01]|4[0139]|51|6", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[1-57]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[1-7]\\d{7}|8\\d{4,7}|90\\d{4,6}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "12345678", "nationalNumberPattern": "(?:[1-357][2-8]|4[24-8])\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "31234567", "nationalNumberPattern": "65(?:1\\d|55|[67]0)\\d{4}|(?:[37][01]|4[0139]|51|6[489])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "[6-8]"}, "exampleNumber": "80123456", "nationalNumberPattern": "80\\d{4,6}"}, "premiumRate": {"possibleLengths": {"national": "[5-8]"}, "exampleNumber": "90123456", "nationalNumberPattern": "89[1-3]\\d{2,5}|90\\d{4,6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "59012345", "nationalNumberPattern": "(?:59\\d\\d|8(?:1(?:[67]\\d|8[0-489])|2(?:0\\d|2[0-37-9]|8[0-2489])|3[389]\\d))\\d{4}"}}, {"leadingDigits": "79", "internationalPrefix": "00", "id": "SJ", "countryCode": "47", "generalDesc": {"nationalNumberPattern": "0\\d{4}|(?:[4589]\\d|79)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "79123456", "nationalNumberPattern": "79\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "41234567", "nationalNumberPattern": "(?:4[015-8]|5[89]|9\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80012345", "nationalNumberPattern": "80[01]\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "82012345", "nationalNumberPattern": "82[09]\\d{5}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "81021234", "nationalNumberPattern": "810(?:0[0-6]|[2-8]\\d)\\d{3}"}, "personalNumber": {"possibleLengths": {"national": "8"}, "exampleNumber": "88012345", "nationalNumberPattern": "880\\d{5}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "85012345", "nationalNumberPattern": "85[0-5]\\d{5}"}, "uan": {"possibleLengths": {"national": "5,8"}, "exampleNumber": "02000", "nationalNumberPattern": "(?:0[2-9]|81(?:0(?:0[7-9]|1\\d)|5\\d\\d))\\d{3}"}, "voicemail": {"possibleLengths": {"national": "8"}, "exampleNumber": "81212345", "nationalNumberPattern": "81[23]\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SK", "countryCode": "421", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{2})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "21", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["[3-5][1-8]1", "[3-5][1-8]1[67]"], "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["909", "9090"], "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d)(\\d{3})(\\d{3})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1/$2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[689]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3-5]", "format": "$1/$2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "[2-689]\\d{8}|[2-59]\\d{6}|[2-5]\\d{5}"}, "noInternationalDialling": {"possibleLengths": {"national": "7,9"}, "nationalNumberPattern": "9090\\d{3}|(?:602|8(?:00|[5-9]\\d)|9(?:00|[78]\\d))\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "6,7,9"}, "exampleNumber": "221234567", "nationalNumberPattern": "(?:2(?:16|[2-9]\\d{3})|(?:(?:[3-5][1-8]\\d|819)\\d|601[1-5])\\d)\\d{4}|(?:2|[3-5][1-8])1[67]\\d{3}|[3-5][1-8]16\\d\\d"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912123456", "nationalNumberPattern": "909[1-9]\\d{5}|9(?:0[1-8]|1[0-24-9]|4[03-57-9]|5\\d)\\d{6}"}, "pager": {"possibleLengths": {"national": "7"}, "exampleNumber": "9090123", "nationalNumberPattern": "9090\\d{3}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "9(?:00|[78]\\d)\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "850123456", "nationalNumberPattern": "8[5-9]\\d{7}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "690123456", "nationalNumberPattern": "6(?:02|5[0-4]|9[0-6])\\d{6}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "961234567", "nationalNumberPattern": "96\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SL", "countryCode": "232", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[236-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[2378]\\d|66|99)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "6"}, "exampleNumber": "22221234", "nationalNumberPattern": "22[2-4][2-9]\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "25123456", "nationalNumberPattern": "(?:25|3[013-5]|66|7[3-9]|8[08]|99)\\d{6}"}}, {"nationalPrefixForParsing": "([89]\\d{5})$", "internationalPrefix": "00", "id": "SM", "countryCode": "378", "nationalPrefixTransformRule": "0549$1", "availableFormats": {"numberFormat": [{"pattern": "(\\d{6})", "leadingDigits": "[89]", "format": "$1", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[5-7]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{4})(\\d{6})", "leadingDigits": "0", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:0549|[5-7]\\d)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "6"}, "exampleNumber": "0549886377", "nationalNumberPattern": "0549(?:8[0157-9]|9\\d)\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "66661212", "nationalNumberPattern": "6[16]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "71123456", "nationalNumberPattern": "7[178]\\d{6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "58001110", "nationalNumberPattern": "5[158]\\d{6}"}}, {"internationalPrefix": "00", "id": "SN", "countryCode": "221", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "8", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "leadingDigits": "[379]", "format": "$1 $2 $3 $4"}]}, "generalDesc": {"nationalNumberPattern": "(?:[378]\\d{4}|93330)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "301012345", "nationalNumberPattern": "3(?:0(?:1[0-2]|80)|282|3(?:8[1-9]|9[3-9])|611)\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "701234567", "nationalNumberPattern": "7(?:[06-8]\\d|21|5[4-7]|90)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "884123456", "nationalNumberPattern": "88[4689]\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "810123456", "nationalNumberPattern": "81[02468]\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "933301234", "nationalNumberPattern": "93330\\d{4}|3(?:392|9[01]\\d)\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SO", "countryCode": "252", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{4})", "leadingDigits": "8[125]", "format": "$1 $2"}, {"pattern": "(\\d{6})", "leadingDigits": "[134]", "format": "$1"}, {"pattern": "(\\d)(\\d{6})", "leadingDigits": "[15]|2[0-79]|3[0-46-8]|4[0-7]", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{7})", "leadingDigits": "24|[67]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[3478]|64|90", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{5,7})", "leadingDigits": "1|28|6[1-35-9]|9[2-9]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[346-9]\\d{8}|[12679]\\d{7}|[1-5]\\d{6}|[1348]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6,7"}, "exampleNumber": "4012345", "nationalNumberPattern": "(?:1\\d|2[0-79]|3[0-46-8]|4[0-7]|5[57-9])\\d{5}|(?:[134]\\d|8[125])\\d{4}"}, "mobile": {"possibleLengths": {"national": "[7-9]"}, "exampleNumber": "71123456", "nationalNumberPattern": "28\\d{5}|(?:6[1-9]|79)\\d{6,7}|(?:15|24|(?:3[59]|4[89]|8[08])\\d|60|7[1-8]|9(?:0\\d|[2-9]))\\d{6}"}}, {"internationalPrefix": "00", "id": "SR", "countryCode": "597", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "56", "format": "$1-$2-$3"}, {"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "[2-5]", "format": "$1-$2"}, {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[6-8]", "format": "$1-$2"}]}, "generalDesc": {"nationalNumberPattern": "(?:[2-5]|68|[78]\\d)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "6,7"}, "exampleNumber": "211234", "nationalNumberPattern": "(?:2[1-3]|3[0-7]|(?:4|68)\\d|5[2-58])\\d{4}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "7412345", "nationalNumberPattern": "(?:7[124-7]|8[124-9])\\d{5}"}, "voip": {"possibleLengths": {"national": "6"}, "exampleNumber": "561234", "nationalNumberPattern": "56\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SS", "countryCode": "211", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[19]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[19]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "181234567", "nationalNumberPattern": "1[89]\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "977123456", "nationalNumberPattern": "(?:12|9[12579])\\d{7}"}}, {"internationalPrefix": "00", "id": "ST", "countryCode": "239", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[29]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:22|9\\d)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2221234", "nationalNumberPattern": "22\\d{5}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "9812345", "nationalNumberPattern": "900[5-9]\\d{3}|9(?:0[1-9]|[89]\\d)\\d{4}"}}, {"internationalPrefix": "00", "id": "SV", "countryCode": "503", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[89]", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[267]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4})", "leadingDigits": "[89]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[267]\\d{7}|[89]00\\d{4}(?:\\d{4})?"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "2(?:[1-6]\\d{3}|[79]90[034]|890[0245])\\d{3}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "70123456", "nationalNumberPattern": "66(?:[02-9]\\d\\d|1(?:[02-9]\\d|16))\\d{3}|(?:6[0-57-9]|7\\d)\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7,11"}, "exampleNumber": "8001234", "nationalNumberPattern": "800\\d{4}(?:\\d{4})?"}, "premiumRate": {"possibleLengths": {"national": "7,11"}, "exampleNumber": "9001234", "nationalNumberPattern": "900\\d{4}(?:\\d{4})?"}}, {"nationalPrefixForParsing": "1|(5\\d{6})$", "countryCode": "1", "leadingDigits": "721", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "721$1", "internationalPrefix": "011", "id": "SX", "generalDesc": {"nationalNumberPattern": "7215\\d{6}|(?:[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7215425678", "nationalNumberPattern": "7215(?:4[2-8]|8[239]|9[056])\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7215205678", "nationalNumberPattern": "7215(?:1[02]|2\\d|5[034679]|8[014-8])\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002123456", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002123456", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "SY", "countryCode": "963", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-5]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[1-39]\\d{8}|[1-5]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8,9", "localOnly": "6,7"}, "exampleNumber": "112345678", "nationalNumberPattern": "21\\d{6,7}|(?:1(?:[14]\\d|[2356])|2[235]|3(?:[13]\\d|4)|4[134]|5[1-3])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "944567890", "nationalNumberPattern": "9(?:22|[3-589]\\d|6[02-9])\\d{6}"}}, {"internationalPrefix": "00", "id": "SZ", "countryCode": "268", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[0237]", "format": "$1 $2"}, {"pattern": "(\\d{5})(\\d{4})", "leadingDigits": "9", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "0800\\d{4}|(?:[237]\\d|900)\\d{6}"}, "noInternationalDialling": {"possibleLengths": {"national": "8"}, "nationalNumberPattern": "0800\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22171234", "nationalNumberPattern": "[23][2-5]\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "76123456", "nationalNumberPattern": "7[6-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "08001234", "nationalNumberPattern": "0800\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900012345", "nationalNumberPattern": "900\\d{6}"}, "voip": {"possibleLengths": {"national": "8"}, "exampleNumber": "70012345", "nationalNumberPattern": "70\\d{6}"}}, {"leadingDigits": "8", "internationalPrefix": "00", "id": "TA", "countryCode": "290", "generalDesc": {"nationalNumberPattern": "8\\d{3}"}, "fixedLine": {"possibleLengths": {"national": "4"}, "exampleNumber": "8999", "nationalNumberPattern": "8\\d{3}"}}, {"nationalPrefixForParsing": "1|([2-479]\\d{6})$", "countryCode": "1", "leadingDigits": "649", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "649$1", "internationalPrefix": "011", "id": "TC", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|649|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6497121234", "nationalNumberPattern": "649(?:266|712|9(?:4\\d|50))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6492311234", "nationalNumberPattern": "649(?:2(?:3[129]|4[1-79])|3\\d\\d|4[34][1-3])\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}, "voip": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "6497101234", "nationalNumberPattern": "649(?:71[01]|966)\\d{4}"}}, {"preferredInternationalPrefix": "00", "internationalPrefix": "00|16", "id": "TD", "countryCode": "235", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[2679]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "(?:22|[69]\\d|77)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22501234", "nationalNumberPattern": "22(?:[37-9]0|5[0-5]|6[89])\\d{4}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "63012345", "nationalNumberPattern": "(?:6[023568]|77|9\\d)\\d{6}"}}, {"internationalPrefix": "00", "id": "TG", "countryCode": "228", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[279]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "[279]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "22212345", "nationalNumberPattern": "2(?:2[2-7]|3[23]|4[45]|55|6[67]|77)\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "90112345", "nationalNumberPattern": "(?:7[09]|9[0-36-9])\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00[1-9]", "id": "TH", "countryCode": "66", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[13-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3})(\\d{3})", "leadingDigits": "1", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "1\\d{9}|[1689]\\d{8}|[1-57]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "21234567", "nationalNumberPattern": "(?:1[0689]|2\\d|3[2-9]|4[2-5]|5[2-6]|7[3-7])\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "812345678", "nationalNumberPattern": "671[0-3]\\d{5}|(?:14|6[1-6]|[89]\\d)\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "1800123456", "nationalNumberPattern": "1800\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "1900123456", "nationalNumberPattern": "1900\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "601234567", "nationalNumberPattern": "6[08]\\d{7}"}}, {"nationalPrefix": "8", "preferredInternationalPrefix": "8~10", "internationalPrefix": "810", "id": "TJ", "countryCode": "992", "availableFormats": {"numberFormat": [{"pattern": "(\\d{6})(\\d)(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": ["331", "3317"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{2})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "[34]7|91[78]", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d)(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "3", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "[02457-9]|11", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[02]0|11|[3-57-9]\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "3,[5-7]"}, "exampleNumber": "372123456", "nationalNumberPattern": "(?:3(?:1[3-5]|2[245]|3[12]|4[24-7]|5[25]|72)|4(?:46|74|87))\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "917123456", "nationalNumberPattern": "41[18]\\d{6}|(?:[024]0|11|5[05]|7[07]|8[08]|9\\d)\\d{7}"}}, {"internationalPrefix": "00", "id": "TK", "countryCode": "690", "generalDesc": {"nationalNumberPattern": "[2-47]\\d{3,6}"}, "fixedLine": {"possibleLengths": {"national": "[4-7]"}, "exampleNumber": "3101", "nationalNumberPattern": "(?:2[2-4]|[34]\\d)\\d{2,5}"}, "mobile": {"possibleLengths": {"national": "[4-7]"}, "exampleNumber": "7290", "nationalNumberPattern": "7[2-4]\\d{2,5}"}}, {"internationalPrefix": "00", "id": "TL", "countryCode": "670", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-489]|70", "format": "$1 $2"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "7", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "7\\d{7}|(?:[2-47]\\d|[89]0)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "7"}, "exampleNumber": "2112345", "nationalNumberPattern": "(?:2[1-5]|3[1-9]|4[1-4])\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "77212345", "nationalNumberPattern": "7[2-8]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8012345", "nationalNumberPattern": "80\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9012345", "nationalNumberPattern": "90\\d{5}"}, "personalNumber": {"possibleLengths": {"national": "7"}, "exampleNumber": "7012345", "nationalNumberPattern": "70\\d{5}"}}, {"nationalPrefix": "8", "preferredInternationalPrefix": "8~10", "internationalPrefix": "810", "id": "TM", "countryCode": "993", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{2})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "($NP $FG)", "leadingDigits": "12", "format": "$1 $2-$3-$4"}, {"pattern": "(\\d{3})(\\d)(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "($NP $FG)", "leadingDigits": "[1-5]", "format": "$1 $2-$3-$4"}, {"pattern": "(\\d{2})(\\d{6})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "6", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "[1-6]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "12345678", "nationalNumberPattern": "(?:1(?:2\\d|3[1-9])|2(?:22|4[0-35-8])|3(?:22|4[03-9])|4(?:22|3[128]|4\\d|6[15])|5(?:22|5[7-9]|6[014-689]))\\d{5}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "66123456", "nationalNumberPattern": "6\\d{7}"}}, {"internationalPrefix": "00", "id": "TN", "countryCode": "216", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "leadingDigits": "[2-57-9]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[2-57-9]\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "8"}, "exampleNumber": "30010123", "nationalNumberPattern": "81200\\d{3}|(?:3[0-2]|7\\d)\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "20123456", "nationalNumberPattern": "3(?:001|[12]40)\\d{4}|(?:(?:[259]\\d|4[0-7])\\d|3(?:1[1-35]|6[0-4]|91))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80101234", "nationalNumberPattern": "8010\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "88123456", "nationalNumberPattern": "88\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "81101234", "nationalNumberPattern": "8[12]10\\d{4}"}}, {"internationalPrefix": "00", "id": "TO", "countryCode": "676", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})", "leadingDigits": "[2-4]|50|6[09]|7[0-24-69]|8[05]", "format": "$1-$2"}, {"pattern": "(\\d{4})(\\d{3})", "leadingDigits": "0", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[5-8]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:0800|[5-8]\\d{3})\\d{3}|[2-8]\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "20123", "nationalNumberPattern": "(?:2\\d|3[0-8]|4[0-4]|50|6[09]|7[0-24-69]|8[05])\\d{3}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "7715123", "nationalNumberPattern": "6(?:3[02]|8[5-9])\\d{4}|(?:6[09]|7\\d|8[46-9])\\d{5}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "0800222", "nationalNumberPattern": "0800\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "5501234", "nationalNumberPattern": "55[04]\\d{4}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "TR", "countryCode": "90", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d)(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "444", "format": "$1 $2 $3", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "512|8[0589]|90", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["5(?:[0-59]|61)", "5(?:[0-59]|616)", "5(?:[0-59]|6161)"], "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": "[24][1-8]|3[1-9]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{6,7})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "80", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "4\\d{6}|8\\d{11,12}|(?:[2-58]\\d\\d|900)\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "7"}, "nationalNumberPattern": "444\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "10"}, "exampleNumber": "2123456789", "nationalNumberPattern": "(?:2(?:[13][26]|[28][2468]|[45][268]|[67][246])|3(?:[13][28]|[24-6][2468]|[78][02468]|92)|4(?:[16][246]|[23578][2468]|4[26]))\\d{7}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "5012345678", "nationalNumberPattern": "56161\\d{5}|5(?:0[15-7]|1[06]|24|[34]\\d|5[1-59]|9[46])\\d{7}"}, "pager": {"possibleLengths": {"national": "10"}, "exampleNumber": "5123456789", "nationalNumberPattern": "512\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10,12,13"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}(?:\\d{2,3})?"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9001234567", "nationalNumberPattern": "(?:8[89]8|900)\\d{7}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5922121234", "nationalNumberPattern": "592(?:21[12]|461)\\d{4}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "8500123456", "nationalNumberPattern": "850\\d{7}"}, "uan": {"possibleLengths": {"national": "7"}, "exampleNumber": "4441444", "nationalNumberPattern": "444\\d{4}"}}, {"nationalPrefixForParsing": "1|([2-46-8]\\d{6})$", "countryCode": "1", "leadingDigits": "868", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "868$1", "internationalPrefix": "011", "id": "TT", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8682211234", "nationalNumberPattern": "868(?:2(?:0[13]|1[89]|[23]\\d|4[0-2])|6(?:0[7-9]|1[02-8]|2[1-9]|[3-69]\\d|7[0-79])|82[124])\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8682911234", "nationalNumberPattern": "868(?:2(?:6[3-9]|[7-9]\\d)|(?:3\\d|4[6-9])\\d|6(?:20|78|8\\d)|7(?:0[1-9]|1[02-9]|[2-9]\\d))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}, "voicemail": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "8686191234", "nationalNumberPattern": "868619\\d{4}"}}, {"internationalPrefix": "00", "id": "TV", "countryCode": "688", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3})", "leadingDigits": "2", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{4})", "leadingDigits": "90", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{5})", "leadingDigits": "7", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:2|7\\d\\d|90)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "20123", "nationalNumberPattern": "2[02-9]\\d{3}"}, "mobile": {"possibleLengths": {"national": "6,7"}, "exampleNumber": "901234", "nationalNumberPattern": "(?:7[01]\\d|90)\\d{4}"}}, {"countryCode": "886", "mobileNumberPortableRegion": "true", "nationalPrefix": "0", "preferredExtnPrefix": "#", "internationalPrefix": "0(?:0[25-79]|19)", "id": "TW", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d)(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "202", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[258]0", "format": "$1 $2 $3"}, {"pattern": "(\\d)(\\d{3,4})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["[23568]|4(?:0[02-48]|[1-47-9])|7[1-9]", "[23568]|4(?:0[2-48]|[1-47-9])|(?:400|7)[1-9]"], "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[49]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[2-689]\\d{8}|7\\d{9,10}|[2-8]\\d{7}|2\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "221234567", "nationalNumberPattern": "(?:2[2-8]\\d|370|55[01]|7[1-9])\\d{6}|4(?:(?:0(?:0[1-9]|[2-48]\\d)|1[023]\\d)\\d{4,5}|(?:[239]\\d\\d|4(?:0[56]|12|49))\\d{5})|6(?:[01]\\d{7}|4(?:0[56]|12|24|4[09])\\d{4,5})|8(?:(?:2(?:3\\d|4[0-269]|[578]0|66)|36[24-9]|90\\d\\d)\\d{4}|4(?:0[56]|12|24|4[09])\\d{4,5})|(?:2(?:2(?:0\\d\\d|4(?:0[68]|[249]0|3[0-467]|5[0-25-9]|6[0235689]))|(?:3(?:[09]\\d|1[0-4])|(?:4\\d|5[0-49]|6[0-29]|7[0-5])\\d)\\d)|(?:(?:3[2-9]|5[2-8]|6[0-35-79]|8[7-9])\\d\\d|4(?:2(?:[089]\\d|7[1-9])|(?:3[0-4]|[78]\\d|9[01])\\d))\\d)\\d{3}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "(?:40001[0-2]|9[0-8]\\d{4})\\d{3}"}, "tollFree": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80[0-79]\\d{6}|800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "7,9"}, "exampleNumber": "203123456", "nationalNumberPattern": "20(?:[013-9]\\d\\d|2)\\d{4}"}, "personalNumber": {"possibleLengths": {"national": "9"}, "exampleNumber": "990123456", "nationalNumberPattern": "99\\d{7}"}, "voip": {"possibleLengths": {"national": "10,11"}, "exampleNumber": "7012345678", "nationalNumberPattern": "7010(?:[0-2679]\\d|3[0-7]|8[0-5])\\d{5}|70\\d{8}"}, "uan": {"possibleLengths": {"national": "9"}, "exampleNumber": "500123456", "nationalNumberPattern": "50[0-46-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00[056]", "id": "TZ", "countryCode": "255", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{2})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[24]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[67]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:[26-8]\\d|41|90)\\d{7}"}, "noInternationalDialling": {"possibleLengths": {"national": "9"}, "nationalNumberPattern": "(?:8(?:[04]0|6[01])|90\\d)\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "222345678", "nationalNumberPattern": "2[2-8]\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "621234567", "nationalNumberPattern": "77[2-9]\\d{6}|(?:6[1-9]|7[1-689])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80[08]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "900123456", "nationalNumberPattern": "90\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "840123456", "nationalNumberPattern": "8(?:40|6[01])\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "412345678", "nationalNumberPattern": "41\\d{7}"}}, {"nationalPrefix": "0", "preferredInternationalPrefix": "0~0", "internationalPrefix": "00", "id": "UA", "countryCode": "380", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["6[12][29]|(?:3[1-8]|4[136-8]|5[12457]|6[49])2|(?:56|65)[24]", "6[12][29]|(?:35|4[1378]|5[12457]|6[49])2|(?:56|65)[24]|(?:3[1-46-8]|46)2[013-9]"], "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["4[45][0-5]|5(?:0|6[37])|6(?:[12][018]|[36-8])|7|89|9[1-9]|(?:48|57)[0137-9]", "4[45][0-5]|5(?:0|6(?:3[14-7]|7))|6(?:[12][018]|[36-8])|7|89|9[1-9]|(?:48|57)[0137-9]"], "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3-6]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[89]\\d{9}|[3-9]\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "[5-7]"}, "exampleNumber": "311234567", "nationalNumberPattern": "(?:3[1-8]|4[13-8]|5[1-7]|6[12459])\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "501234567", "nationalNumberPattern": "(?:50|6[36-8]|7[1-3]|9[1-9])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "800123456", "nationalNumberPattern": "800[1-8]\\d{5,6}"}, "premiumRate": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "900212345", "nationalNumberPattern": "900[239]\\d{5,6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "891234567", "nationalNumberPattern": "89[1-579]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00[057]", "id": "UG", "countryCode": "256", "availableFormats": {"numberFormat": [{"pattern": "(\\d{4})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["202", "2024"], "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[27-9]|4(?:6[45]|[7-9])", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[34]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "800\\d{6}|(?:[29]0|[347]\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "[5-7]"}, "exampleNumber": "312345678", "nationalNumberPattern": "20(?:(?:(?:24|81)0|30[67])\\d|6(?:00[0-2]|30[0-4]))\\d{3}|(?:20(?:[0147]\\d|2[5-9]|32|5[0-4]|6[15-9])|[34]\\d{3})\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "712345678", "nationalNumberPattern": "7260\\d{5}|7(?:[0157-9]\\d|20|36|4[0-4])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800[1-3]\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "901123456", "nationalNumberPattern": "90[1-3]\\d{6}"}}, {"mainCountryForCode": "true", "countryCode": "1", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "internationalPrefix": "011", "id": "US", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[2-9]", "format": "$1-$2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "[2-9]", "format": "($1) $2-$3", "intlFormat": "$1-$2-$3"}]}, "generalDesc": {"nationalNumberPattern": "[2-9]\\d{9}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2015550123", "nationalNumberPattern": "(?:2(?:0[1-35-9]|1[02-9]|2[03-589]|3[149]|4[08]|5[1-46]|6[0279]|7[0269]|8[13])|3(?:0[1-57-9]|1[02-9]|2[01356]|3[0-24679]|4[167]|5[12]|6[014]|8[056])|4(?:0[124-9]|1[02-579]|2[3-5]|3[0245]|4[0235]|58|6[39]|7[0589]|8[04])|5(?:0[1-57-9]|1[0235-8]|20|3[0149]|4[01]|5[19]|6[1-47]|7[013-5]|8[056])|6(?:0[1-35-9]|1[024-9]|2[03689]|[34][016]|5[0179]|6[0-279]|78|8[0-29])|7(?:0[1-46-8]|1[2-9]|2[04-7]|3[1247]|4[037]|5[47]|6[02359]|7[02-59]|8[156])|8(?:0[1-68]|1[02-8]|2[08]|3[0-289]|4[3578]|5[046-9]|6[02-5]|7[028])|9(?:0[1346-9]|1[02-9]|2[0589]|3[0146-8]|4[0179]|5[12469]|7[0-389]|8[04-69]))[2-9]\\d{6}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2015550123", "nationalNumberPattern": "(?:2(?:0[1-35-9]|1[02-9]|2[03-589]|3[149]|4[08]|5[1-46]|6[0279]|7[0269]|8[13])|3(?:0[1-57-9]|1[02-9]|2[01356]|3[0-24679]|4[167]|5[12]|6[014]|8[056])|4(?:0[124-9]|1[02-579]|2[3-5]|3[0245]|4[0235]|58|6[39]|7[0589]|8[04])|5(?:0[1-57-9]|1[0235-8]|20|3[0149]|4[01]|5[19]|6[1-47]|7[013-5]|8[056])|6(?:0[1-35-9]|1[024-9]|2[03689]|[34][016]|5[0179]|6[0-279]|78|8[0-29])|7(?:0[1-46-8]|1[2-9]|2[04-7]|3[1247]|4[037]|5[47]|6[02359]|7[02-59]|8[156])|8(?:0[1-68]|1[02-8]|2[08]|3[0-289]|4[3578]|5[046-9]|6[02-5]|7[028])|9(?:0[1346-9]|1[02-9]|2[0589]|3[0146-8]|4[0179]|5[12469]|7[0-389]|8[04-69]))[2-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"countryCode": "598", "nationalPrefix": "0", "preferredInternationalPrefix": "00", "preferredExtnPrefix": " int. ", "internationalPrefix": "0(?:0|1[3-9]\\d)", "id": "UY", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "405|8|90", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "9", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[24]", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "4", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "4\\d{9}|[249]\\d{7}|(?:[49]\\d|80)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8", "localOnly": "7"}, "exampleNumber": "21231234", "nationalNumberPattern": "(?:2\\d|4[2-7])\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "94231234", "nationalNumberPattern": "9[1-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "8001234", "nationalNumberPattern": "(?:4\\d{5}|80[05])\\d{4}|405\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "7"}, "exampleNumber": "9001234", "nationalNumberPattern": "90[0-8]\\d{4}"}}, {"nationalPrefix": "8", "preferredInternationalPrefix": "8~10", "internationalPrefix": "810", "id": "UZ", "countryCode": "998", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixFormattingRule": "$NP $FG", "leadingDigits": "[35-9]", "format": "$1 $2 $3 $4"}}, "generalDesc": {"nationalNumberPattern": "55501\\d{4}|(?:33|[679]\\d|88)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "669050123", "nationalNumberPattern": "(?:6(?:1(?:22|3[124]|4[1-4]|5[1-3578]|64)|2(?:22|3[0-57-9]|41)|5(?:22|3[3-7]|5[024-8])|6\\d\\d|7(?:[23]\\d|7[69])|9(?:22|4[1-8]|6[135]))|7(?:0(?:5[4-9]|6[0146]|7[124-6]|9[135-8])|(?:1[12]|8\\d)\\d|2(?:22|3[13-57-9]|4[1-3579]|5[14])|3(?:2\\d|3[1578]|4[1-35-7]|5[1-57]|61)|4(?:2\\d|3[1-579]|7[1-79])|5(?:22|5[1-9]|6[1457])|6(?:22|3[12457]|4[13-8])|9(?:22|5[1-9])))\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "(?:(?:33|88|9[0-57-9])\\d{3}|55501|6(?:1(?:2(?:2[01]|98)|35[0-4]|50\\d|61[23]|7(?:[01][017]|4\\d|55|9[5-9]))|2(?:(?:11|7\\d)\\d|2(?:[12]1|9[01379])|5(?:[126]\\d|3[0-4]))|5(?:19[01]|2(?:27|9[26])|(?:30|59|7\\d)\\d)|6(?:2(?:1[5-9]|2[0367]|38|41|52|60)|(?:3[79]|9[0-3])\\d|4(?:56|83)|7(?:[07]\\d|1[017]|3[07]|4[047]|5[057]|67|8[0178]|9[79]))|7(?:2(?:24|3[237]|4[5-9]|7[15-8])|5(?:7[12]|8[0589])|7(?:0\\d|[39][07])|9(?:0\\d|7[079]))|9(?:2(?:1[1267]|3[01]|5\\d|7[0-4])|(?:5[67]|7\\d)\\d|6(?:2[0-26]|8\\d)))|7(?:[07]\\d{3}|1(?:13[01]|6(?:0[47]|1[67]|66)|71[3-69]|98\\d)|2(?:2(?:2[79]|95)|3(?:2[5-9]|6[0-6])|57\\d|7(?:0\\d|1[17]|2[27]|3[37]|44|5[057]|66|88))|3(?:2(?:1[0-6]|21|3[469]|7[159])|(?:33|9[4-6])\\d|5(?:0[0-4]|5[579]|9\\d)|7(?:[0-3579]\\d|4[0467]|6[67]|8[078]))|4(?:2(?:29|5[0257]|6[0-7]|7[1-57])|5(?:1[0-4]|8\\d|9[5-9])|7(?:0\\d|1[024589]|2[0-27]|3[0137]|[46][07]|5[01]|7[5-9]|9[079])|9(?:7[015-9]|[89]\\d))|5(?:112|2(?:0\\d|2[29]|[49]4)|3[1568]\\d|52[6-9]|7(?:0[01578]|1[017]|[23]7|4[047]|[5-7]\\d|8[78]|9[079]))|6(?:2(?:2[1245]|4[2-4])|39\\d|41[179]|5(?:[349]\\d|5[0-2])|7(?:0[017]|[13]\\d|22|44|55|67|88))|9(?:22[128]|3(?:2[0-4]|7\\d)|57[02569]|7(?:2[05-9]|3[37]|4\\d|60|7[2579]|87|9[07]))))\\d{4}"}}, {"leadingDigits": "06698", "internationalPrefix": "00", "id": "VA", "countryCode": "39", "mobileNumberPortableRegion": "true", "generalDesc": {"nationalNumberPattern": "0\\d{5,10}|3[0-8]\\d{7,10}|55\\d{8}|8\\d{5}(?:\\d{2,4})?|(?:1\\d|39)\\d{7,8}"}, "fixedLine": {"possibleLengths": {"national": "[6-11]"}, "exampleNumber": "0669812345", "nationalNumberPattern": "06698\\d{1,6}"}, "mobile": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "3123456789", "nationalNumberPattern": "3[1-9]\\d{8}|3[2-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "6,9"}, "exampleNumber": "800123456", "nationalNumberPattern": "80(?:0\\d{3}|3)\\d{3}"}, "premiumRate": {"possibleLengths": {"national": "6,[8-10]"}, "exampleNumber": "899123456", "nationalNumberPattern": "(?:0878\\d\\d|89(?:2|4[5-9]\\d))\\d{3}|89[45][0-4]\\d\\d|(?:1(?:44|6[346])|89(?:5[5-9]|9))\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "6,9"}, "exampleNumber": "848123456", "nationalNumberPattern": "84(?:[08]\\d{3}|[17])\\d{3}"}, "personalNumber": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "1781234567", "nationalNumberPattern": "1(?:78\\d|99)\\d{6}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "5512345678", "nationalNumberPattern": "55\\d{8}"}, "voicemail": {"possibleLengths": {"national": "11,12"}, "exampleNumber": "33101234501", "nationalNumberPattern": "3[2-8]\\d{9,10}"}}, {"nationalPrefixForParsing": "1|([2-7]\\d{6})$", "countryCode": "1", "leadingDigits": "784", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "784$1", "internationalPrefix": "011", "id": "VC", "generalDesc": {"nationalNumberPattern": "(?:[58]\\d\\d|784|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7842661234", "nationalNumberPattern": "784(?:266|3(?:6[6-9]|7\\d|8[0-6])|4(?:38|5[0-36-8]|8[0-8])|5(?:55|7[0-2]|93)|638|784)\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "7844301234", "nationalNumberPattern": "784(?:4(?:3[0-5]|5[45]|89|9[0-8])|5(?:2[6-9]|3[0-4])|720)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "VE", "countryCode": "58", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{7})", "carrierCodeFormattingRule": "$CC $FG", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[24-689]", "format": "$1-$2"}}, "generalDesc": {"nationalNumberPattern": "[68]00\\d{7}|(?:[24]\\d|[59]0)\\d{8}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2121234567", "nationalNumberPattern": "(?:2(?:12|3[457-9]|[467]\\d|[58][1-9]|9[1-6])|[4-6]00)\\d{7}"}, "mobile": {"possibleLengths": {"national": "10"}, "exampleNumber": "4121234567", "nationalNumberPattern": "4(?:1[24-8]|2[46])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8001234567", "nationalNumberPattern": "800\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9001234567", "nationalNumberPattern": "90[01]\\d{7}"}, "uan": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "5010123456", "nationalNumberPattern": "501\\d{7}"}}, {"nationalPrefixForParsing": "1|([2-578]\\d{6})$", "countryCode": "1", "leadingDigits": "284", "mobileNumberPortableRegion": "true", "nationalPrefix": "1", "nationalPrefixTransformRule": "284$1", "internationalPrefix": "011", "id": "VG", "generalDesc": {"nationalNumberPattern": "(?:284|[58]\\d\\d|900)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2842291234", "nationalNumberPattern": "284496[0-5]\\d{3}|284(?:229|4(?:22|9[45])|774|8(?:52|6[459]))\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "2843001234", "nationalNumberPattern": "284496[6-9]\\d{3}|284(?:245|3(?:0[0-3]|4[0-7]|68|9[34])|4(?:4[0-6]|68|99)|5(?:4[0-7]|68|9[69]))\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefixForParsing": "1|([2-9]\\d{6})$", "countryCode": "1", "leadingDigits": "340", "nationalPrefix": "1", "nationalPrefixTransformRule": "340$1", "internationalPrefix": "011", "id": "VI", "generalDesc": {"nationalNumberPattern": "[58]\\d{9}|(?:34|90)0\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "3406421234", "nationalNumberPattern": "340(?:2(?:0[12]|2[06-8]|4[49]|77)|3(?:32|44)|4(?:2[23]|44|7[34]|89)|5(?:1[34]|55)|6(?:2[56]|4[23]|77|9[023])|7(?:1[2-57-9]|2[57]|7\\d)|884|998)\\d{4}"}, "mobile": {"possibleLengths": {"national": "10", "localOnly": "7"}, "exampleNumber": "3406421234", "nationalNumberPattern": "340(?:2(?:0[12]|2[06-8]|4[49]|77)|3(?:32|44)|4(?:2[23]|44|7[34]|89)|5(?:1[34]|55)|6(?:2[56]|4[23]|77|9[023])|7(?:1[2-57-9]|2[57]|7\\d)|884|998)\\d{4}"}, "tollFree": {"possibleLengths": {"national": "10"}, "exampleNumber": "8002345678", "nationalNumberPattern": "8(?:00|33|44|55|66|77|88)[2-9]\\d{6}"}, "premiumRate": {"possibleLengths": {"national": "10"}, "exampleNumber": "9002345678", "nationalNumberPattern": "900[2-9]\\d{6}"}, "personalNumber": {"possibleLengths": {"national": "10"}, "exampleNumber": "5002345678", "nationalNumberPattern": "52(?:3(?:[2-46-9][02-9]\\d|5(?:[02-46-9]\\d|5[0-46-9]))|4(?:[2-478][02-9]\\d|5(?:[034]\\d|2[024-9]|5[0-46-9])|6(?:0[1-9]|[2-9]\\d)|9(?:[05-9]\\d|2[0-5]|49)))\\d{4}|52[34][2-9]1[02-9]\\d{4}|5(?:00|2[12]|33|44|66|77|88)[2-9]\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "VN", "countryCode": "84", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[17]99", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{2})(\\d{5})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "80", "format": "$1 $2"}, {"pattern": "(\\d{3})(\\d{4,5})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "69", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{4})(\\d{4,6})", "nationalPrefixOptionalWhenFormatting": "true", "leadingDigits": "1", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2})(\\d{2})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[69]", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[3578]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2[48]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{3})", "nationalPrefixOptionalWhenFormatting": "true", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[12]\\d{9}|[135-9]\\d{8}|[16]\\d{7}|[16-8]\\d{6}"}, "noInternationalDialling": {"possibleLengths": {"national": "7,8"}, "nationalNumberPattern": "[17]99\\d{4}|69\\d{5,6}"}, "fixedLine": {"possibleLengths": {"national": "10"}, "exampleNumber": "2101234567", "nationalNumberPattern": "2(?:0[3-9]|1[0-689]|2[0-25-9]|3[2-9]|4[2-8]|5[124-9]|6[0-39]|7[0-7]|8[2-79]|9[0-4679])\\d{7}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "912345678", "nationalNumberPattern": "(?:5(?:2[238]|59)|89[689]|99[013-9])\\d{6}|(?:3\\d|5[689]|7[06-9]|8[1-8]|9[0-8])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "[8-10]"}, "exampleNumber": "1800123456", "nationalNumberPattern": "1800\\d{4,6}|12(?:0[13]|28)\\d{4}"}, "premiumRate": {"possibleLengths": {"national": "[8-10]"}, "exampleNumber": "1900123456", "nationalNumberPattern": "1900\\d{4,6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "672012345", "nationalNumberPattern": "672\\d{6}"}, "uan": {"possibleLengths": {"national": "7,8"}, "exampleNumber": "1992000", "nationalNumberPattern": "(?:[17]99|80\\d)\\d{4}|69\\d{5,6}"}}, {"internationalPrefix": "00", "id": "VU", "countryCode": "678", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{4})", "leadingDigits": "[579]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "(?:[23]\\d|[48]8)\\d{3}|(?:[57]\\d|90)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "5"}, "exampleNumber": "22123", "nationalNumberPattern": "(?:38[0-8]|48[4-9])\\d\\d|(?:2[02-9]|3[4-7]|88)\\d{3}"}, "mobile": {"possibleLengths": {"national": "7"}, "exampleNumber": "5912345", "nationalNumberPattern": "(?:5\\d|7[013-7])\\d{5}"}, "voip": {"possibleLengths": {"national": "7"}, "exampleNumber": "9010123", "nationalNumberPattern": "90[1-9]\\d{4}"}, "uan": {"possibleLengths": {"national": "5,7"}, "exampleNumber": "30123", "nationalNumberPattern": "(?:3[03]|900\\d)\\d{3}"}}, {"internationalPrefix": "00", "id": "WF", "countryCode": "681", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{2})(\\d{2})", "leadingDigits": "[4-8]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "(?:[45]0|68|72|8\\d)\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "6"}, "exampleNumber": "501234", "nationalNumberPattern": "(?:50|68|72)\\d{4}"}, "mobile": {"possibleLengths": {"national": "6"}, "exampleNumber": "501234", "nationalNumberPattern": "(?:50|68|72|8[23])\\d{4}"}, "voicemail": {"possibleLengths": {"national": "6"}, "exampleNumber": "401234", "nationalNumberPattern": "[48]0\\d{4}"}}, {"internationalPrefix": "0", "id": "WS", "countryCode": "685", "availableFormats": {"numberFormat": [{"pattern": "(\\d{5})", "leadingDigits": "[2-5]|6[1-9]", "format": "$1"}, {"pattern": "(\\d{3})(\\d{3,7})", "leadingDigits": "[68]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{5})", "leadingDigits": "7", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:[2-6]|8\\d{5})\\d{4}|[78]\\d{6}|[68]\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "5,6"}, "exampleNumber": "22123", "nationalNumberPattern": "6[1-9]\\d{3}|(?:[2-5]|60)\\d{4}"}, "mobile": {"possibleLengths": {"national": "7,10"}, "exampleNumber": "7212345", "nationalNumberPattern": "(?:7[1-35-7]|8(?:[3-7]|9\\d{3}))\\d{5}"}, "tollFree": {"possibleLengths": {"national": "6"}, "exampleNumber": "800123", "nationalNumberPattern": "800\\d{3}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "XK", "countryCode": "383", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[89]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[2-4]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[23]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[23]\\d{7,8}|(?:4\\d\\d|[89]00)\\d{5}"}, "fixedLine": {"possibleLengths": {"national": "8,9"}, "exampleNumber": "28012345", "nationalNumberPattern": "(?:2[89]|39)0\\d{6}|[23][89]\\d{6}"}, "mobile": {"possibleLengths": {"national": "8"}, "exampleNumber": "43201234", "nationalNumberPattern": "4[3-9]\\d{6}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "80001234", "nationalNumberPattern": "800\\d{5}"}, "premiumRate": {"possibleLengths": {"national": "8"}, "exampleNumber": "90001234", "nationalNumberPattern": "900\\d{5}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "YE", "countryCode": "967", "availableFormats": {"numberFormat": [{"pattern": "(\\d)(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-6]|7[24-68]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "(?:1|7\\d)\\d{7}|[1-7]\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "7,8", "localOnly": "6"}, "exampleNumber": "1234567", "nationalNumberPattern": "78[0-7]\\d{4}|17\\d{6}|(?:[12][2-68]|3[2358]|4[2-58]|5[2-6]|6[3-58]|7[24-6])\\d{5}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "712345678", "nationalNumberPattern": "7[0137]\\d{7}"}}, {"nationalPrefix": "0", "leadingDigits": "269|63", "internationalPrefix": "00", "id": "YT", "countryCode": "262", "generalDesc": {"nationalNumberPattern": "80\\d{7}|(?:26|63)9\\d{6}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "269601234", "nationalNumberPattern": "269(?:0[67]|5[0-2]|6\\d|[78]0)\\d{4}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "639012345", "nationalNumberPattern": "639(?:0[0-79]|1[019]|[267]\\d|3[09]|[45]0|9[04-79])\\d{4}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "80\\d{7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "ZA", "countryCode": "27", "mobileNumberPortableRegion": "true", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8[1-4]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{2,3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8[1-4]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "860", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[1-9]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[1-79]\\d{8}|8\\d{4,9}"}, "fixedLine": {"possibleLengths": {"national": "9"}, "exampleNumber": "101234567", "nationalNumberPattern": "(?:2(?:0330|4302)|52087)0\\d{3}|(?:1[0-8]|2[1-378]|3[1-69]|4\\d|5[1346-8])\\d{7}"}, "mobile": {"possibleLengths": {"national": "[5-9]"}, "exampleNumber": "711234567", "nationalNumberPattern": "(?:1(?:3492[0-25]|4495[0235]|549(?:20|5[01]))|4[34]492[01])\\d{3}|8[1-4]\\d{3,7}|(?:2[27]|47|54)4950\\d{3}|(?:1(?:049[2-4]|9[12]\\d\\d)|(?:6\\d|7[0-46-9])\\d{3}|8(?:5\\d{3}|7(?:08[67]|158|28[5-9]|310)))\\d{4}|(?:1[6-8]|28|3[2-69]|4[025689]|5[36-8])4920\\d{3}|(?:12|[2-5]1)492\\d{4}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "801234567", "nationalNumberPattern": "80\\d{7}"}, "premiumRate": {"possibleLengths": {"national": "9"}, "exampleNumber": "862345678", "nationalNumberPattern": "(?:86[2-9]|9[0-2]\\d)\\d{6}"}, "sharedCost": {"possibleLengths": {"national": "9"}, "exampleNumber": "860123456", "nationalNumberPattern": "860\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "871234567", "nationalNumberPattern": "87(?:08[0-589]|15[0-79]|28[0-4]|31[1-9])\\d{4}|87(?:[02][0-79]|1[0-46-9]|3[02-9]|[4-9]\\d)\\d{5}"}, "uan": {"possibleLengths": {"national": "9,10"}, "exampleNumber": "861123456", "nationalNumberPattern": "861\\d{6,7}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "ZM", "countryCode": "260", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})", "leadingDigits": "[1-9]", "format": "$1 $2", "intlFormat": "NA"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[28]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[79]", "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "(?:63|80)0\\d{6}|(?:21|[79]\\d)\\d{7}"}, "fixedLine": {"possibleLengths": {"national": "9", "localOnly": "6"}, "exampleNumber": "211234567", "nationalNumberPattern": "21[1-8]\\d{6}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "955123456", "nationalNumberPattern": "(?:7[679]|9[5-8])\\d{7}"}, "tollFree": {"possibleLengths": {"national": "9"}, "exampleNumber": "800123456", "nationalNumberPattern": "800\\d{6}"}, "voip": {"possibleLengths": {"national": "9"}, "exampleNumber": "630012345", "nationalNumberPattern": "630\\d{6}"}}, {"nationalPrefix": "0", "internationalPrefix": "00", "id": "ZW", "countryCode": "263", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "2(?:0[45]|2[278]|[49]8)|3(?:[09]8|17)|6(?:[29]8|37|75)|[23][78]|(?:33|5[15]|6[68])[78]", "format": "$1 $2"}, {"pattern": "(\\d)(\\d{3})(\\d{2,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "[49]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "80", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{7})", "nationalPrefixFormattingRule": "($NP$FG)", "leadingDigits": ["24|8[13-59]|(?:2[05-79]|39|5[45]|6[15-8])2", "2(?:02[014]|4|[56]20|[79]2)|392|5(?:42|525)|6(?:[16-8]21|52[013])|8[13-59]"], "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "7", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["2(?:1[39]|2[0157]|[378]|[56][14])|3(?:12|29)", "2(?:1[39]|2[0157]|[378]|[56][14])|3(?:123|29)"], "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{6})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "8", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "1|2(?:0[0-36-9]|12|29|[56])|3(?:1[0-689]|[24-6])|5(?:[0236-9]|1[2-4])|6(?:[013-59]|7[0-46-9])|(?:33|55|6[68])[0-69]|(?:29|3[09]|62)[0-79]", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{3})(\\d{3,4})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": "29[013-9]|39|54", "format": "$1 $2 $3"}, {"pattern": "(\\d{4})(\\d{3,5})", "nationalPrefixFormattingRule": "$NP$FG", "leadingDigits": ["(?:25|54)8", "258|5483"], "format": "$1 $2"}]}, "generalDesc": {"nationalNumberPattern": "2(?:[0-57-9]\\d{6,8}|6[0-24-9]\\d{6,7})|[38]\\d{9}|[35-8]\\d{8}|[3-6]\\d{7}|[1-689]\\d{6}|[1-3569]\\d{5}|[1356]\\d{4}"}, "fixedLine": {"possibleLengths": {"national": "[5-10]", "localOnly": "3,4"}, "exampleNumber": "1312345", "nationalNumberPattern": "(?:1(?:(?:3\\d|9)\\d|[4-8])|2(?:(?:(?:0(?:2[014]|5)|(?:2[0157]|31|84|9)\\d\\d|[56](?:[14]\\d\\d|20)|7(?:[089]|2[03]|[35]\\d\\d))\\d|4(?:2\\d\\d|8))\\d|1(?:2|[39]\\d{4}))|3(?:(?:123|(?:29\\d|92)\\d)\\d\\d|7(?:[19]|[56]\\d))|5(?:0|1[2-478]|26|[37]2|4(?:2\\d{3}|83)|5(?:25\\d\\d|[78])|[689]\\d)|6(?:(?:[16-8]21|28|52[013])\\d\\d|[39])|8(?:[1349]28|523)\\d\\d)\\d{3}|(?:4\\d\\d|9[2-9])\\d{4,5}|(?:(?:2(?:(?:(?:0|8[146])\\d|7[1-7])\\d|2(?:[278]\\d|92)|58(?:2\\d|3))|3(?:[26]|9\\d{3})|5(?:4\\d|5)\\d\\d)\\d|6(?:(?:(?:[0-246]|[78]\\d)\\d|37)\\d|5[2-8]))\\d\\d|(?:2(?:[569]\\d|8[2-57-9])|3(?:[013-59]\\d|8[37])|6[89]8)\\d{3}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "712345678", "nationalNumberPattern": "7(?:[17]\\d|[38][1-9])\\d{6}"}, "tollFree": {"possibleLengths": {"national": "7"}, "exampleNumber": "8001234", "nationalNumberPattern": "80(?:[01]\\d|20|8[0-8])\\d{3}"}, "voip": {"possibleLengths": {"national": "10"}, "exampleNumber": "8686123456", "nationalNumberPattern": "86(?:1[12]|22|30|44|55|77|8[368])\\d{6}"}}, {"id": "001", "countryCode": "800", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[1-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "[1-9]\\d{7}"}, "tollFree": {"possibleLengths": {"national": "8"}, "exampleNumber": "12345678", "nationalNumberPattern": "[1-9]\\d{7}"}}, {"id": "001", "countryCode": "808", "availableFormats": {"numberFormat": {"pattern": "(\\d{4})(\\d{4})", "leadingDigits": "[1-9]", "format": "$1 $2"}}, "generalDesc": {"nationalNumberPattern": "[1-9]\\d{7}"}, "sharedCost": {"possibleLengths": {"national": "8"}, "exampleNumber": "12345678", "nationalNumberPattern": "[1-9]\\d{7}"}}, {"id": "001", "countryCode": "870", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "[35-7]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "7\\d{11}|[35-7]\\d{8}"}, "mobile": {"possibleLengths": {"national": "9,12"}, "exampleNumber": "301234567", "nationalNumberPattern": "(?:[356]|774[45])\\d{8}|7[6-8]\\d{7}"}}, {"id": "001", "countryCode": "878", "availableFormats": {"numberFormat": {"pattern": "(\\d{2})(\\d{5})(\\d{5})", "leadingDigits": "1", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "10\\d{10}"}, "voip": {"possibleLengths": {"national": "12"}, "exampleNumber": "101234567890", "nationalNumberPattern": "10\\d{10}"}}, {"id": "001", "countryCode": "881", "availableFormats": {"numberFormat": {"pattern": "(\\d)(\\d{3})(\\d{5})", "leadingDigits": "[0-36-9]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[0-36-9]\\d{8}"}, "mobile": {"possibleLengths": {"national": "9"}, "exampleNumber": "612345678", "nationalNumberPattern": "[0-36-9]\\d{8}"}}, {"id": "001", "countryCode": "882", "availableFormats": {"numberFormat": [{"pattern": "(\\d{2})(\\d{5})", "leadingDigits": "16|342", "format": "$1 $2"}, {"pattern": "(\\d{2})(\\d{2})(\\d{4})", "leadingDigits": "[19]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{3})", "leadingDigits": "3[23]", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{3,4})(\\d{4})", "leadingDigits": "1", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4})(\\d{4})", "leadingDigits": "34[57]", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{4})(\\d{4})", "leadingDigits": "34", "format": "$1 $2 $3"}, {"pattern": "(\\d{2})(\\d{4,5})(\\d{5})", "leadingDigits": "[1-3]", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "[13]\\d{6}(?:\\d{2,5})?|285\\d{9}|[19]\\d{7}"}, "mobile": {"possibleLengths": {"national": "7,9,10,12"}, "exampleNumber": "3421234", "nationalNumberPattern": "3(?:37\\d\\d|42)\\d{4}|3(?:2|47|7\\d{3})\\d{7}"}, "voip": {"possibleLengths": {"national": "[7-12]"}, "exampleNumber": "390123456789", "nationalNumberPattern": "1(?:3(?:0[0347]|[13][0139]|2[035]|4[013568]|6[0459]|7[06]|8[15-8]|9[0689])\\d{4}|6\\d{5,10})|(?:(?:285\\d\\d|3(?:45|[69]\\d{3}))\\d|9[89])\\d{6}"}, "voicemail": {"possibleLengths": {"national": "11"}, "exampleNumber": "34851234567", "nationalNumberPattern": "348[57]\\d{7}"}}, {"id": "001", "countryCode": "883", "availableFormats": {"numberFormat": [{"pattern": "(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "510", "format": "$1 $2 $3"}, {"pattern": "(\\d{3})(\\d{3})(\\d{3})(\\d{3})", "leadingDigits": "510", "format": "$1 $2 $3 $4"}, {"pattern": "(\\d{4})(\\d{4})(\\d{4})", "leadingDigits": "5", "format": "$1 $2 $3"}]}, "generalDesc": {"nationalNumberPattern": "51\\d{7}(?:\\d{3})?"}, "voip": {"possibleLengths": {"national": "9,12"}, "exampleNumber": "510012345", "nationalNumberPattern": "51[013]0\\d{8}|5100\\d{5}"}}, {"id": "001", "countryCode": "888", "availableFormats": {"numberFormat": {"pattern": "(\\d{3})(\\d{3})(\\d{5})", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "\\d{11}"}, "uan": {"possibleLengths": {"national": "11"}, "exampleNumber": "12345678901", "nationalNumberPattern": "\\d{11}"}}, {"id": "001", "countryCode": "979", "availableFormats": {"numberFormat": {"pattern": "(\\d)(\\d{4})(\\d{4})", "leadingDigits": "[1359]", "format": "$1 $2 $3"}}, "generalDesc": {"nationalNumberPattern": "[1359]\\d{8}"}, "premiumRate": {"possibleLengths": {"national": "9", "localOnly": "8"}, "exampleNumber": "123456789", "nationalNumberPattern": "[1359]\\d{8}"}}]} }} diff --git a/AddameSPM/Sources/AuthenticationView/TermsAndPrivacyWebView.swift b/AddameSPM/Sources/AuthenticationView/TermsAndPrivacyWebView.swift new file mode 100644 index 0000000..caf6d7e --- /dev/null +++ b/AddameSPM/Sources/AuthenticationView/TermsAndPrivacyWebView.swift @@ -0,0 +1,87 @@ +// +// TermsAndPrivacyWebView.swift +// AddaMeIOS +// +// Created by Saroar Khandoker on 07.12.2020. +// + +import SwiftUI +import ComposableArchitecture + +public struct TermsAndPrivacyState: Equatable { + public init( + urlString: String? = nil + ) { + self.urlString = urlString + } + + public var urlString: String? +} + +public enum TermsAndPrivacyAction: Equatable { + case terms + case privacy +} + +public struct TermsAndPrivacyEnvironment { + public init() {} +} + +extension TermsAndPrivacyEnvironment { + public static let live: TermsAndPrivacyEnvironment = .init() +} + +public let termsAndPrivacyReducer = Reducer< + TermsAndPrivacyState, + TermsAndPrivacyAction, + TermsAndPrivacyEnvironment +> { _, action, _ in + switch action { + case .terms: + return .none + case .privacy: + return .none + } +} + +public struct TermsAndPrivacyWebView: View { + @Environment(\.presentationMode) var presentationMode + + public init(store: Store) { + self.store = store + } + + public let store: Store + + public var body: some View { + WithViewStore(self.store) { viewStore in + TermsAndPrivacyWebRepresentableView(urlString: viewStore.urlString) + .overlay( + Button( + action: { + presentationMode.wrappedValue.dismiss() + }, + label: { + Image(systemName: "xmark.circle").font(.title) + } + ) + .padding(.bottom, 10) + .padding(), + + alignment: .bottomTrailing + ) + } + } +} + +struct TermsAndPrivacyWebView_Previews: PreviewProvider { + + static let store = Store( + initialState: TermsAndPrivacyState(urlString: "http://10.0.1.3:3030/privacy"), + reducer: termsAndPrivacyReducer, environment: .init() + ) + + static var previews: some View { + TermsAndPrivacyWebView(store: store) + } +} diff --git a/Addame/Addame/Sources/AuthenticationView/TermsWebView.swift b/AddameSPM/Sources/AuthenticationView/TermsWebView.swift similarity index 100% rename from Addame/Addame/Sources/AuthenticationView/TermsWebView.swift rename to AddameSPM/Sources/AuthenticationView/TermsWebView.swift diff --git a/Addame/Addame/Sources/ChatClient/ChatClient.swift b/AddameSPM/Sources/ChatClient/ChatClient.swift similarity index 83% rename from Addame/Addame/Sources/ChatClient/ChatClient.swift rename to AddameSPM/Sources/ChatClient/ChatClient.swift index 0fd79f6..962b6f5 100644 --- a/Addame/Addame/Sources/ChatClient/ChatClient.swift +++ b/AddameSPM/Sources/ChatClient/ChatClient.swift @@ -1,12 +1,12 @@ import Combine import Foundation import FoundationExtension -import HttpRequest +import HTTPRequestKit import SharedModels public struct ChatClient { public typealias MessageListHandler = (QueryItem, String, String) -> AnyPublisher< - ChatMessageResponse, HTTPError + ChatMessageResponse, HTTPRequest.HRError > public let messages: MessageListHandler diff --git a/Addame/Addame/Sources/ChatClient/Mocks.swift b/AddameSPM/Sources/ChatClient/Mocks.swift similarity index 97% rename from Addame/Addame/Sources/ChatClient/Mocks.swift rename to AddameSPM/Sources/ChatClient/Mocks.swift index e95b620..1dad4c8 100644 --- a/Addame/Addame/Sources/ChatClient/Mocks.swift +++ b/AddameSPM/Sources/ChatClient/Mocks.swift @@ -8,7 +8,7 @@ import Combine import Foundation import FoundationExtension -import HttpRequest +import HTTPRequestKit import SharedModels // swiftlint:disable all @@ -66,7 +66,7 @@ extension ChatClient { metadata: Metadata(per: 10, total: 10, page: 1) ) ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) diff --git a/Addame/Addame/Sources/ChatClientLive/Live.swift b/AddameSPM/Sources/ChatClientLive/Live.swift similarity index 69% rename from Addame/Addame/Sources/ChatClientLive/Live.swift rename to AddameSPM/Sources/ChatClientLive/Live.swift index 25407c3..7c22c68 100644 --- a/Addame/Addame/Sources/ChatClientLive/Live.swift +++ b/AddameSPM/Sources/ChatClientLive/Live.swift @@ -8,20 +8,20 @@ import ChatClient import Combine import Foundation -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels -func token() -> AnyPublisher { +func token() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { print(#line, "not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } @@ -32,12 +32,12 @@ public struct ChatAPI { private func tokenHandle( input _: Input, path: String, - method: HTTPMethod, + method: HTTPRequest.Method, params: [String: Any] = [:], queryItems: [URLQueryItem] = [] - ) -> AnyPublisher { - return token().flatMap { token -> AnyPublisher in - let builder: HttpRequest = .build( + ) -> AnyPublisher { + return token().flatMap { token -> AnyPublisher in + let builder: HTTPRequest = .build( baseURL: baseURL, method: method, authType: .bearer(token: token), @@ -47,13 +47,13 @@ public struct ChatAPI { ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) @@ -62,9 +62,9 @@ public struct ChatAPI { public func messages( query: QueryItem, conversationID _: String, path: String - ) -> AnyPublisher { + ) -> AnyPublisher { return tokenHandle(input: query, path: path, method: .get, params: query.parameters) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) diff --git a/Addame/Addame/Sources/ChatView/ChatAction.swift b/AddameSPM/Sources/ChatView/ChatAction.swift similarity index 95% rename from Addame/Addame/Sources/ChatView/ChatAction.swift rename to AddameSPM/Sources/ChatView/ChatAction.swift index 272719b..44f2ff0 100644 --- a/Addame/Addame/Sources/ChatView/ChatAction.swift +++ b/AddameSPM/Sources/ChatView/ChatAction.swift @@ -6,7 +6,7 @@ // import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels import WebSocketClient @@ -16,7 +16,7 @@ public enum ChatAction: Equatable { case onAppear case alertDismissed case conversation(ConversationResponse.Item?) - case messages(Result) + case messages(Result) case fetchMoreMessageIfNeeded(currentItem: ChatMessageResponse.Item?) case fetchMoreMessage(currentItem: ChatMessageResponse.Item) case message(index: ChatMessageResponse.Item.ID, action: MessageAction) diff --git a/Addame/Addame/Sources/ChatView/ChatBottomView.swift b/AddameSPM/Sources/ChatView/ChatBottomView.swift similarity index 100% rename from Addame/Addame/Sources/ChatView/ChatBottomView.swift rename to AddameSPM/Sources/ChatView/ChatBottomView.swift diff --git a/Addame/Addame/Sources/ChatView/ChatEnvironment.swift b/AddameSPM/Sources/ChatView/ChatEnvironment.swift similarity index 80% rename from Addame/Addame/Sources/ChatView/ChatEnvironment.swift rename to AddameSPM/Sources/ChatView/ChatEnvironment.swift index 49878a7..2632dd5 100644 --- a/Addame/Addame/Sources/ChatView/ChatEnvironment.swift +++ b/AddameSPM/Sources/ChatView/ChatEnvironment.swift @@ -6,12 +6,14 @@ // import ChatClient +import ChatClientLive import Combine import ComposableArchitecture import ConversationClient import KeychainService import SharedModels import WebSocketClient +import WebSocketClientLive public struct ChatEnvironment { let chatClient: ChatClient @@ -40,3 +42,12 @@ public struct ChatEnvironment { return currentUSER } } + +extension ChatEnvironment { + public static let live: ChatEnvironment = .init( + chatClient: .live(api: .build), + websocketClient: .live, + mainQueue: .main, + backgroundQueue: .main + ) +} diff --git a/Addame/Addame/Sources/ChatView/ChatListView.swift b/AddameSPM/Sources/ChatView/ChatListView.swift similarity index 95% rename from Addame/Addame/Sources/ChatView/ChatListView.swift rename to AddameSPM/Sources/ChatView/ChatListView.swift index de88468..48b823a 100644 --- a/Addame/Addame/Sources/ChatView/ChatListView.swift +++ b/AddameSPM/Sources/ChatView/ChatListView.swift @@ -28,6 +28,7 @@ struct ChatListView: View { viewStore.send(.fetchMoreMessageIfNeeded(currentItem: messageViewStore.state)) } .scaleEffect(x: 1, y: -1, anchor: .center) + .listRowSeparatorHidden() } } } diff --git a/Addame/Addame/Sources/ChatView/ChatReducer.swift b/AddameSPM/Sources/ChatView/ChatReducer.swift similarity index 97% rename from Addame/Addame/Sources/ChatView/ChatReducer.swift rename to AddameSPM/Sources/ChatView/ChatReducer.swift index d259774..0df9389 100644 --- a/Addame/Addame/Sources/ChatView/ChatReducer.swift +++ b/AddameSPM/Sources/ChatView/ChatReducer.swift @@ -68,6 +68,12 @@ public let chatReducer = Reducer { state.isLoadingPage = false state.currentPage += 1 +// response.items.forEach { +// if !state.messages.contains($0) { +// state.messages.append($0) +// } +// } + let combineMessageResults = (response.items + state.messages).uniqElemets().sorted() state.messages = .init(uniqueElements: combineMessageResults) diff --git a/Addame/Addame/Sources/ChatView/ChatRowView.swift b/AddameSPM/Sources/ChatView/ChatRowView.swift similarity index 92% rename from Addame/Addame/Sources/ChatView/ChatRowView.swift rename to AddameSPM/Sources/ChatView/ChatRowView.swift index 921b412..f45bf20 100644 --- a/Addame/Addame/Sources/ChatView/ChatRowView.swift +++ b/AddameSPM/Sources/ChatView/ChatRowView.swift @@ -7,7 +7,7 @@ import AsyncImageLoder import ComposableArchitecture -import HttpRequest +import HTTPRequestKit import KeychainService import SharedModels import SwiftUI @@ -45,8 +45,9 @@ struct ChatRowView: View { @Environment(\.colorScheme) var colorScheme let store: Store - @ViewBuilder func currentUserRow(viewStore: ViewStore) - -> some View { + @ViewBuilder func currentUserRow( + viewStore: ViewStore + ) -> some View { HStack { Group { AvatarView(avatarUrl: viewStore.sender.avatarUrl) @@ -90,14 +91,14 @@ struct ChatRowView: View { if !currenuser(viewStore.sender.id) { if #available(iOS 15.0, *) { currentUserRow(viewStore: viewStore) - .listRowSeparator(.hidden) +// .listRowSeparator(.hidden) } else { currentUserRow(viewStore: viewStore) } } else { if #available(iOS 15.0, *) { opponentUsersRow(viewStore: viewStore) - .listRowSeparator(.hidden) +// .listRowSeparator(.hidden) } else { opponentUsersRow(viewStore: viewStore) } diff --git a/Addame/Addame/Sources/ChatView/ChatState.swift b/AddameSPM/Sources/ChatView/ChatState.swift similarity index 100% rename from Addame/Addame/Sources/ChatView/ChatState.swift rename to AddameSPM/Sources/ChatView/ChatState.swift diff --git a/Addame/Addame/Sources/ChatView/ChatView.swift b/AddameSPM/Sources/ChatView/ChatView.swift similarity index 95% rename from Addame/Addame/Sources/ChatView/ChatView.swift rename to AddameSPM/Sources/ChatView/ChatView.swift index 4268f58..756b237 100644 --- a/Addame/Addame/Sources/ChatView/ChatView.swift +++ b/AddameSPM/Sources/ChatView/ChatView.swift @@ -1,6 +1,6 @@ import ComposableArchitecture import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI import WebSocketClient @@ -32,7 +32,7 @@ extension ChatView { case onAppear case alertDismissed case conversation(ConversationResponse.Item?) - case messages(Result) + case messages(Result) case fetchMoreMessageIfNeeded(currentItem: ChatMessageResponse.Item?) case fetchMoreMessage(currentItem: ChatMessageResponse.Item) case message(index: ChatMessageResponse.Item.ID, action: MessageAction) @@ -70,7 +70,7 @@ public struct ChatView: View { ) .redacted(reason: viewStore.isLoadingPage ? .placeholder : []) } - .listStyle(.plain) // only for xcode 13 + .listStyle(PlainListStyle()) .scaleEffect(x: 1, y: -1, anchor: .center) .offset(x: 0, y: 2) } @@ -83,6 +83,7 @@ public struct ChatView: View { ChatBottomView(store: store) } + .padding(.bottom, 20) } } diff --git a/Addame/Addame/Sources/CombineHelpers/Combine.swift b/AddameSPM/Sources/CombineHelpers/Combine.swift similarity index 100% rename from Addame/Addame/Sources/CombineHelpers/Combine.swift rename to AddameSPM/Sources/CombineHelpers/Combine.swift diff --git a/Addame/Addame/Sources/CombineHelpers/ReplaySubject.swift b/AddameSPM/Sources/CombineHelpers/ReplaySubject.swift similarity index 100% rename from Addame/Addame/Sources/CombineHelpers/ReplaySubject.swift rename to AddameSPM/Sources/CombineHelpers/ReplaySubject.swift diff --git a/Addame/Addame/Sources/ComposableArchitectureHelpers/WebSocketId.swift b/AddameSPM/Sources/ComposableArchitectureHelpers/WebSocketId.swift similarity index 100% rename from Addame/Addame/Sources/ComposableArchitectureHelpers/WebSocketId.swift rename to AddameSPM/Sources/ComposableArchitectureHelpers/WebSocketId.swift diff --git a/Addame/Addame/Sources/ContactClient/ContactClient.swift b/AddameSPM/Sources/ContactClient/ContactClient.swift similarity index 97% rename from Addame/Addame/Sources/ContactClient/ContactClient.swift rename to AddameSPM/Sources/ContactClient/ContactClient.swift index 8fec50b..5716b6a 100644 --- a/Addame/Addame/Sources/ContactClient/ContactClient.swift +++ b/AddameSPM/Sources/ContactClient/ContactClient.swift @@ -2,7 +2,7 @@ import Combine import CombineContacts import Contacts import CoreData -import HttpRequest +import HTTPRequestKit import PhoneNumberKit import SharedModels import SwiftUI @@ -10,7 +10,7 @@ import SwiftUI public struct ContactClient { public typealias AuthorizationStatusHandler = () -> AnyPublisher public typealias BuildContactsHandler = () -> AnyPublisher<[Contact], ContactError> - public typealias GetRegisterUsersHandler = ([Contact]) -> AnyPublisher<[User], HTTPError> + public typealias GetRegisterUsersHandler = ([Contact]) -> AnyPublisher<[User], HTTPRequest.HRError> public var authorization: AuthorizationStatusHandler public var buidContacts: BuildContactsHandler diff --git a/Addame/Addame/Sources/ContactClient/Mocks.swift b/AddameSPM/Sources/ContactClient/Mocks.swift similarity index 92% rename from Addame/Addame/Sources/ContactClient/Mocks.swift rename to AddameSPM/Sources/ContactClient/Mocks.swift index 7ae6e9d..65cd36e 100644 --- a/Addame/Addame/Sources/ContactClient/Mocks.swift +++ b/AddameSPM/Sources/ContactClient/Mocks.swift @@ -9,7 +9,7 @@ import Combine import CombineContacts import Contacts import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels // swiftlint:disable all @@ -58,7 +58,7 @@ extension ContactClient { }, getRegisterUsersFromServer: { _ in Just([]) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) @@ -75,7 +75,7 @@ extension ContactClient { }, getRegisterUsersFromServer: { _ in Just([]) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) @@ -92,7 +92,7 @@ extension ContactClient { }, getRegisterUsersFromServer: { _ in Just([]) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) @@ -109,7 +109,7 @@ extension ContactClient { }, getRegisterUsersFromServer: { _ in Just(users) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) diff --git a/Addame/Addame/Sources/ContactClientLive/FlatMapLatest.swift b/AddameSPM/Sources/ContactClientLive/FlatMapLatest.swift similarity index 100% rename from Addame/Addame/Sources/ContactClientLive/FlatMapLatest.swift rename to AddameSPM/Sources/ContactClientLive/FlatMapLatest.swift diff --git a/Addame/Addame/Sources/ContactClientLive/Live.swift b/AddameSPM/Sources/ContactClientLive/Live.swift similarity index 86% rename from Addame/Addame/Sources/ContactClientLive/Live.swift rename to AddameSPM/Sources/ContactClientLive/Live.swift index 18b2e06..150c564 100644 --- a/Addame/Addame/Sources/ContactClientLive/Live.swift +++ b/AddameSPM/Sources/ContactClientLive/Live.swift @@ -12,21 +12,21 @@ import Contacts import CoreData import CoreDataStore import Foundation -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import PhoneNumberKit import SharedModels -func token() -> AnyPublisher { +func token() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { print(#line, "not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } @@ -128,9 +128,9 @@ public struct ContactAPI { } } - private func fetchUsers(by contacts: [Contact]) -> AnyPublisher<[User], HTTPError> { - return token().flatMap { token -> AnyPublisher<[User], HTTPError> in - let builder: HttpRequest = .build( + private func fetchUsers(by contacts: [Contact]) -> AnyPublisher<[User], HTTPRequest.HRError> { + return token().flatMap { token -> AnyPublisher<[User], HTTPRequest.HRError> in + let builder: HTTPRequest = .build( baseURL: baseURL, method: .post, authType: .bearer(token: token), @@ -140,28 +140,28 @@ public struct ContactAPI { ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher<[User], HTTPError> in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher<[User], HTTPRequest.HRError> in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - .catch { (error: HTTPError) -> AnyPublisher<[User], HTTPError> in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher<[User], HTTPRequest.HRError> in Fail(error: error).eraseToAnyPublisher() } - .catch { (error: HTTPError) -> AnyPublisher<[User], HTTPError> in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher<[User], HTTPRequest.HRError> in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func getRegUsers(by contacts: [Contact]) -> AnyPublisher<[User], HTTPError> { + public func getRegUsers(by contacts: [Contact]) -> AnyPublisher<[User], HTTPRequest.HRError> { return buildCustomContacts() - .mapError { contactError -> HTTPError in - HTTPError.custom("from contactError to httpError", contactError) + .mapError { contactError -> HTTPRequest.HRError in + HTTPRequest.HRError.custom("from contactError to HTTPRequest.HRError", contactError) } - .flatMapLatest { contacts -> AnyPublisher<[User], HTTPError> in + .flatMapLatest { contacts -> AnyPublisher<[User], HTTPRequest.HRError> in self.fetchUsers(by: contacts) } .eraseToAnyPublisher() diff --git a/Addame/Addame/Sources/ContactsView/ContactListAction.swift b/AddameSPM/Sources/ContactsView/ContactListAction.swift similarity index 90% rename from Addame/Addame/Sources/ContactsView/ContactListAction.swift rename to AddameSPM/Sources/ContactsView/ContactListAction.swift index 9c29eaa..3658b9a 100644 --- a/Addame/Addame/Sources/ContactsView/ContactListAction.swift +++ b/AddameSPM/Sources/ContactsView/ContactListAction.swift @@ -7,7 +7,7 @@ import ChatView import Contacts -import HttpRequest +import HTTPRequestKit import SharedModels // public enum ChatAction: Equatable {} @@ -15,7 +15,7 @@ import SharedModels public enum ContactListAction: Equatable { case onAppear case contactRow(id: String, action: ContactRowAction) - case contactsResponse(Result<[Contact], HTTPError>) + case contactsResponse(Result<[Contact], HTTPRequest.HRError>) } // extension ContactListAction { diff --git a/Addame/Addame/Sources/ContactsView/ContactListView.swift b/AddameSPM/Sources/ContactsView/ContactListView.swift similarity index 98% rename from Addame/Addame/Sources/ContactsView/ContactListView.swift rename to AddameSPM/Sources/ContactsView/ContactListView.swift index 522882c..67b3984 100644 --- a/Addame/Addame/Sources/ContactsView/ContactListView.swift +++ b/AddameSPM/Sources/ContactsView/ContactListView.swift @@ -18,7 +18,7 @@ import CoreData import CoreDataClient import CoreDataStore import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI import SwiftUIExtension diff --git a/Addame/Addame/Sources/ContactsView/ContactRow.swift b/AddameSPM/Sources/ContactsView/ContactRow.swift similarity index 96% rename from Addame/Addame/Sources/ContactsView/ContactRow.swift rename to AddameSPM/Sources/ContactsView/ContactRow.swift index 4b666b4..2685d66 100644 --- a/Addame/Addame/Sources/ContactsView/ContactRow.swift +++ b/AddameSPM/Sources/ContactsView/ContactRow.swift @@ -71,11 +71,7 @@ public struct ContactRow: View { if #available(iOS 15.0, *) { Image(systemName: "bubble.left.and.bubble.right") .opacity(viewStore.isMoving ? 0 : 1) - .overlay { - if viewStore.isMoving { - ProgressView() - } - } + .overlay(ProgressView().opacity(viewStore.isMoving ? 1 : 0)) } else { Image(systemName: "bubble.left.and.bubble.right") .opacity(isClick ? 0 : 1) diff --git a/Addame/Addame/Sources/ContactsView/ContactRowAction.swift b/AddameSPM/Sources/ContactsView/ContactRowAction.swift similarity index 92% rename from Addame/Addame/Sources/ContactsView/ContactRowAction.swift rename to AddameSPM/Sources/ContactsView/ContactRowAction.swift index 620f131..fbf1c7c 100644 --- a/Addame/Addame/Sources/ContactsView/ContactRowAction.swift +++ b/AddameSPM/Sources/ContactsView/ContactRowAction.swift @@ -7,7 +7,7 @@ import ChatView import Contacts -import HttpRequest +import HTTPRequestKit import SharedModels public enum ContactRowAction: Equatable { diff --git a/Addame/Addame/Sources/ContactsView/ContactRowReducer.swift b/AddameSPM/Sources/ContactsView/ContactRowReducer.swift similarity index 96% rename from Addame/Addame/Sources/ContactsView/ContactRowReducer.swift rename to AddameSPM/Sources/ContactsView/ContactRowReducer.swift index c9cd00e..d69e0e6 100644 --- a/Addame/Addame/Sources/ContactsView/ContactRowReducer.swift +++ b/AddameSPM/Sources/ContactsView/ContactRowReducer.swift @@ -11,7 +11,7 @@ import ChatView import Combine import ComposableArchitecture import ComposableArchitectureHelpers -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI diff --git a/Addame/Addame/Sources/ContactsView/ContactRowState.swift b/AddameSPM/Sources/ContactsView/ContactRowState.swift similarity index 95% rename from Addame/Addame/Sources/ContactsView/ContactRowState.swift rename to AddameSPM/Sources/ContactsView/ContactRowState.swift index 2243907..c5b8917 100644 --- a/Addame/Addame/Sources/ContactsView/ContactRowState.swift +++ b/AddameSPM/Sources/ContactsView/ContactRowState.swift @@ -8,7 +8,7 @@ import ChatView import ComposableArchitecture import Contacts -import HttpRequest +import HTTPRequestKit import SharedModels public struct ContactRowState: Equatable, Identifiable { diff --git a/Addame/Addame/Sources/ContactsView/ContactsAction.swift b/AddameSPM/Sources/ContactsView/ContactsAction.swift similarity index 93% rename from Addame/Addame/Sources/ContactsView/ContactsAction.swift rename to AddameSPM/Sources/ContactsView/ContactsAction.swift index 3663a88..a14d5e8 100644 --- a/Addame/Addame/Sources/ContactsView/ContactsAction.swift +++ b/AddameSPM/Sources/ContactsView/ContactsAction.swift @@ -7,7 +7,7 @@ import ChatView import Contacts -import HttpRequest +import HTTPRequestKit import SharedModels // public enum ChatAction: Equatable {} @@ -17,7 +17,7 @@ public enum ContactsAction: Equatable { case alertDismissed case contact(id: String?, action: ContactRowAction) case contactsAuthorizationStatus(CNAuthorizationStatus) - case contactsResponse(Result<[Contact], HTTPError>) + case contactsResponse(Result<[Contact], HTTPRequest.HRError>) case moveToChatRoom(Bool) case chatWith(name: String, phoneNumber: String) diff --git a/Addame/Addame/Sources/ContactsView/ContactsEnvironment.swift b/AddameSPM/Sources/ContactsView/ContactsEnvironment.swift similarity index 71% rename from Addame/Addame/Sources/ContactsView/ContactsEnvironment.swift rename to AddameSPM/Sources/ContactsView/ContactsEnvironment.swift index fc1e8b2..bf9fcff 100644 --- a/Addame/Addame/Sources/ContactsView/ContactsEnvironment.swift +++ b/AddameSPM/Sources/ContactsView/ContactsEnvironment.swift @@ -9,6 +9,8 @@ import Combine import ComposableArchitecture import CoreDataClient import CoreDataStore +import ContactClient +import ContactClientLive public struct ContactsEnvironment { public let coreDataClient: CoreDataClient @@ -26,3 +28,13 @@ public struct ContactsEnvironment { self.mainQueue = mainQueue } } + +extension ContactsEnvironment { + public static let live: ContactsEnvironment = .init( + coreDataClient: CoreDataClient( + contactClient: ContactClient.live(api: .build) + ), + backgroundQueue: .main, + mainQueue: .main + ) +} diff --git a/Addame/Addame/Sources/ContactsView/ContactsReducer.swift b/AddameSPM/Sources/ContactsView/ContactsReducer.swift similarity index 99% rename from Addame/Addame/Sources/ContactsView/ContactsReducer.swift rename to AddameSPM/Sources/ContactsView/ContactsReducer.swift index 0ce66da..008b7b0 100644 --- a/Addame/Addame/Sources/ContactsView/ContactsReducer.swift +++ b/AddameSPM/Sources/ContactsView/ContactsReducer.swift @@ -13,7 +13,7 @@ import ComposableArchitecture import ComposableArchitectureHelpers import CoreData import CoreDataStore -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI import WebSocketClient diff --git a/Addame/Addame/Sources/ContactsView/ContactsState.swift b/AddameSPM/Sources/ContactsView/ContactsState.swift similarity index 99% rename from Addame/Addame/Sources/ContactsView/ContactsState.swift rename to AddameSPM/Sources/ContactsView/ContactsState.swift index 453b2f7..53a7ab9 100644 --- a/Addame/Addame/Sources/ContactsView/ContactsState.swift +++ b/AddameSPM/Sources/ContactsView/ContactsState.swift @@ -8,7 +8,7 @@ import ChatView import ComposableArchitecture import Contacts -import HttpRequest +import HTTPRequestKit import SharedModels public struct ContactsState: Equatable { diff --git a/Addame/Addame/Sources/ContactsView/ContactsView.swift b/AddameSPM/Sources/ContactsView/ContactsView.swift similarity index 96% rename from Addame/Addame/Sources/ContactsView/ContactsView.swift rename to AddameSPM/Sources/ContactsView/ContactsView.swift index 14a0434..38c3efd 100644 --- a/Addame/Addame/Sources/ContactsView/ContactsView.swift +++ b/AddameSPM/Sources/ContactsView/ContactsView.swift @@ -11,7 +11,7 @@ import CoreData import CoreDataClient import CoreDataStore import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI @@ -29,7 +29,7 @@ extension ContactsView { case alertDismissed case contactRow(id: String?, action: ContactRowAction) case contactsAuthorizationStatus(CNAuthorizationStatus) - case contactsResponse(Result<[Contact], HTTPError>) + case contactsResponse(Result<[Contact], HTTPRequest.HRError>) } } diff --git a/Addame/Addame/Sources/ConversationClient/ConversationClient.swift b/AddameSPM/Sources/ConversationClient/ConversationClient.swift similarity index 81% rename from Addame/Addame/Sources/ConversationClient/ConversationClient.swift rename to AddameSPM/Sources/ConversationClient/ConversationClient.swift index 8da0801..1819151 100644 --- a/Addame/Addame/Sources/ConversationClient/ConversationClient.swift +++ b/AddameSPM/Sources/ConversationClient/ConversationClient.swift @@ -1,19 +1,19 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI public struct ConversationClient { public typealias ConversationCreateHandler = - (CreateConversation, String) -> AnyPublisher + (CreateConversation, String) -> AnyPublisher public typealias AddUserToConversationHandler = (AddUser, String) - -> AnyPublisher + -> AnyPublisher public typealias ConversationListHandler = (QueryItem, String) -> AnyPublisher< - ConversationResponse, HTTPError + ConversationResponse, HTTPRequest.HRError > public typealias ConversationFindHandler = (String, String) -> AnyPublisher< - ConversationResponse.Item, HTTPError + ConversationResponse.Item, HTTPRequest.HRError > public let create: ConversationCreateHandler diff --git a/Addame/Addame/Sources/ConversationClient/Mocks.swift b/AddameSPM/Sources/ConversationClient/Mocks.swift similarity index 93% rename from Addame/Addame/Sources/ConversationClient/Mocks.swift rename to AddameSPM/Sources/ConversationClient/Mocks.swift index af1f761..877fc92 100644 --- a/Addame/Addame/Sources/ConversationClient/Mocks.swift +++ b/AddameSPM/Sources/ConversationClient/Mocks.swift @@ -8,7 +8,7 @@ import Combine import Foundation import FoundationExtension -import HttpRequest +import HTTPRequestKit import SharedModels // swiftlint:disable all @@ -43,12 +43,12 @@ extension ConversationClient { return Just( conversationItem ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, addUserToConversation: { _, _ in Just(ConversationResponse.UserAdd.diff) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, list: { _, _ in @@ -75,7 +75,7 @@ extension ConversationClient { metadata: Metadata(per: 10, total: 10, page: 1) ) ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, find: { _, _ in @@ -107,7 +107,7 @@ extension ConversationClient { return Just( conversationItem ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) diff --git a/Addame/Addame/Sources/ConversationClientLive/Live.swift b/AddameSPM/Sources/ConversationClientLive/Live.swift similarity index 63% rename from Addame/Addame/Sources/ConversationClientLive/Live.swift rename to AddameSPM/Sources/ConversationClientLive/Live.swift index e24307e..51914c6 100644 --- a/Addame/Addame/Sources/ConversationClientLive/Live.swift +++ b/AddameSPM/Sources/ConversationClientLive/Live.swift @@ -8,20 +8,20 @@ import Combine import ConversationClient import Foundation -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels -func token() -> AnyPublisher { +func token() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { print(#line, "not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } @@ -29,36 +29,45 @@ public struct ConversationAPI { public static let build = Self() private var baseURL: URL { EnvironmentKeys.rootURL.appendingPathComponent("/conversations") } + fileprivate func handleDataType( + input: Input? = nil, + params: [String: Any] = [:], + queryItems: [URLQueryItem] = [] + ) -> HTTPRequest.DataType { + if !params.isEmpty { + return .query(with: params) + } else if !queryItems.isEmpty { + return .query(with: queryItems) + } else { + return .encodable(input: input, encoder: .init()) + } + } + private func tokenHandle( input: Input? = nil, path: String, - method: HTTPMethod, + method: HTTPRequest.Method, params: [String: Any] = [:], queryItems: [URLQueryItem] = [] - ) -> AnyPublisher { - return token().flatMap { token -> AnyPublisher in - let builder: HttpRequest = .build( + ) -> AnyPublisher { + return token().flatMap { token -> AnyPublisher in + let builder: HTTPRequest = .build( baseURL: baseURL, method: method, authType: .bearer(token: token), path: path, contentType: .json, - dataType: .sendData( - items: queryItems, - params: params, - encodable: input, - parameters: input - ) + dataType: handleDataType(input: input, params: params, queryItems: queryItems) ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) @@ -67,10 +76,10 @@ public struct ConversationAPI { func tokenHandle( path: String, - method: HTTPMethod, + method: HTTPRequest.Method, params: [String: Any] = [:], queryItems: [URLQueryItem] = [] - ) -> AnyPublisher { + ) -> AnyPublisher { return tokenHandle( input: Never?.none, path: path, method: method, params: params, queryItems: queryItems ) @@ -78,9 +87,9 @@ public struct ConversationAPI { .eraseToAnyPublisher() } - public func create(event: Event, path: String) -> AnyPublisher { + public func create(event: Event, path: String) -> AnyPublisher { return tokenHandle(input: event, path: path, method: .post) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) @@ -90,9 +99,9 @@ public struct ConversationAPI { public func create( conversation: CreateConversation, path: String - ) -> AnyPublisher { + ) -> AnyPublisher { return tokenHandle(input: conversation, path: path, method: .post) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) @@ -102,7 +111,7 @@ public struct ConversationAPI { public func addUserToConversation( addUser: AddUser, path: String - ) -> AnyPublisher { + ) -> AnyPublisher { return tokenHandle( path: path, method: .post, params: [ @@ -110,16 +119,16 @@ public struct ConversationAPI { "usersId": addUser.usersId ] ) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func list(query: QueryItem, path: String) -> AnyPublisher { + public func list(query: QueryItem, path: String) -> AnyPublisher { return tokenHandle(input: query, path: path, method: .get) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) @@ -127,13 +136,13 @@ public struct ConversationAPI { } public func find(conversationsId: String, path: String) -> AnyPublisher< - ConversationResponse.Item, HTTPError + ConversationResponse.Item, HTTPRequest.HRError > { return tokenHandle( path: path, method: .get, params: ["conversationsId": conversationsId] ) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) diff --git a/Addame/Addame/Sources/ConversationsView/ConversationEnvironment.swift b/AddameSPM/Sources/ConversationsView/ConversationEnvironment.swift similarity index 83% rename from Addame/Addame/Sources/ConversationsView/ConversationEnvironment.swift rename to AddameSPM/Sources/ConversationsView/ConversationEnvironment.swift index 1043e0a..14452d8 100644 --- a/Addame/Addame/Sources/ConversationsView/ConversationEnvironment.swift +++ b/AddameSPM/Sources/ConversationsView/ConversationEnvironment.swift @@ -9,6 +9,7 @@ import ChatClient import Combine import ComposableArchitecture import ConversationClient +import ConversationClientLive import SharedModels import WebSocketClient @@ -31,6 +32,15 @@ public struct ConversationEnvironment { } } +extension ConversationEnvironment { + public static let live: ConversationEnvironment = .init( + conversationClient: .live(api: .build), + websocketClient: .live, + backgroundQueue: .main, + mainQueue: .main + ) +} + // public class WebsocketEnvironment { // // let websocketClient: WebSocketClient diff --git a/Addame/Addame/Sources/ConversationsView/ConversationsAction.swift b/AddameSPM/Sources/ConversationsView/ConversationsAction.swift similarity index 92% rename from Addame/Addame/Sources/ConversationsView/ConversationsAction.swift rename to AddameSPM/Sources/ConversationsView/ConversationsAction.swift index 48ecc80..ea29cf9 100644 --- a/Addame/Addame/Sources/ConversationsView/ConversationsAction.swift +++ b/AddameSPM/Sources/ConversationsView/ConversationsAction.swift @@ -9,7 +9,7 @@ import ChatView import ComposableArchitecture import ContactsView import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels public enum ConversationsAction: Equatable { @@ -22,8 +22,8 @@ public enum ConversationsAction: Equatable { case chat(ChatAction) case contacts(ContactsAction) - case conversationsResponse(Result) - case conversationResponse(Result) + case conversationsResponse(Result) + case conversationResponse(Result) case fetchMoreConversationIfNeeded(currentItem: ConversationResponse.Item?) } diff --git a/Addame/Addame/Sources/ConversationsView/ConversationsReducer.swift b/AddameSPM/Sources/ConversationsView/ConversationsReducer.swift similarity index 88% rename from Addame/Addame/Sources/ConversationsView/ConversationsReducer.swift rename to AddameSPM/Sources/ConversationsView/ConversationsReducer.swift index a20fc38..12cda16 100644 --- a/Addame/Addame/Sources/ConversationsView/ConversationsReducer.swift +++ b/AddameSPM/Sources/ConversationsView/ConversationsReducer.swift @@ -5,17 +5,13 @@ // Created by Saroar Khandoker on 20.04.2021. // -import ChatClient -import ChatClientLive import ChatView import Combine import ComposableArchitecture +import ComposablePresentation import ComposableArchitectureHelpers -import ContactClient -import ContactClientLive import ContactsView -import CoreDataClient -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI import WebSocketClient @@ -135,6 +131,7 @@ public let conversationsReducer = Reducer< return presentChatView() case let .conversationResponse(.failure(error)): + print(error) return .none case let .contacts(.contact(id: id, action: action)): @@ -167,30 +164,15 @@ public let conversationsReducer = Reducer< return .none } } -.presents( +.presenting( chatReducer, state: \.chatState, action: /ConversationsAction.chat, - environment: { - ChatEnvironment( - chatClient: ChatClient.live(api: .build), - websocketClient: .live, - mainQueue: $0.mainQueue, - backgroundQueue: $0.backgroundQueue - ) - } + environment: { _ in ChatEnvironment.live } ) -.presents( +.presenting( contactsReducer, state: \.contactsState, action: /ConversationsAction.contacts, - environment: { - ContactsEnvironment( - coreDataClient: CoreDataClient( - contactClient: ContactClient.live(api: .build) - ), - backgroundQueue: $0.backgroundQueue, - mainQueue: $0.mainQueue - ) - } + environment: { _ in ContactsEnvironment.live } ) diff --git a/Addame/Addame/Sources/ConversationsView/ConversationsState.swift b/AddameSPM/Sources/ConversationsView/ConversationsState.swift similarity index 100% rename from Addame/Addame/Sources/ConversationsView/ConversationsState.swift rename to AddameSPM/Sources/ConversationsView/ConversationsState.swift diff --git a/Addame/Addame/Sources/ConversationsView/ConversationsView.swift b/AddameSPM/Sources/ConversationsView/ConversationsView.swift similarity index 86% rename from Addame/Addame/Sources/ConversationsView/ConversationsView.swift rename to AddameSPM/Sources/ConversationsView/ConversationsView.swift index 73df7c2..02079f7 100644 --- a/Addame/Addame/Sources/ConversationsView/ConversationsView.swift +++ b/AddameSPM/Sources/ConversationsView/ConversationsView.swift @@ -8,9 +8,10 @@ import AsyncImageLoder import ChatView import ComposableArchitecture +import ComposablePresentation import ComposableArchitectureHelpers import ContactsView -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI import SwiftUIExtension @@ -50,7 +51,7 @@ extension ConversationsView { case alertDismissed case chatView(isPresented: Bool) case contactsView(isPresented: Bool) - case conversationsResponse(Result) + case conversationsResponse(Result) case fetchMoreConversationIfNeeded(currentItem: ConversationResponse.Item?) case conversationTapped(ConversationResponse.Item) case chat(ChatAction) @@ -88,6 +89,9 @@ public struct ConversationsView: View { .redacted(reason: viewStore.isLoadingPage ? .placeholder : []) } } + .onAppear { + ViewStore(store.stateless).send(.onAppear) + } .navigationTitle("Chats") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { @@ -97,11 +101,7 @@ public struct ConversationsView: View { if #available(iOS 15.0, *) { Image(systemName: "bubble.left.and.bubble.right") .opacity(viewStore.isSheetPresented ? 0 : 1) - .overlay { - if viewStore.isSheetPresented { - ProgressView() - } - } + .overlay(ProgressView().opacity(viewStore.isSheetPresented ? 1 : 0) ) } else { Image(systemName: "square.and.pencil") .opacity(viewStore.isSheetPresented ? 0 : 1) @@ -111,32 +111,21 @@ public struct ConversationsView: View { } .background(Color(.systemBackground)) .alert(self.store.scope(state: { $0.alert }), dismiss: ConversationsAction.alertDismissed) - .sheet( - isPresented: - viewStore.binding( - get: { $0.isSheetPresented }, - send: ConversationsView.ViewAction.contactsView(isPresented:) - ) - ) { - IfLetStore( - self.store.scope( - state: { $0.contactsState }, - action: ConversationsAction.contacts - ), - then: ContactsView.init(store:) - ) - } } - .debug("ConversationView") - .navigate( - using: store.scope( - state: \.chatState, - action: ConversationsAction.chat - ), - destination: ChatView.init(store:), - onDismiss: { - ViewStore(store.stateless).send(.chatView(isPresented: false)) - } + .navigationViewStyle(StackNavigationViewStyle()) + .sheet( + store.scope(state: \.contactsState, action: ConversationsAction.contacts), + mapState: replayNonNil(), + onDismiss: { ViewStore(store.stateless).send(.contactsView(isPresented: false)) }, + content: ContactsView.init(store:) + ) + .background( + NavigationLinkWithStore( + store.scope(state: \.chatState, action: ConversationsAction.chat), + mapState: replayNonNil(), + onDeactivate: { ViewStore(store.stateless).send(.chatView(isPresented: false)) }, + destination: ChatView.init(store:) + ) ) } } @@ -181,13 +170,13 @@ public struct ConversationListView: View { viewStore.send(.conversationTapped(conversationViewStore.state)) } label: { ConversationRow(store: conversationStore) - // .onAppear { - // viewStore.send( - // .fetchMoreConversationIfNeeded( - // currentItem: conversationViewStore.state - // ) - // ) - // } + // .onAppear { + // viewStore.send( + // .fetchMoreConversationIfNeeded( + // currentItem: conversationViewStore.state + // ) + // ) + // } } .buttonStyle(PlainButtonStyle()) } diff --git a/Addame/Addame/Sources/CoreDataClient/CoreDataClient.swift b/AddameSPM/Sources/CoreDataClient/CoreDataClient.swift similarity index 92% rename from Addame/Addame/Sources/CoreDataClient/CoreDataClient.swift rename to AddameSPM/Sources/CoreDataClient/CoreDataClient.swift index 8b69a20..192d150 100644 --- a/Addame/Addame/Sources/CoreDataClient/CoreDataClient.swift +++ b/AddameSPM/Sources/CoreDataClient/CoreDataClient.swift @@ -4,7 +4,7 @@ import ContactClientLive import CoreData import CoreDataStore import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels public final class CoreDataClient { @@ -15,11 +15,11 @@ public final class CoreDataClient { self.contactClient = contactClient } - public func getContacts() -> AnyPublisher<[Contact], HTTPError> { + public func getContacts() -> AnyPublisher<[Contact], HTTPRequest.HRError> { return contactClient.buidContacts() .removeDuplicates() .mapError { - return HTTPError.custom("ContactEntity Fetch data error ", $0) + return HTTPRequest.HRError.custom("ContactEntity Fetch data error ", $0) } .flatMap { contacts in self.registerContacts(contacts: contacts) @@ -27,7 +27,7 @@ public final class CoreDataClient { .eraseToAnyPublisher() } - public func registerContacts(contacts: [Contact]) -> AnyPublisher<[Contact], HTTPError> { + public func registerContacts(contacts: [Contact]) -> AnyPublisher<[Contact], HTTPRequest.HRError> { var results = [Contact]() return contactClient.getRegisterUsersFromServer(contacts) .map { users -> [Contact] in @@ -117,7 +117,7 @@ public final class CoreDataClient { // // } - // public func fetchContactEntityThenConvertToContacts() -> AnyPublisher<[Contact], HTTPError> { + // public func fetchContactEntityThenConvertToContacts() -> AnyPublisher<[Contact], HTTPRequest.HRError> { // let request: NSFetchRequest = ContactEntity.fetchRequest() // let sortDescriptor = NSSortDescriptor(key: "id", ascending: true) // request.sortDescriptors = [sortDescriptor] @@ -134,7 +134,7 @@ public final class CoreDataClient { // .print() // .receive(on: DispatchQueue.main) // .mapError { - // return HTTPError.custom("ContactEntity Fetch data error ", $0) + // return HTTPRequest.HRError.custom("ContactEntity Fetch data error ", $0) // } // .eraseToAnyPublisher() // diff --git a/Addame/Addame/Sources/CoreDataStore/CoreDataStore.swift b/AddameSPM/Sources/CoreDataStore/CoreDataStore.swift similarity index 70% rename from Addame/Addame/Sources/CoreDataStore/CoreDataStore.swift rename to AddameSPM/Sources/CoreDataStore/CoreDataStore.swift index 86ea80c..f321590 100644 --- a/Addame/Addame/Sources/CoreDataStore/CoreDataStore.swift +++ b/AddameSPM/Sources/CoreDataStore/CoreDataStore.swift @@ -7,25 +7,6 @@ public struct CoreDataStore { return container.viewContext } - // static public var preview: CoreDataStore = { - // guard let result = CoreDataStore(inMemory: false) else { return } - // let viewContext = result.container.viewContext - // - // if viewContext.hasChanges { - // do { - // try viewContext.save() - // } catch { - // // The context couldn't be saved. - // // You should add your own error handling here. - // let nserror = error as NSError - // fatalError("Unresolved error \(nserror), \(nserror.userInfo)") - // } - // } - // - // return result - // - // }() - public let container: NSPersistentContainer @discardableResult diff --git a/Addame/Addame/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataClass.swift b/AddameSPM/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataClass.swift similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataClass.swift rename to AddameSPM/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataClass.swift diff --git a/Addame/Addame/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataProperties.swift b/AddameSPM/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataProperties.swift similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataProperties.swift rename to AddameSPM/Sources/CoreDataStore/Entities/Contacts/ContactEntity+CoreDataProperties.swift diff --git a/Addame/Addame/Sources/CoreDataStore/Entities/Contacts/ContactEntityExtension.swift b/AddameSPM/Sources/CoreDataStore/Entities/Contacts/ContactEntityExtension.swift similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Entities/Contacts/ContactEntityExtension.swift rename to AddameSPM/Sources/CoreDataStore/Entities/Contacts/ContactEntityExtension.swift diff --git a/Addame/Addame/Sources/CoreDataStore/Helper/CoreDataPublisher.swift b/AddameSPM/Sources/CoreDataStore/Helper/CoreDataPublisher.swift similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Helper/CoreDataPublisher.swift rename to AddameSPM/Sources/CoreDataStore/Helper/CoreDataPublisher.swift diff --git a/Addame/Addame/Sources/CoreDataStore/Helper/ManagedModel.swift b/AddameSPM/Sources/CoreDataStore/Helper/ManagedModel.swift similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Helper/ManagedModel.swift rename to AddameSPM/Sources/CoreDataStore/Helper/ManagedModel.swift diff --git a/Addame/Addame/Sources/CoreDataStore/Helper/NSManagedObjectContext+Extensions.swift b/AddameSPM/Sources/CoreDataStore/Helper/NSManagedObjectContext+Extensions.swift similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Helper/NSManagedObjectContext+Extensions.swift rename to AddameSPM/Sources/CoreDataStore/Helper/NSManagedObjectContext+Extensions.swift diff --git a/Addame/Addame/Sources/CoreDataStore/Models/AddaModel.xcdatamodeld/AddaModel.xcdatamodel/contents b/AddameSPM/Sources/CoreDataStore/Models/AddaModel.xcdatamodeld/AddaModel.xcdatamodel/contents similarity index 100% rename from Addame/Addame/Sources/CoreDataStore/Models/AddaModel.xcdatamodeld/AddaModel.xcdatamodel/contents rename to AddameSPM/Sources/CoreDataStore/Models/AddaModel.xcdatamodeld/AddaModel.xcdatamodel/contents diff --git a/Addame/Addame/Sources/EventClient/EventClient.swift b/AddameSPM/Sources/EventClient/EventClient.swift similarity index 81% rename from Addame/Addame/Sources/EventClient/EventClient.swift rename to AddameSPM/Sources/EventClient/EventClient.swift index e4e4a13..eacd74e 100644 --- a/Addame/Addame/Sources/EventClient/EventClient.swift +++ b/AddameSPM/Sources/EventClient/EventClient.swift @@ -1,12 +1,12 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels import SwiftUI public struct EventClient { - public typealias EventFetchHandler = (QueryItem, String) -> AnyPublisher - public typealias EventCreateHandler = (Event, String) -> AnyPublisher + public typealias EventFetchHandler = (QueryItem, String) -> AnyPublisher + public typealias EventCreateHandler = (Event, String) -> AnyPublisher public let events: EventFetchHandler public let create: EventCreateHandler diff --git a/Addame/Addame/Sources/EventClient/Mocks.swift b/AddameSPM/Sources/EventClient/Mocks.swift similarity index 62% rename from Addame/Addame/Sources/EventClient/Mocks.swift rename to AddameSPM/Sources/EventClient/Mocks.swift index e877f13..c62c479 100644 --- a/Addame/Addame/Sources/EventClient/Mocks.swift +++ b/AddameSPM/Sources/EventClient/Mocks.swift @@ -7,20 +7,21 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels // swiftlint:disable all extension EventClient { + private static let data = Date(timeIntervalSince1970: 0) public static let empty = Self( events: { _, _ in Just(EventResponse.emptry) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, create: { _, _ in - Just(Event.draff) - .setFailureType(to: HTTPError.self) + Just(EventResponse.Item.draff) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) @@ -31,54 +32,57 @@ extension EventClient { EventResponse( items: [ .init( - id: "5fbfe53675a93bda87c7cb16", name: "Cool :)", categories: "General", + id: "5fbfe53675a93bda87c7cb10", name: "In Future people will be very kind and happy!", categories: "General", duration: 14400, isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, overlay: false, - coordinates: [60.020532228306031, 30.388014239849944], createdAt: Date(), - updatedAt: Date()), + coordinates: [60.020532228306031, 30.388014239849944], createdAt: data, + updatedAt: data), .init( - id: "5fbe8a8c8ba94be8a688324a", name: "Awesome 🤩 app", categories: "General", + id: "5fbe8a8c8ba94be8a688324c", name: "Awesome 🤩 app ", categories: "General", duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, overlay: false, - coordinates: [60.020525506753494, 30.387988546891499], createdAt: Date(), - updatedAt: Date()), + coordinates: [60.020525506753494, 30.387988546891499], createdAt: data, + updatedAt: data), .init( id: "5fbea245b226053f0ece711c", name: "Bicycling 🚴🏽", categories: "LookingForAcompany", duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", addressName: "9к5 улица Бутлерова Saint Petersburg, Saint Petersburg", type: "Point", sponsored: false, overlay: false, - coordinates: [60.00380571585201, 30.399472870547118], createdAt: Date(), - updatedAt: Date()), + coordinates: [60.00380571585201, 30.399472870547118], createdAt: data, + updatedAt: data), .init( - id: "5fbea245b226053f0ece711c", name: "Walk Around 🚶🏽🚶🏼‍♀️", + id: "5fbea245b226053f0ece712c", name: "Walk Around 🚶🏽🚶🏼‍♀️", categories: "LookingForAcompany", imageUrl: "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", addressName: "188839, Первомайское, СНТ Славино-2 Поселок, 31 Первомайское Россия", type: "Point", sponsored: false, overlay: false, - coordinates: [60.261340452875721, 29.873706166262373], createdAt: Date(), - updatedAt: Date()), + coordinates: [60.261340452875721, 29.873706166262373], createdAt: data, + updatedAt: data), ], - metadata: .init(per: 10, total: 10, page: 1) + metadata: .init(per: 2, total: 4, page: 1) ) ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, create: { _, _ in Just( - Event( - id: "5fb1510012de9980bd0c2efc", name: "Testing data", details: "Waitting for details", - imageUrl: - "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", - duration: 14400, categories: "General", isActive: true, - addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: .Point, sponsored: false, - overlay: false, coordinates: [60.020532228306031, 30.388014239849944]) + EventResponse.Item( + id: "5fbfe53675a93bda87c7cb16", name: "Create Event For Test", categories: "General", + imageUrl: "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1605811270871.jpeg", + duration: 14400, isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", + sponsored: false, overlay: false, + coordinates: [60.020532228306031, 30.388014239849944], + createdAt: data, + updatedAt: data + ) ) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) diff --git a/Addame/Addame/Sources/EventClientLive/Live.swift b/AddameSPM/Sources/EventClientLive/Live.swift similarity index 71% rename from Addame/Addame/Sources/EventClientLive/Live.swift rename to AddameSPM/Sources/EventClientLive/Live.swift index 1c24969..5e83461 100644 --- a/Addame/Addame/Sources/EventClientLive/Live.swift +++ b/AddameSPM/Sources/EventClientLive/Live.swift @@ -8,20 +8,20 @@ import Combine import EventClient import Foundation -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels -func token() -> AnyPublisher { +func token() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { print(#line, "not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } @@ -34,7 +34,7 @@ public struct EventAPI { input: Input? = nil, params: [String: Any] = [:], queryItems: [URLQueryItem] = [] - ) -> DataType { + ) -> HTTPRequest.DataType { if !params.isEmpty { return .query(with: params) } else if !queryItems.isEmpty { @@ -47,13 +47,13 @@ public struct EventAPI { private func tokenHandle( input: Input? = nil, path: String, - method: HTTPMethod, + method: HTTPRequest.Method, params: [String: Any] = [:], queryItems: [URLQueryItem] = [] - ) -> AnyPublisher { - return token().flatMap { token -> AnyPublisher in + ) -> AnyPublisher { + return token().flatMap { token -> AnyPublisher in - let builder: HttpRequest = .build( + let builder: HTTPRequest = .build( baseURL: baseURL, method: method, authType: .bearer(token: token), @@ -63,40 +63,40 @@ public struct EventAPI { ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func create(event: Event, path: String) -> AnyPublisher { + public func create(event: Event, path: String) -> AnyPublisher { return tokenHandle(input: event, path: path, method: .post) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func fetch(events query: QueryItem, path: String) -> AnyPublisher { + public func fetch(events query: QueryItem, path: String) -> AnyPublisher { return tokenHandle(input: query, path: path, method: .get) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func fetch(query: QueryItem, path: String) -> AnyPublisher { + public func fetch(query: QueryItem, path: String) -> AnyPublisher { return tokenHandle(input: query, path: path, method: .get, params: query.parameters) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsAction.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsAction.swift similarity index 97% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsAction.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsAction.swift index 4a08ba9..3a8883c 100644 --- a/Addame/Addame/Sources/EventDetailsView/EventDetailsAction.swift +++ b/AddameSPM/Sources/EventDetailsView/EventDetailsAction.swift @@ -7,7 +7,7 @@ import ComposableArchitecture import ConversationClient -import HttpRequest +import HTTPRequestKit import KeychainService import MapView import SharedModels diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsEnvironment.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsEnvironment.swift similarity index 71% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsEnvironment.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsEnvironment.swift index 250f6bb..343e425 100644 --- a/Addame/Addame/Sources/EventDetailsView/EventDetailsEnvironment.swift +++ b/AddameSPM/Sources/EventDetailsView/EventDetailsEnvironment.swift @@ -7,6 +7,7 @@ import ComposableArchitecture import ConversationClient +import ConversationClientLive public struct EventDetailsEnvironment { public init( @@ -20,3 +21,10 @@ public struct EventDetailsEnvironment { public let conversationClient: ConversationClient var mainQueue: AnySchedulerOf } + +extension EventDetailsEnvironment { + public static let live: EventDetailsEnvironment = .init( + conversationClient: .live(api: .build), + mainQueue: .main + ) +} diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayAction.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsOverlayAction.swift similarity index 88% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayAction.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsOverlayAction.swift index 2a6deb1..699ff16 100644 --- a/Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayAction.swift +++ b/AddameSPM/Sources/EventDetailsView/EventDetailsOverlayAction.swift @@ -7,7 +7,7 @@ import ComposableArchitecture import ConversationClient -import HttpRequest +import HTTPRequestKit import KeychainService import MapView import SharedModels @@ -17,8 +17,8 @@ public enum EventDetailsOverlayAction: Equatable { case alertDismissed case startChat(Bool) case askJoinRequest(Bool) - case joinToEvent(Result) - case conversationResponse(Result) + case joinToEvent(Result) + case conversationResponse(Result) } extension EventDetailsOverlayAction { diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayReducer.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsOverlayReducer.swift similarity index 100% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayReducer.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsOverlayReducer.swift diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayState.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsOverlayState.swift similarity index 100% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayState.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsOverlayState.swift diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayView.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsOverlayView.swift similarity index 96% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayView.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsOverlayView.swift index e6a44de..b652ef4 100644 --- a/Addame/Addame/Sources/EventDetailsView/EventDetailsOverlayView.swift +++ b/AddameSPM/Sources/EventDetailsView/EventDetailsOverlayView.swift @@ -8,7 +8,7 @@ import AsyncImageLoder import ComposableArchitecture import ComposableArchitectureHelpers -import HttpRequest +import HTTPRequestKit import MapKit import SharedModels import SwiftUI @@ -89,8 +89,8 @@ extension EventDetailsOverlayView { case alertDismissed case startChat(Bool) case askJoinRequest(Bool) - case joinToEvent(Result) - case conversationResponse(Result) + case joinToEvent(Result) + case conversationResponse(Result) } } diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsReducer.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsReducer.swift similarity index 93% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsReducer.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsReducer.swift index a1af0c5..6235e75 100644 --- a/Addame/Addame/Sources/EventDetailsView/EventDetailsReducer.swift +++ b/AddameSPM/Sources/EventDetailsView/EventDetailsReducer.swift @@ -9,7 +9,7 @@ import ChatView import ComposableArchitecture import ConversationClient import ConversationClientLive -import HttpRequest +import HTTPRequestKit import KeychainService import MapKit import MapView @@ -35,9 +35,12 @@ public let eventDetailsReducer = Reducer< switch action { case .onAppear: + let latitude = state.event.coordinates[0] + let longitude = state.event.coordinates[1] + let coordinate = CLLocationCoordinate2D( - latitude: state.event.coordinate.latitude, - longitude: state.event.coordinate.longitude + latitude: latitude, + longitude: longitude ) state.region = CoordinateRegion( diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsState.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsState.swift similarity index 100% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsState.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsState.swift diff --git a/Addame/Addame/Sources/EventDetailsView/EventDetailsView.swift b/AddameSPM/Sources/EventDetailsView/EventDetailsView.swift similarity index 99% rename from Addame/Addame/Sources/EventDetailsView/EventDetailsView.swift rename to AddameSPM/Sources/EventDetailsView/EventDetailsView.swift index 81ceb81..c771ba0 100644 --- a/Addame/Addame/Sources/EventDetailsView/EventDetailsView.swift +++ b/AddameSPM/Sources/EventDetailsView/EventDetailsView.swift @@ -11,7 +11,7 @@ import ComposableArchitecture import ComposableArchitectureHelpers import ComposableCoreLocation import ConversationClient -import HttpRequest +import HTTPRequestKit import KeychainService import MapKit import MapView diff --git a/Addame/Addame/Sources/EventFormView/EventFormAction.swift b/AddameSPM/Sources/EventFormView/EventFormAction.swift similarity index 95% rename from Addame/Addame/Sources/EventFormView/EventFormAction.swift rename to AddameSPM/Sources/EventFormView/EventFormAction.swift index a91fedb..544b0e3 100644 --- a/Addame/Addame/Sources/EventFormView/EventFormAction.swift +++ b/AddameSPM/Sources/EventFormView/EventFormAction.swift @@ -7,7 +7,7 @@ import ComposableArchitecture import Foundation -import HttpRequest +import HTTPRequestKit import MapKit import MapView import SharedModels @@ -25,7 +25,7 @@ public enum EventFormAction: Equatable { case liveLocationToggleChanged(Bool) case isSearchSheet(isPresented: Bool) case locationSearch(LocationSearchAction) - case eventsResponse(Result) + case eventsResponse(Result) case backToPVAfterCreatedEventSuccessfully case submitButtonTapped diff --git a/Addame/Addame/Sources/EventFormView/EventFormEnvironment.swift b/AddameSPM/Sources/EventFormView/EventFormEnvironment.swift similarity index 76% rename from Addame/Addame/Sources/EventFormView/EventFormEnvironment.swift rename to AddameSPM/Sources/EventFormView/EventFormEnvironment.swift index ed25306..1e0d2d0 100644 --- a/Addame/Addame/Sources/EventFormView/EventFormEnvironment.swift +++ b/AddameSPM/Sources/EventFormView/EventFormEnvironment.swift @@ -22,3 +22,10 @@ public struct EventFormEnvironment { self.mainQueue = mainQueue } } + +extension EventFormEnvironment { + public static let live: EventFormEnvironment = .init( + eventClient: .live(api: .build), + mainQueue: .main + ) +} diff --git a/Addame/Addame/Sources/EventFormView/EventFormReducer.swift b/AddameSPM/Sources/EventFormView/EventFormReducer.swift similarity index 90% rename from Addame/Addame/Sources/EventFormView/EventFormReducer.swift rename to AddameSPM/Sources/EventFormView/EventFormReducer.swift index ec87229..e613c09 100644 --- a/Addame/Addame/Sources/EventFormView/EventFormReducer.swift +++ b/AddameSPM/Sources/EventFormView/EventFormReducer.swift @@ -6,8 +6,9 @@ // import ComposableArchitecture +import ComposablePresentation import Foundation -import HttpRequest +import HTTPRequestKit import KeychainService import MapView import SharedModels @@ -72,6 +73,7 @@ public let eventFormReducer = Reducer< return .none } + state.isPostRequestOnFly = true let event = Event( name: state.title, details: "", @@ -88,7 +90,6 @@ public let eventFormReducer = Reducer< // selectedPlace.coordinatesMongoDouble ) - state.isPostRequestOnFly = true return environment.eventClient .create(event, "") .retry(3) @@ -96,22 +97,23 @@ public let eventFormReducer = Reducer< .catchToEffect(EventFormAction.eventsResponse) case .actionSheetButtonTapped: - let cancel = ActionSheetState.Button.cancel() - var alertButtons: [ActionSheetState.Button] = Categories.allCases.enumerated() + // menu context please + state.actionSheet = .init( + title: .init("Categories"), + message: .init("Select your category."), + buttons: [.cancel(.init("Cancel"))] + ) + + state.actionSheet?.buttons = Categories + .allCases.enumerated() .map { _, item in .default( .init("\(item.rawValue)"), action: .send(.selectedCategories(item)) ) } - alertButtons.append(cancel) - state.actionSheet = .init( - title: .init("Action sheet"), - message: .init("This is an action sheet."), - buttons: alertButtons - ) return .none case .actionSheetCancelTapped: @@ -168,11 +170,10 @@ public let eventFormReducer = Reducer< return .none } } -.presents( +.debug() +.presenting( locationSearchReducer, state: \.locationSearchState, action: /EventFormAction.locationSearch, - environment: { _ in - LocationEnvironment(localSearch: .live, mainQueue: .immediate) - } + environment: { _ in LocationEnvironment.live } ) diff --git a/Addame/Addame/Sources/EventFormView/EventFormState.swift b/AddameSPM/Sources/EventFormView/EventFormState.swift similarity index 87% rename from Addame/Addame/Sources/EventFormView/EventFormState.swift rename to AddameSPM/Sources/EventFormView/EventFormState.swift index 273ab40..466963a 100644 --- a/Addame/Addame/Sources/EventFormView/EventFormState.swift +++ b/AddameSPM/Sources/EventFormView/EventFormState.swift @@ -13,10 +13,20 @@ import MapView import SharedModels extension EventFormState { - public static let eventFormPlacholder = Self( + public static let validEventForm = Self( title: "Walk around", - isPostRequestOnFly: true, - isEventCreatedSuccessfully: true + durationRawValue: "7200", + categoryRawValue: "General", + eventAddress: "188839, Первомайское, СНТ Славино-2 Поселок, 31 Первомайское Россия", isPostRequestOnFly: false, + isEventCreatedSuccessfully: false + ) + + public static let inValidEventForm = Self( + title: "Walk around Walk around Walk around Walk around Walk around", + durationRawValue: "4hr", + categoryRawValue: "General", + isPostRequestOnFly: false, + isEventCreatedSuccessfully: false ) } @@ -37,7 +47,7 @@ public struct EventFormState: Equatable { selectedDutaionButtons: DurationButtons = .FourHours, durations: [String] = DurationButtons.allCases.map { $0.rawValue }, catagories: [String] = Categories.allCases.map { $0.rawValue }, - actionSheet: ActionSheetState? = nil, + actionSheet: ConfirmationDialogState? = nil, alert: AlertState? = nil, locationSearchState _: LocationSearchState? = nil, isPostRequestOnFly: Bool = false, @@ -101,7 +111,7 @@ public struct EventFormState: Equatable { public var durations = DurationButtons.allCases.map { $0.rawValue } public var catagories = Categories.allCases.map { $0.rawValue } - public var actionSheet: ActionSheetState? + public var actionSheet: ConfirmationDialogState? public var alert: AlertState? public var locationSearchState: LocationSearchState? @@ -130,8 +140,6 @@ extension EventFormState { currentPlace: currentPlace, eventAddress: eventAddress, selectedDutaionButtons: selectedDutaionButtons, - durations: durations, - catagories: catagories, actionSheet: actionSheet, alert: alert, locationSearchState: locationSearchState, diff --git a/Addame/Addame/Sources/EventFormView/EventFormView.swift b/AddameSPM/Sources/EventFormView/EventFormView.swift similarity index 85% rename from Addame/Addame/Sources/EventFormView/EventFormView.swift rename to AddameSPM/Sources/EventFormView/EventFormView.swift index 1ab50e3..0dac635 100644 --- a/Addame/Addame/Sources/EventFormView/EventFormView.swift +++ b/AddameSPM/Sources/EventFormView/EventFormView.swift @@ -7,11 +7,12 @@ import Combine import ComposableArchitecture +import ComposablePresentation import ComposableArchitectureHelpers import EventClient import EventClientLive import Foundation -import HttpRequest +import HTTPRequestKit import KeychainService import MapKit import MapView @@ -21,7 +22,7 @@ import SwiftUIExtension extension EventFormView { public struct ViewState: Equatable { - public var title = String.empty + public var title = "" public var textFieldHeight: CGFloat = 30 public var durationRawValue: String = DurationButtons.FourHours.rawValue public var categoryRawValue: String = Categories.General.rawValue @@ -44,10 +45,7 @@ extension EventFormView { public var currentPlace: EventResponse.Item? public var eventAddress: String = "" public var selectedDutaionButtons: DurationButtons = .FourHours - - public var durations = DurationButtons.allCases.map { $0.rawValue } - public var catagories = Categories.allCases.map { $0.rawValue } - public var actionSheet: ActionSheetState? + public var actionSheet: ConfirmationDialogState? public var alert: AlertState? public var locationSearchState: LocationSearchState? public var isPostRequestOnFly: Bool = false @@ -100,11 +98,17 @@ public struct EventFormView: View { ) ) { viewStore in ZStack(alignment: viewStore.state.isEventCreatedSuccessfully ? .top : .bottomTrailing) { + if viewStore.state.isPostRequestOnFly { ProgressView() } Form { + + Text("Create Event Form") + .font(.title) + .frame(maxWidth: .infinity, alignment: .center) + Section { HStack { TextField( @@ -115,7 +119,7 @@ public struct EventFormView: View { ) ) .padding(5) - .font(Font.system(size: 15, weight: .medium, design: .serif)) + .font(Font.system(size: 25, weight: .medium, design: .serif)) // .hideKeyboardOnTap() .lineLimit(3) // .background( @@ -125,7 +129,7 @@ public struct EventFormView: View { // ) .foregroundColor(Color(UIColor.systemRed)) .accentColor(Color.green) - .textFieldStyle(.roundedBorder) +// .textFieldStyle(.roundedBorder) .overlay( RoundedRectangle(cornerRadius: 10) .stroke(Color.gray, lineWidth: 1) @@ -175,21 +179,25 @@ public struct EventFormView: View { .foregroundColor( Color( #colorLiteral( - red: 0.9154241085, green: 0.2969468832, blue: 0.2259359956, alpha: 1))) + red: 0.9154241085, + green: 0.2969468832, + blue: 0.2259359956, + alpha: 1) + ) + ) } .padding(.vertical) } - .actionSheet( + .confirmationDialog( self.store.scope(state: \.actionSheet), dismiss: .actionSheetDismissed ) Toggle( - isOn: - viewStore.binding( - get: \.liveLocationToggleisOn, - send: ViewAction.liveLocationToggleChanged - ) + isOn: viewStore.binding( + get: \.liveLocationToggleisOn, + send: ViewAction.liveLocationToggleChanged + ) ) { HStack { VStack(alignment: .leading) { @@ -223,34 +231,20 @@ public struct EventFormView: View { sendButton(viewStore) } } - + .alert(self.store.scope(state: { $0.alert }), dismiss: .alertDismissed) .navigationTitle("Event Form") .navigationBarTitleDisplayMode(.inline) .onAppear { viewStore.send(.didAppear) } - .onDisappear { - viewStore.send(.didDisappear) - } .sheet( - isPresented: - viewStore.binding( - get: { $0.isSheetPresented }, - send: EventFormView.ViewAction.isSearchSheet(isPresented:) - ) - ) { - IfLetStore( - self.store.scope( - state: { $0.locationSearchState }, - action: EventFormAction.locationSearch - ), - then: LocationSearchView.init(store:) - ) - } - .alert(self.store.scope(state: { $0.alert }), dismiss: .alertDismissed) + store.scope(state: \.locationSearchState, action: EventFormAction.locationSearch), + mapState: replayNonNil(), + onDismiss: { ViewStore(store.stateless).send(.isSearchSheet(isPresented: true)) }, + content: LocationSearchView.init(store:) + ) .edgesIgnoringSafeArea(.all) } - .debug("EventFormView") } fileprivate func sendButton( @@ -273,6 +267,7 @@ public struct EventFormView: View { } .font(.system(size: 26, weight: .bold, design: .rounded)) .padding(10) + } else { Image(systemName: "dot.circle") .foregroundColor(.white) @@ -283,11 +278,18 @@ public struct EventFormView: View { .background(viewStore.state.isAllFeildsAreValid ? Color.blue : Color.red) .clipShape(viewStore.state.isAllFeildsAreValid ? AnyShape(Capsule()) : AnyShape(Circle())) .animation(.default) - .disabled(!viewStore.state.isAllFeildsAreValid) + .disabled(!viewStore.state.isAllFeildsAreValid && viewStore.isPostRequestOnFly) + .opacity(viewStore.isPostRequestOnFly ? 0 : 1) + .overlay( + ActivityIndicator() + .frame(maxWidth: .infinity) + .padding() + .opacity(viewStore.isPostRequestOnFly ? 1 : 0) + ) .padding() - .padding(.bottom, 55) + .padding(.bottom, 16) + } - .padding() } fileprivate func successfullyCreatedNoticeView( @@ -320,7 +322,7 @@ public struct EventFormView: View { struct EventFormView_Previews: PreviewProvider { static let store = Store( - initialState: EventFormState.eventFormPlacholder, + initialState: EventFormState.validEventForm, reducer: eventFormReducer, environment: EventFormEnvironment( eventClient: .empty, @@ -329,11 +331,11 @@ struct EventFormView_Previews: PreviewProvider { ) static var previews: some View { - NavigationView { + Text("Background").sheet(isPresented: .constant(true)) { EventFormView(store: store) // .redacted(reason: .placeholder) // .redacted(reason: EventsState.events.isLoadingPage ? .placeholder : []) - .environment(\.colorScheme, .dark) +// .environment(\.colorScheme, .dark) } } } diff --git a/AddameSPM/Sources/EventView/EventRowView.swift b/AddameSPM/Sources/EventView/EventRowView.swift new file mode 100644 index 0000000..ffdf273 --- /dev/null +++ b/AddameSPM/Sources/EventView/EventRowView.swift @@ -0,0 +1,123 @@ +// +// EventRowView.swift +// +// +// Created by Saroar Khandoker on 20.09.2021. +// + +import AsyncImageLoder +import ChatView +import ComposableArchitecture +import ComposableArchitectureHelpers +import ComposableCoreLocation +import MapKit +import SharedModels +import SwiftUI +import SwiftUIExtension + +public struct EventRowView: View { + let currentLocation: Location? + @Environment(\.colorScheme) var colorScheme + + public let store: Store + + public init( + store: Store, + currentLocation: Location? + ) { + self.currentLocation = currentLocation + self.store = store + } + + public var body: some View { + WithViewStore(self.store) { viewStore in + HStack { + if viewStore.imageUrl != nil { + AsyncImage( + urlString: viewStore.imageUrl, + placeholder: { Text("Loading...").frame(width: 100, height: 100, alignment: .center) }, + image: { + Image(uiImage: $0).resizable() + } + ) + .aspectRatio(contentMode: .fit) + .frame(width: 120) + .padding(.trailing, 15) + .cornerRadius(radius: 10, corners: [.topLeft, .bottomLeft]) + } else { + Image(systemName: "photo") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 90) + .padding(10) + .cornerRadius(radius: 10, corners: [.topLeft, .bottomLeft]) + } + + VStack(alignment: .leading) { + Text(viewStore.name) + .foregroundColor(colorScheme == .dark ? Color.white : Color.black) + .lineLimit(2) + .alignmentGuide(.leading) { viewDimensions in viewDimensions[.leading] } + .font(.system(size: 23, weight: .light, design: .rounded)) + .padding(.top, 10) + .padding(.bottom, 5) + + Text(viewStore.addressName) + .lineLimit(2) + .alignmentGuide(.leading) { viewDimensions in viewDimensions[.leading] } + .font(.system(size: 15, weight: .light, design: .rounded)) + .foregroundColor(.blue) + .padding(.bottom, 5) + + Spacer() + HStack { + Spacer() + Text(" \(viewStore.distance?.meterTOmiles ?? "0.0")") + .lineLimit(2) + .alignmentGuide(.leading) { viewDimensions in viewDimensions[.leading] } + .font(.system(size: 15, weight: .light, design: .rounded)) + .foregroundColor(.blue) + .padding(.bottom, 10) + } + .padding(.bottom, 5) + } + + Spacer() + } + .background( + RoundedRectangle(cornerRadius: 10) + .foregroundColor( + colorScheme == .dark + ? Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)) + : Color( + #colorLiteral( + red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 0.5))) + ) + .padding([.leading, .trailing], 10) + .padding([.top, .bottom], 5) + } + } +} + +extension Double { + var meterTOkilometers: String { + return String(format: "%.02f km away", self / 1000) + } + + var meterTOmiles: String { + return String(format: "%.02f miles away", self / 1609) + } +} + +// struct EventRowView_Previews: PreviewProvider { +// +// static let store: Store = .init( +// initialState: EventsState.event, +// reducer: eventsReducer, +// environment: EventsEnvironment.happyPath +// ) +// +// static var previews: some View { +// EventRowView(store: store, currentLocation: EventsState.eventForRow.location) +// } +// } diff --git a/Addame/Addame/Sources/EventView/EventView.swift b/AddameSPM/Sources/EventView/EventView.swift similarity index 55% rename from Addame/Addame/Sources/EventView/EventView.swift rename to AddameSPM/Sources/EventView/EventView.swift index 40ce186..2c7eca6 100644 --- a/Addame/Addame/Sources/EventView/EventView.swift +++ b/AddameSPM/Sources/EventView/EventView.swift @@ -3,13 +3,16 @@ import ChatView import ComposableArchitecture import ComposableArchitectureHelpers import ComposableCoreLocation +import ComposablePresentation import EventDetailsView import EventFormView -import HttpRequest +import HTTPRequestKit import MapKit import SharedModels import SwiftUI import SwiftUIExtension +import AdSupport +import AppTrackingTransparency extension EventView { public struct ViewState: Equatable { @@ -19,6 +22,8 @@ extension EventView { public var waitingForUpdateLocation = true public var isLoadingPage = false public var isMovingChatRoom: Bool = false + public var isEFromNavigationActive: Bool = false + public var isIDFAAuthorized = false public var location: Location? public var events: IdentifiedArrayOf = [] public var myEvents: IdentifiedArrayOf = [] @@ -38,6 +43,7 @@ extension EventView { case event(index: EventResponse.Item.ID, action: EventAction) + case fetchEventOnAppear case eventFormView(isNavigate: Bool) case eventForm(EventFormAction) @@ -51,6 +57,8 @@ extension EventView { case currentLocationButtonTapped case eventTapped(EventResponse.Item) + + case idfaAuthorizationStatus(ATTrackingManager.AuthorizationStatus) case popupSettings case dismissEvent case onAppear @@ -86,19 +94,20 @@ public struct EventView: View { ScrollView { LazyVStack { if viewStore.waitingForUpdateLocation { - VStack { + HStack { ActivityIndicator() - .frame(maxWidth: .infinity) - .padding() - .padding(.top, 20) + .padding(.leading, 5) if viewStore.isLoadingPage { Text("Now fetching near by Hanghouts!") - .frame(maxWidth: .infinity) + .font(.system(.body, design: .rounded)) + .frame(maxWidth: .infinity, alignment: .leading) .padding() .animation(.easeOut) + .layoutPriority(1) + } - } else if viewStore.waitingForUpdateLocation { + if viewStore.waitingForUpdateLocation { Text("Please wait we are updating your current location!") .font(.body) .frame(maxWidth: .infinity) @@ -112,6 +121,36 @@ public struct EventView: View { .padding() } + if !viewStore.isIDFAAuthorized { + VStack { + Text(""" + App can't work without your data Permission. + We don't use your data for marketing purpose or send any 3rd party. + You cant change permission anytime from app settings + """ + ).font(.body) + .frame(maxWidth: .infinity) + .padding() + .padding(.bottom, 10) + .animation(.easeIn) + + Button { + viewStore.send(.popupSettings) + } label: { + + Label("Go to settings", systemImage: "gear") + .padding(10.0) + .overlay( + RoundedRectangle(cornerRadius: 10.0) + .stroke(lineWidth: 2.0) + ) + .foregroundColor(.red) + } + + } + + } + EventsListView( store: viewStore.isLoadingPage ? Store( @@ -124,6 +163,7 @@ public struct EventView: View { .redacted(reason: viewStore.isLoadingPage ? .placeholder : []) } } + .navigationTitle("Events") .background(colorScheme == .dark ? Color.gray.edgesIgnoringSafeArea(.all) : nil) HStack { @@ -147,49 +187,47 @@ public struct EventView: View { color: viewStore.state.isLocationAuthorized ? Color.green : Color.red, radius: 20, y: 5) } } + .onAppear { + ViewStore(store.stateless).send(.onAppear) + } + .navigationViewStyle(StackNavigationViewStyle()) .navigationBarTitleDisplayMode(.automatic) .toolbar { ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) { toolbarItemTrailingButton(viewStore) } } - .navigationTitle("Events") .alert(self.store.scope(state: { $0.alert }), dismiss: .alertDismissed) - .sheet( - isPresented: - viewStore.binding( - get: { $0.isEventDetailsSheetPresented }, - send: EventView.ViewAction.eventDetailsView(isPresented:) - ) - ) { - IfLetStore( - self.store.scope( - state: { $0.eventDetailsState }, - action: EventsAction.eventDetails - ), - then: EventDetailsView.init(store:) - ) - } } - .navigate( - using: store.scope( - state: \.eventFormState, - action: EventsAction.eventForm - ), - destination: EventFormView.init(store:), + .sheet( + store.scope(state: \.eventDetailsState, action: EventsAction.eventDetails), + mapState: replayNonNil(), onDismiss: { - ViewStore(store.stateless).send(.eventFormView(isNavigate: false)) - } + ViewStore(store.stateless).send(.eventDetailsView(isPresented: false)) + }, + content: EventDetailsView.init(store:) ) - .navigate( - using: store.scope( - state: \.chatState, - action: EventsAction.chat - ), - destination: ChatView.init(store:), - onDismiss: { - ViewStore(store.stateless).send(.chatView(isNavigate: false)) - } + .sheet( + store.scope(state: \.eventFormState, action: EventsAction.eventForm), + mapState: replayNonNil(), + onDismiss: { ViewStore(store.stateless).send(.eventFormView(isNavigate: false)) }, + content: EventFormView.init(store:) + ) +// .navigationLink( +// store.scope(state: \.eventFormState, action: EventsAction.eventForm), +// state: replayNonNil(), +// onDismiss: { +// ViewStore(store.stateless).send(.eventFormView(isNavigate: false)) +// }, +// destination: EventFormView.init(store:) +// ) + .background( + NavigationLinkWithStore( + store.scope(state: \.chatState, action: EventsAction.chat), + mapState: replayNonNil(), + onDeactivate: { ViewStore(store.stateless).send(.chatView(isNavigate: false)) }, + destination: ChatView.init(store:) + ) ) } @@ -202,56 +240,34 @@ public struct EventView: View { if #available(iOS 15.0, *) { Image(systemName: "plus.circle") .font(.title) - // .foregroundColor( - // viewStore.state.isLocationAuthorized ? Color.black : Color.gray - // ) .foregroundColor(colorScheme == .dark ? .white : .blue) .opacity(viewStore.isEventDetailsSheetPresented ? 0 : 1) - .overlay { - if viewStore.isEventDetailsSheetPresented { - ProgressView() - .frame(width: 150.0, height: 150.0) - .padding(50.0) - } - } + .overlay( + ProgressView() + .frame(width: 150.0, height: 150.0) + .padding(50.0) + .opacity(viewStore.isEventDetailsSheetPresented ? 1 : 0) + ) } else { Image(systemName: "plus.circle") .font(.title) .foregroundColor(viewStore.state.isLocationAuthorized ? Color.black : Color.gray) } } - .disabled(viewStore.state.placeMark == nil) - .opacity(viewStore.state.placeMark == nil ? 0 : 1) + .disabled(viewStore.state.placeMark == nil || !viewStore.isIDFAAuthorized ) + .opacity(viewStore.state.placeMark == nil || !viewStore.isIDFAAuthorized ? 0 : 1) } } struct EventView_Previews: PreviewProvider { - static let environment = EventsEnvironment( - pathMonitorClient: .satisfied, - locationManager: .live, - eventClient: .happyPath, - backgroundQueue: .immediate, - mainQueue: .immediate, - userDefaults: .noop - ) static let store = Store( - initialState: EventsState.placeholderEvents, - reducer: eventReducer, - environment: environment + initialState: EventsState.fetchEvents, + reducer: eventsReducer, + environment: EventsEnvironment.happyPath ) static var previews: some View { - // TabView { - // NavigationView { - - // EventView(store: store) - // .redacted(reason: .placeholder) - // .redacted(reason: EventsState.events.isLoadingPage ? .placeholder : []) - // .environment(\.colorScheme, .dark) - // } - // } - // Group { TabView { NavigationView { @@ -298,93 +314,3 @@ struct EventsListView: View { } } } - -public struct EventRowView: View { - let currentLocation: Location? - @Environment(\.colorScheme) var colorScheme - - public let store: Store - - public init(store: Store, currentLocation: Location?) { - self.currentLocation = currentLocation - self.store = store - } - - public var body: some View { - WithViewStore(self.store) { viewStore in - HStack { - if viewStore.imageUrl != nil { - AsyncImage( - urlString: viewStore.imageUrl, - placeholder: { Text("Loading...").frame(width: 100, height: 100, alignment: .center) }, - image: { - Image(uiImage: $0).resizable() - } - ) - .aspectRatio(contentMode: .fit) - .frame(width: 120) - .padding(.trailing, 15) - .cornerRadius(radius: 10, corners: [.topLeft, .bottomLeft]) - } else { - Image(systemName: "photo") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 90) - .padding(10) - .cornerRadius(radius: 10, corners: [.topLeft, .bottomLeft]) - } - - VStack(alignment: .leading) { - Text(viewStore.name) - .foregroundColor(colorScheme == .dark ? Color.white : Color.black) - .lineLimit(2) - .alignmentGuide(.leading) { viewDimensions in viewDimensions[.leading] } - .font(.system(size: 23, weight: .light, design: .rounded)) - .padding(.top, 10) - .padding(.bottom, 5) - - Text(viewStore.addressName) - .lineLimit(2) - .alignmentGuide(.leading) { viewDimensions in viewDimensions[.leading] } - .font(.system(size: 15, weight: .light, design: .rounded)) - .foregroundColor(.blue) - .padding(.bottom, 5) - - Spacer() - HStack { - Spacer() - Text(" \(viewStore.distance?.meterTOmiles ?? "0.0")") - .lineLimit(2) - .alignmentGuide(.leading) { viewDimensions in viewDimensions[.leading] } - .font(.system(size: 15, weight: .light, design: .rounded)) - .foregroundColor(.blue) - .padding(.bottom, 10) - } - .padding(.bottom, 5) - } - - Spacer() - } - .background( - RoundedRectangle(cornerRadius: 10) - .foregroundColor( - colorScheme == .dark - ? Color(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)) - : Color( - #colorLiteral( - red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 0.5))) - ) - .padding(10) - } - } -} - -extension Double { - var meterTOkilometers: String { - return String(format: "%.02f km away", self / 1000) - } - - var meterTOmiles: String { - return String(format: "%.02f miles away", self / 1609) - } -} diff --git a/Addame/Addame/Sources/EventView/EventsAction.swift b/AddameSPM/Sources/EventView/EventsAction.swift similarity index 80% rename from Addame/Addame/Sources/EventView/EventsAction.swift rename to AddameSPM/Sources/EventView/EventsAction.swift index ebb8d97..4413859 100644 --- a/Addame/Addame/Sources/EventView/EventsAction.swift +++ b/AddameSPM/Sources/EventView/EventsAction.swift @@ -11,9 +11,13 @@ import ComposableCoreLocation import EventDetailsView import EventFormView import Foundation -import HttpRequest +import HTTPRequestKit import MapKit import SharedModels +import AdSupport +import AppTrackingTransparency + +public enum EventAction: Equatable {} public enum EventsAction: Equatable { case alertDismissed @@ -30,22 +34,23 @@ public enum EventsAction: Equatable { case chatView(isNavigate: Bool) case chat(ChatAction) + case fetchEventOnAppear case fetchMoreEventsIfNeeded(item: EventResponse.Item?) case addressResponse(Result) case currentLocationButtonTapped case locationManager(LocationManager.Action) - case eventsResponse(Result) - case eventCoordinate(Result) + case eventsResponse(Result) + case eventPlacemarkResponse(Result) case eventTapped(EventResponse.Item) + case idfaAuthorizationStatus(ATTrackingManager.AuthorizationStatus) + case popupSettings case dismissEvent case onAppear } -public enum EventAction: Equatable {} - // swiftlint:disable:next superfluous_disable_command extension EventsAction { // swiftlint:disable:next cyclomatic_complexity function_body_length superfluous_disable_command @@ -56,9 +61,9 @@ extension EventsAction { case .dismissEventDetails: return .dismissEventDetails case let .eventFormView(active): - return .eventFormView(isNavigate: active) + return self.eventFormView(isNavigate: active) case let .eventForm(eventFormAction): - return eventForm(eventFormAction) + return self.eventForm(eventFormAction) case let .chatView(isNavigate: bool): return .chatView(isNavigate: bool) case let .chat(action): @@ -73,6 +78,8 @@ extension EventsAction { return popupSettings case .dismissEvent: return .dismissEvent + case .fetchEventOnAppear: + return .fetchEventOnAppear case .onAppear: return .onAppear case let .eventDetailsView(isPresented: isPresented): @@ -81,6 +88,8 @@ extension EventsAction { return .eventDetails(action) case let .fetchMoreEventsIfNeeded(item: item): return .fetchMoreEventsIfNeeded(item: item) + case .idfaAuthorizationStatus(let status): + return .idfaAuthorizationStatus(status) } } } diff --git a/Addame/Addame/Sources/EventView/EventsEnvironment.swift b/AddameSPM/Sources/EventView/EventsEnvironment.swift similarity index 65% rename from Addame/Addame/Sources/EventView/EventsEnvironment.swift rename to AddameSPM/Sources/EventView/EventsEnvironment.swift index fcbb67b..b5aeabe 100644 --- a/Addame/Addame/Sources/EventView/EventsEnvironment.swift +++ b/AddameSPM/Sources/EventView/EventsEnvironment.swift @@ -10,16 +10,21 @@ import ComposableArchitecture import ComposableCoreLocation import Contacts import EventClient +import EventClientLive import PathMonitorClient +import PathMonitorClientLive import UserDefaultsClient +import IDFAClient +import IDFAClientLive public struct EventsEnvironment { let pathMonitorClient: PathMonitorClient - var locationManager: LocationManager + let locationManager: LocationManager let eventClient: EventClient public var backgroundQueue: AnySchedulerOf public var mainQueue: AnySchedulerOf public var userDefaults: UserDefaultsClient + var idfaClient: IDFAClient public init( pathMonitorClient: PathMonitorClient, @@ -27,7 +32,8 @@ public struct EventsEnvironment { eventClient: EventClient, backgroundQueue: AnySchedulerOf, mainQueue: AnySchedulerOf, - userDefaults: UserDefaultsClient + userDefaults: UserDefaultsClient, + idfaClient: IDFAClient ) { self.pathMonitorClient = pathMonitorClient self.locationManager = locationManager @@ -35,9 +41,10 @@ public struct EventsEnvironment { self.backgroundQueue = backgroundQueue self.mainQueue = mainQueue self.userDefaults = userDefaults + self.idfaClient = idfaClient } - func getCoordinate(_ location: Location) -> Effect { + func getPlacemark(_ location: Location) -> Effect { return Effect.future { callback in let address = CLGeocoder() address.reverseGeocodeLocation( @@ -60,3 +67,25 @@ public struct EventsEnvironment { } } } + +extension EventsEnvironment { + public static let live: EventsEnvironment = .init( + pathMonitorClient: .live(queue: .main), + locationManager: .live, + eventClient: .live(api: .build), + backgroundQueue: .main, + mainQueue: .main, + userDefaults: .live(), + idfaClient: .live + ) + + public static let happyPath: EventsEnvironment = .init( + pathMonitorClient: .satisfied, + locationManager: .live, + eventClient: .happyPath, + backgroundQueue: .immediate, + mainQueue: .immediate, + userDefaults: .noop, + idfaClient: .authorized + ) +} diff --git a/Addame/Addame/Sources/EventView/EventsReducer.swift b/AddameSPM/Sources/EventView/EventsReducer.swift similarity index 71% rename from Addame/Addame/Sources/EventView/EventsReducer.swift rename to AddameSPM/Sources/EventView/EventsReducer.swift index b4a8fea..b96ab1a 100644 --- a/Addame/Addame/Sources/EventView/EventsReducer.swift +++ b/AddameSPM/Sources/EventView/EventsReducer.swift @@ -5,45 +5,93 @@ // Created by Saroar Khandoker on 06.04.2021. // -import ChatClient -import ChatClientLive import ChatView import Combine import ComposableArchitecture import ComposableArchitectureHelpers import ComposableCoreLocation import Contacts -import ConversationClient -import ConversationClientLive -import EventClient -import EventClientLive import EventDetailsView import EventFormView -import HttpRequest +import HTTPRequestKit import MapKit import SharedModels import SwiftUI -import WebSocketClient -import WebSocketClientLive - -// swiftlint:disable file_length -struct Foo { - @AppStorage("isAuthorized") - public static var isAuthorized: Bool = false -} +import MapView struct LocationManagerId: Hashable {} +struct IDFAStatusId: Hashable {} -public let eventReducer = Reducer { +// swiftlint:disable superfluous_disable_command file_length +public let eventsReducer = Reducer { state, action, environment in - var fetchEvents: Effect { - guard state.isConnected, let location = state.location else { return .none } - state.location = location + var currentLocationButtonTapped: Effect { + guard environment.locationManager.locationServicesEnabled() else { + state.alert = .init(title: TextState("Location services are turned off.")) + state.waitingForUpdateLocation = false + return .none + } + + switch environment.locationManager.authorizationStatus() { + case .notDetermined: + state.isRequestingCurrentLocation = true + state.waitingForUpdateLocation = true + #if os(macOS) + return environment.locationManager + .requestAlwaysAuthorization() + .fireAndForget() + #else + return environment.locationManager + .requestWhenInUseAuthorization() + .fireAndForget() + #endif + + case .restricted: + state.alert = .init( + title: .init("Please give us access to your location in settings"), + message: .init("Please go to Settings and turn on the permissions"), + primaryButton: .cancel(.init("Cancel"), action: .send(.alertDismissed)), + secondaryButton: .default(.init("Go to Settings"), action: .send(.popupSettings)) + ) + state.waitingForUpdateLocation = false + return .none + + case .denied: + state.alert = .init( + title: .init("Please give us access to your location in settings"), + message: .init("Please go to Settings and turn on the permissions"), + primaryButton: .cancel(.init("Cancel"), action: .send(.alertDismissed)), + secondaryButton: .default(TextState("Go to Settings"), action: .send(.popupSettings)) + ) + state.waitingForUpdateLocation = false + return .none + + case .authorizedAlways, .authorizedWhenInUse: + state.isLocationAuthorized = true + state.isConnected = true + state.waitingForUpdateLocation = false + + return environment.locationManager.startUpdatingLocation() + .fireAndForget() + +// environment.locationManager +// .requestLocation() +// .fireAndForget() + + @unknown default: + return .none + } + } - guard !state.isLoadingPage, state.canLoadMorePages else { return .none } + var fetchEvents: Effect { + guard state.isConnected && state.canLoadMorePages, + let location = state.location + else { + return .none + } - // state.isLoadingPage = true + state.location = location let getDistanceType = environment.userDefaults.integerForKey("typee") let maxDistance = getDistanceType == 0 ? (250 * 1000) : (250 / 1.609) * 1609 @@ -82,11 +130,11 @@ public let eventReducer = Reducer .map(EventsAction.eventsResponse) } - func getLocation(_ location: Location) -> Effect { - return environment.getCoordinate(location) + func getPlacemark(_ location: Location) -> Effect { + return environment.getPlacemark(location) .receive(on: environment.mainQueue) .catchToEffect() - .map(EventsAction.eventCoordinate) + .map(EventsAction.eventPlacemarkResponse) } func presentChatView() -> Effect { @@ -98,43 +146,29 @@ public let eventReducer = Reducer } switch action { - case let .eventFormView(isNavigate: active): - guard - let placeMark = state.placeMark, - let location = placeMark.location - else { - // pop alert let user know about issue - return .none - } + case .onAppear: - state.eventFormState = - active - ? EventFormState( - placeMark: state.placeMark, - eventAddress: state.currentAddress, - eventCoordinate: location.coordinate - ) - : nil + return .merge( + environment.locationManager.delegate() + .map(EventsAction.locationManager) + .cancellable(id: LocationManagerId()), + + currentLocationButtonTapped, + environment.idfaClient.requestAuthorization() + .map(EventsAction.idfaAuthorizationStatus) + .cancellable(id: IDFAStatusId()) + ) + case .fetchEventOnAppear: + if state.isLocationAuthorized && state.isIDFAAuthorized { + return fetchEvents + } return .none case .dismissEvent: - return .none - case .onAppear: - - return .merge( - environment.locationManager - .create(id: LocationManagerId()) - .map(EventsAction.locationManager), - - environment.locationManager - .requestWhenInUseAuthorization(id: LocationManagerId()) - .fireAndForget() - ) - case .alertDismissed: state.alert = nil return .none @@ -162,11 +196,11 @@ public let eventReducer = Reducer state.isLoadingPage = false state.currentPage += 1 - let events = (state.events + eventArray.items) - // .uniqElemets() - // .sorted() - - state.events = .init(uniqueElements: events) + eventArray.items.forEach { + if !state.events.contains($0) { + state.events.append($0) + } + } return .none @@ -185,7 +219,8 @@ public let eventReducer = Reducer case let .addressResponse(.success(address)): return .none - case let .eventCoordinate(.success(placemark)): + case let .eventPlacemarkResponse(.success(placemark)): + let formatter = CNPostalAddressFormatter() guard let postalAddress = placemark.postalAddress else { // handle error here @@ -203,79 +238,51 @@ public let eventReducer = Reducer state.location = location return .merge( - fetchEvents, - getLocation(location) + Effect(value: .fetchEventOnAppear) + .receive(on: environment.mainQueue) + .eraseToEffect(), + getPlacemark(location) ) case .locationManager: return .none case .currentLocationButtonTapped: + return currentLocationButtonTapped - guard environment.locationManager.locationServicesEnabled() else { - state.alert = .init(title: TextState("Location services are turned off.")) - state.waitingForUpdateLocation = false - return .none - } - - switch environment.locationManager.authorizationStatus() { - case .notDetermined: - state.isRequestingCurrentLocation = true - state.waitingForUpdateLocation = false - #if os(macOS) - return environment.locationManager - .requestAlwaysAuthorization(id: LocationManagerId()) - .fireAndForget() - #else - return environment.locationManager - .requestWhenInUseAuthorization(id: LocationManagerId()) - .fireAndForget() - #endif - - case .restricted: - state.alert = .init( - title: .init("Please give us access to your location in settings"), - message: .init("Please go to Settings and turn on the permissions"), - primaryButton: .cancel(.init("Cancel"), action: .send(.alertDismissed)), - secondaryButton: .default(.init(""), action: .send(.popupSettings)) - ) - state.waitingForUpdateLocation = false - return .none + case .popupSettings: + UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) - case .denied: - state.alert = .init( - title: .init("Please give us access to your location in settings"), - message: .init("Please go to Settings and turn on the permissions"), - primaryButton: .cancel(.init("Cancel"), action: .send(.alertDismissed)), - secondaryButton: .default(TextState(""), action: .send(.popupSettings)) - ) - state.waitingForUpdateLocation = false - return .none + return .none - case .authorizedAlways, .authorizedWhenInUse: - state.isLocationAuthorized = true - state.isConnected = true - state.waitingForUpdateLocation = false + case .dismissEventDetails: + state.event = nil + state.eventDetailsState = nil + return .none - return environment.locationManager - .requestLocation(id: LocationManagerId()) - .fireAndForget() + case let .eventFormView(isNavigate: active): - @unknown default: + guard + let placeMark = state.placeMark, + let location = placeMark.location + else { + // pop alert let user know about issue return .none } - case .popupSettings: - // @available(iOSApplicationExtension, unavailable) - // if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) { - // UIApplication.shared.open(url, options: [:], completionHandler: nil) - // } + state.eventFormState = + active + ? EventFormState( + placeMark: state.placeMark, + eventAddress: state.currentAddress, + eventCoordinate: location.coordinate + ) + : nil return .none - case .dismissEventDetails: - state.event = nil - state.eventDetailsState = nil + case let .eventForm(.eventsResponse(.success(event))): + state.events.insert(event, at: 0) return .none case .eventForm(.backToPVAfterCreatedEventSuccessfully): @@ -337,53 +344,38 @@ public let eventReducer = Reducer case let .chatView(isNavigate: isNavigate): state.chatState = isNavigate ? ChatState(conversation: state.conversation) : nil return .none + case .idfaAuthorizationStatus(let status): + state.isIDFAAuthorized = state.isIDFAAuthorization(status) + return .none } } .combined( - with: - locationManagerReducer + with: locationManagerReducer .pullback(state: \.self, action: /EventsAction.locationManager, environment: { $0 }) ) -// .signpost() +.signpost() .debug() - -.presents( +.presenting( eventFormReducer, state: \.eventFormState, action: /EventsAction.eventForm, - environment: { - EventFormEnvironment( - eventClient: EventClient.live(api: .build), - mainQueue: $0.mainQueue - ) - } + environment: { _ in EventFormEnvironment.live } ) -.presents( +.presenting( chatReducer, state: \.chatState, action: /EventsAction.chat, - environment: { - ChatEnvironment( - chatClient: ChatClient.live(api: .build), - websocketClient: .live, - mainQueue: $0.mainQueue, - backgroundQueue: $0.backgroundQueue - ) - } + environment: { _ in ChatEnvironment.live } ) -.presents( +.presenting( eventDetailsReducer, state: \.eventDetailsState, action: /EventsAction.eventDetails, - environment: { - EventDetailsEnvironment( - conversationClient: ConversationClient.live(api: .build), - mainQueue: $0.mainQueue - ) - } + environment: { _ in EventDetailsEnvironment.live } ) +.debug() -public let locationManagerReducer = Reducer< +private let locationManagerReducer = Reducer< EventsState, LocationManager.Action, EventsEnvironment > { state, action, environment in @@ -393,14 +385,19 @@ public let locationManagerReducer = Reducer< state.isLocationAuthorized = true state.isConnected = true + state.waitingForUpdateLocation = false - return environment.locationManager - .requestLocation(id: LocationManagerId()) - .fireAndForget() + if state.isRequestingCurrentLocation { + return environment.locationManager + .startUpdatingLocation() + .fireAndForget() + } + return .none case .didChangeAuthorization(.denied), .didChangeAuthorization(.restricted): + state.waitingForUpdateLocation = false state.isLocationAuthorized = false state.isConnected = false @@ -408,46 +405,16 @@ public let locationManagerReducer = Reducer< title: TextState("Please give us access to your location so you can use our full features"), message: TextState("Please go to Settings and turn on the permissions"), primaryButton: .cancel(.init("Cancel"), action: .send(.alertDismissed)), - secondaryButton: .default(.init("Go Settings"), action: .send(.popupSettings)) + secondaryButton: .default(.init("Go to Settings"), action: .send(.popupSettings)) ) return .none case let .didUpdateLocations(locations): - return .none + state.isRequestingCurrentLocation = false - case .didChangeAuthorization(.notDetermined): - return .none - case let .didChangeAuthorization(status): - print(#line, status) - return .none - case let .didDetermineState(_, region: region): - print(#line, region) - return .none - case .didEnterRegion: - return .none - case .didExitRegion: return .none - case let .didFailRanging(beaconConstraint: beaconConstraint, error: error): - return .none - case .didFailWithError: - return .none - case .didFinishDeferredUpdatesWithError: - return .none - case .didPauseLocationUpdates: - return .none - case .didResumeLocationUpdates: - return .none - case let .didStartMonitoring(region: region): - return .none - case let .didUpdateHeading(newHeading: newHeading): - return .none - case let .didUpdateTo(newLocation: newLocation, oldLocation: oldLocation): - return .none - case .didVisit: - return .none - case let .monitoringDidFail(region: region, error: error): - return .none - case let .didRangeBeacons(_, satisfyingConstraint: satisfyingConstraint): + + default: return .none } } diff --git a/AddameSPM/Sources/EventView/EventsState.swift b/AddameSPM/Sources/EventView/EventsState.swift new file mode 100644 index 0000000..a797360 --- /dev/null +++ b/AddameSPM/Sources/EventView/EventsState.swift @@ -0,0 +1,213 @@ +// +// EventState.swift +// +// +// Created by Saroar Khandoker on 06.04.2021. +// + +import ChatView +import ComposableArchitecture +import ComposableCoreLocation +import EventDetailsView +import EventFormView +import MapKit +import SharedModels +import AppTrackingTransparency + +public struct EventsState: Equatable { + + public var alert: AlertState? + public var isConnected = true + public var isLocationAuthorized = false + public var isRequestingCurrentLocation = false + public var waitingForUpdateLocation = true + public var isLoadingPage = false + public var canLoadMorePages = true + public var isMovingChatRoom: Bool = false + public var isEFromNavigationActive = false + public var isIDFAAuthorized = false + + public var currentPage = 1 + public var currentAddress = "" + public var placeMark: CLPlacemark? + public var location: Location? + public var events: IdentifiedArrayOf = [] + public var myEvents: IdentifiedArrayOf = [] + public var event: EventResponse.Item? + public var conversation: ConversationResponse.Item? + + public var eventFormState: EventFormState? + public var eventDetailsState: EventDetailsState? + public var chatState: ChatState? + + public var isEventDetailsSheetPresented: Bool { eventDetailsState != nil } + + public init( + alert: AlertState? = nil, isConnected: Bool = true, + isLocationAuthorized: Bool = false, isRequestingCurrentLocation: Bool = false, + waitingForUpdateLocation: Bool = true, + isMovingChatRoom: Bool = false, + isEFromNavigationActive: Bool = false, + isIDFAAuthorized: Bool = false, + isLoadingPage: Bool = false, + canLoadMorePages: Bool = true, currentPage: Int = 1, + currentAddress: String = "", placeMark: CLPlacemark? = nil, + location: Location? = nil, events: IdentifiedArrayOf = [], + myEvents: IdentifiedArrayOf = [], event: EventResponse.Item? = nil, + eventFormState: EventFormState? = nil, + eventDetailsState: EventDetailsState? = nil, + chatState: ChatState? = nil + ) { + self.alert = alert + self.isConnected = isConnected + self.isLocationAuthorized = isLocationAuthorized + self.isRequestingCurrentLocation = isRequestingCurrentLocation + self.waitingForUpdateLocation = waitingForUpdateLocation + self.isLoadingPage = isLoadingPage + self.canLoadMorePages = canLoadMorePages + self.isMovingChatRoom = isMovingChatRoom + self.isEFromNavigationActive = isEFromNavigationActive + self.isIDFAAuthorized = isIDFAAuthorized + self.currentPage = currentPage + self.currentAddress = currentAddress + self.placeMark = placeMark + self.location = location + self.events = events + self.myEvents = myEvents + self.event = event + self.eventFormState = eventFormState + self.eventDetailsState = eventDetailsState + self.chatState = chatState + } + +} + +extension EventsState { + func isIDFAAuthorization(_ status: ATTrackingManager.AuthorizationStatus) -> Bool { + switch status { + case .notDetermined, .restricted, .denied: return false + case .authorized: return true + @unknown default: return false + } + } + +} + +extension EventsState { + var view: EventView.ViewState { + EventView.ViewState( + alert: alert, isConnected: isConnected, + isLocationAuthorized: isLocationAuthorized, + waitingForUpdateLocation: waitingForUpdateLocation, + isLoadingPage: isLoadingPage, + isMovingChatRoom: isMovingChatRoom, + isIDFAAuthorized: isIDFAAuthorized, + location: location, + events: events, myEvents: myEvents, + event: event, + placeMark: placeMark, + eventFormState: eventFormState, + eventDetailsState: eventDetailsState, + chatState: chatState, + conversation: conversation + ) + } +} + +// swiftlint:disable all +extension EventsState { + + public static let event: EventResponse.Item = .init( + id: "5fbfe53675a93bda87c7cb16", + name: "Cool :)", categories: "General", + imageUrl: + "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", + duration: 14400, + isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, + overlay: false, coordinates: [60.020532228306031, 30.388014239849944], createdAt: Date(), + updatedAt: Date() + ) + + private static let events: IdentifiedArrayOf = [ + .init( + id: "5fbfe53675a93bda87c7cb16", + name: "Cool :)", categories: "General", + imageUrl: + "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", + duration: 14400, + isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, + overlay: false, coordinates: [60.020532228306031, 30.388014239849944], createdAt: Date(), + updatedAt: Date()), + .init( + id: "5fbe8a8c8ba94be8a688324b", name: "Awesome 🤩 app", categories: "General", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, + overlay: false, coordinates: [60.020525506753494, 30.387988546891499], createdAt: Date(), + updatedAt: Date()), + .init( + id: "5fbea245b226053f0ece711c", name: "Bicycling 🚴🏽", categories: "LookingForAcompany", + imageUrl: + "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "9к5 улица Бутлерова Saint Petersburg, Saint Petersburg", type: "Point", + sponsored: false, overlay: false, coordinates: [60.00380571585201, 30.399472870547118], + createdAt: Date(), updatedAt: Date()), + .init( + id: "5fbea245b226053f0ece712c", name: "Walk Around 🚶🏽🚶🏼‍♀️", categories: "LookingForAcompany", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "188839, Первомайское, СНТ Славино-2 Поселок, 31 Первомайское Россия", + type: "Point", sponsored: false, overlay: false, + coordinates: [60.261340452875721, 29.873706166262373], createdAt: Date(), updatedAt: Date()), + ] + + public static let placeholderEvents = Self( + isConnected: true, + isLocationAuthorized: true, + waitingForUpdateLocation: false, + isLoadingPage: true, + location: Location( + altitude: 0, + coordinate: CLLocationCoordinate2D(latitude: 60.020532228306031, longitude: 30.388014239849944), + course: 0, + horizontalAccuracy: 0, + speed: 0, + timestamp: Date(timeIntervalSince1970: 0), + verticalAccuracy: 0 + ), + events: events + ) + public static let fetchEvents = Self( + isConnected: true, + isLocationAuthorized: true, + waitingForUpdateLocation: true, + isLoadingPage: false, + location: Location( + altitude: 0, + coordinate: CLLocationCoordinate2D(latitude: 60.020532228306031, longitude: 30.388014239849944), + course: 0, + horizontalAccuracy: 0, + speed: 0, + timestamp: Date(timeIntervalSince1970: 0), + verticalAccuracy: 0 + ), + events: events + ) + + + public static let eventForRow = Self( + waitingForUpdateLocation: false, + location: Location( + altitude: 0, + coordinate: CLLocationCoordinate2D(latitude: 60.020532228306031, longitude: 30.388014239849944), + course: 0, + horizontalAccuracy: 0, + speed: 0, + timestamp: Date(timeIntervalSince1970: 0), + verticalAccuracy: 0 + ), + event: event + ) + +} diff --git a/Addame/Addame/Sources/FoundationExtension/Array+RemoveDuplicate.swift b/AddameSPM/Sources/FoundationExtension/Array+RemoveDuplicate.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/Array+RemoveDuplicate.swift rename to AddameSPM/Sources/FoundationExtension/Array+RemoveDuplicate.swift diff --git a/Addame/Addame/Sources/FoundationExtension/Codable+Extension.swift b/AddameSPM/Sources/FoundationExtension/Codable+Extension.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/Codable+Extension.swift rename to AddameSPM/Sources/FoundationExtension/Codable+Extension.swift diff --git a/Addame/Addame/Sources/FoundationExtension/DataExtension.swift b/AddameSPM/Sources/FoundationExtension/DataExtension.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/DataExtension.swift rename to AddameSPM/Sources/FoundationExtension/DataExtension.swift diff --git a/Addame/Addame/Sources/FoundationExtension/Date/Date+Extension.swift b/AddameSPM/Sources/FoundationExtension/Date/Date+Extension.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/Date/Date+Extension.swift rename to AddameSPM/Sources/FoundationExtension/Date/Date+Extension.swift diff --git a/Addame/Addame/Sources/FoundationExtension/Date/DateFormatter+Extension.swift b/AddameSPM/Sources/FoundationExtension/Date/DateFormatter+Extension.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/Date/DateFormatter+Extension.swift rename to AddameSPM/Sources/FoundationExtension/Date/DateFormatter+Extension.swift diff --git a/Addame/Addame/Sources/FoundationExtension/FoundationExtension.swift b/AddameSPM/Sources/FoundationExtension/FoundationExtension.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/FoundationExtension.swift rename to AddameSPM/Sources/FoundationExtension/FoundationExtension.swift diff --git a/Addame/Addame/Sources/FoundationExtension/Image+Compress.swift b/AddameSPM/Sources/FoundationExtension/Image+Compress.swift similarity index 63% rename from Addame/Addame/Sources/FoundationExtension/Image+Compress.swift rename to AddameSPM/Sources/FoundationExtension/Image+Compress.swift index 54160c5..d25fea2 100644 --- a/Addame/Addame/Sources/FoundationExtension/Image+Compress.swift +++ b/AddameSPM/Sources/FoundationExtension/Image+Compress.swift @@ -41,35 +41,36 @@ extension UIImage { case highest = 1 } + private var isHeicSupported: Bool { + // swiftlint:disable force_cast + (CGImageDestinationCopyTypeIdentifiers() as! [String]).contains("public.heic") + } + public func compressImage(_ compressionQuality: JPEGQuality? = .medium) -> (Data?, String) { - var unsuported = false - var imageData = Data() - var imageFormat = "jpeg" - - do { - let data = try heicData(compressionQuality: compressionQuality!) - imageData = data - imageFormat = "heic" - } catch { - print("Error creating HEIC data: \(error.localizedDescription)") - unsuported = true - } - if unsuported == true { + if isHeicSupported { + do { + let data = try heicData(compressionQuality: compressionQuality!) + return (data, "heic") + } catch { + print("Error creating HEIC data: \(error.localizedDescription)") + } + } else { #if os(iOS) guard let data = jpegData(compressionQuality: compressionQuality!.rawValue) else { - return (nil, imageFormat) + return (nil, "") } - imageData = data + return (data, "jpeg") #elseif os(OSX) fatalError("Value of type 'NSImage' has no member 'jpegData'") #endif } - return (imageData, imageFormat) + return (nil, "") } + } extension UIImage { @@ -106,3 +107,20 @@ extension UIImage { return data as Data } } + +extension UIImage { + public func heicData2(compressionQuality: JPEGQuality) -> Data? { + let destinationData = NSMutableData() + + guard + let cgImage = self.cgImage, + let destination = CGImageDestinationCreateWithData(destinationData, AVFileType.heic as CFString, 1, nil) + else { return nil } + + let options = [kCGImageDestinationLossyCompressionQuality: compressionQuality] + CGImageDestinationAddImage(destination, cgImage, options as CFDictionary) + CGImageDestinationFinalize(destination) + + return destinationData as Data + } +} diff --git a/Addame/Addame/Sources/FoundationExtension/MongoDBID/IDGenerator.swift b/AddameSPM/Sources/FoundationExtension/MongoDBID/IDGenerator.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/MongoDBID/IDGenerator.swift rename to AddameSPM/Sources/FoundationExtension/MongoDBID/IDGenerator.swift diff --git a/Addame/Addame/Sources/FoundationExtension/RangeReplaceableCollection+AppendIfNotContains.swift b/AddameSPM/Sources/FoundationExtension/RangeReplaceableCollection+AppendIfNotContains.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/RangeReplaceableCollection+AppendIfNotContains.swift rename to AddameSPM/Sources/FoundationExtension/RangeReplaceableCollection+AppendIfNotContains.swift diff --git a/Addame/Addame/Sources/FoundationExtension/String+Extension.swift b/AddameSPM/Sources/FoundationExtension/String+Extension.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/String+Extension.swift rename to AddameSPM/Sources/FoundationExtension/String+Extension.swift diff --git a/Addame/Addame/Sources/FoundationExtension/String/String+CodingKey.swift b/AddameSPM/Sources/FoundationExtension/String/String+CodingKey.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/String/String+CodingKey.swift rename to AddameSPM/Sources/FoundationExtension/String/String+CodingKey.swift diff --git a/Addame/Addame/Sources/FoundationExtension/String/String+Data.swift b/AddameSPM/Sources/FoundationExtension/String/String+Data.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/String/String+Data.swift rename to AddameSPM/Sources/FoundationExtension/String/String+Data.swift diff --git a/Addame/Addame/Sources/FoundationExtension/String/String+Date.swift b/AddameSPM/Sources/FoundationExtension/String/String+Date.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/String/String+Date.swift rename to AddameSPM/Sources/FoundationExtension/String/String+Date.swift diff --git a/Addame/Addame/Sources/FoundationExtension/String/String+ReplaceCharcters.swift b/AddameSPM/Sources/FoundationExtension/String/String+ReplaceCharcters.swift similarity index 100% rename from Addame/Addame/Sources/FoundationExtension/String/String+ReplaceCharcters.swift rename to AddameSPM/Sources/FoundationExtension/String/String+ReplaceCharcters.swift diff --git a/AddameSPM/Sources/FoundationExtension/SwiftUIView/View+Extension+HideRowSeparatorModifier.swift b/AddameSPM/Sources/FoundationExtension/SwiftUIView/View+Extension+HideRowSeparatorModifier.swift new file mode 100644 index 0000000..1244c99 --- /dev/null +++ b/AddameSPM/Sources/FoundationExtension/SwiftUIView/View+Extension+HideRowSeparatorModifier.swift @@ -0,0 +1,6 @@ +// +// View+Extension+HideRowSeparatorModifier.swift +// AddaMeIOS +// +// Created by Saroar Khandoker on 27.10.2020. +// diff --git a/AddameSPM/Sources/IDFAClient/IDFAClient.swift b/AddameSPM/Sources/IDFAClient/IDFAClient.swift new file mode 100644 index 0000000..c921961 --- /dev/null +++ b/AddameSPM/Sources/IDFAClient/IDFAClient.swift @@ -0,0 +1,22 @@ +// +// IDFAClient.swift +// +// +// Created by Saroar Khandoker on 03.06.2022. +// + +import AdSupport +import AppTrackingTransparency +import Combine +import ComposableArchitecture + +public struct IDFAClient { + public typealias ATTrackingAuthorizationStatus = () -> Effect + public var requestAuthorization: ATTrackingAuthorizationStatus + + public init( + requestAuthorization: @escaping ATTrackingAuthorizationStatus + ) { + self.requestAuthorization = requestAuthorization + } +} diff --git a/AddameSPM/Sources/IDFAClient/Mocks.swift b/AddameSPM/Sources/IDFAClient/Mocks.swift new file mode 100644 index 0000000..27ecb39 --- /dev/null +++ b/AddameSPM/Sources/IDFAClient/Mocks.swift @@ -0,0 +1,58 @@ +// +// Mocks.swift +// +// +// Created by Saroar Khandoker on 04.06.2022. +// + +import AdSupport +import AppTrackingTransparency +import Combine + +@available(iOS 14, *) +extension IDFAClient { + public static let noop = Self( + requestAuthorization: { .none } + ) + + public static let authorized = Self( + requestAuthorization: { + .future { callBack in + callBack(.success(.authorized)) + } + } + ) + + public static let notDetermined = Self( + requestAuthorization: { + .future { callBack in + callBack(.success(.notDetermined)) + } + } + ) + + public static let restricted = Self( + requestAuthorization: { + .future { callBack in + callBack(.success(.restricted)) + } + } + ) + + public static let denied = Self( + requestAuthorization: { + .future { callBack in + callBack(.success(.denied)) + } + } + ) +} + +#if DEBUG + import XCTestDynamicOverlay +extension IDFAClient { + public static let failing = Self( + requestAuthorization: { .failing("\(Self.self).requestAuthorization is not implemented") } + ) +} // i think i dont need it as i dont have any delegate func +#endif diff --git a/AddameSPM/Sources/IDFAClientLive/Live.swift b/AddameSPM/Sources/IDFAClientLive/Live.swift new file mode 100644 index 0000000..5b95928 --- /dev/null +++ b/AddameSPM/Sources/IDFAClientLive/Live.swift @@ -0,0 +1,25 @@ +// +// IDFAClientLive.swift +// +// +// Created by Saroar Khandoker on 04.06.2022. +// + +import IDFAClient +import AdSupport +import AppTrackingTransparency +import Combine +import ComposableArchitecture + +@available(iOS 14, *) +extension IDFAClient { + public static let live = Self( + requestAuthorization: { + .future { callBack in + ATTrackingManager.requestTrackingAuthorization { status in + callBack(.success(status)) + } + } + } + ) +} diff --git a/AddameSPM/Sources/ImagePicker/ImagePicker.swift b/AddameSPM/Sources/ImagePicker/ImagePicker.swift new file mode 100644 index 0000000..5af6ac7 --- /dev/null +++ b/AddameSPM/Sources/ImagePicker/ImagePicker.swift @@ -0,0 +1,195 @@ +// +// ImagePicker.swift +// +// +// Created by Saroar Khandoker on 11.10.2021. +// + +import SwiftUI +import ComposableArchitecture +import PhotosUI + +import Combine + +extension PHPickerResult { + public struct ImageError: Error { + let message: String + } + + func loadImage() -> Future { + return Future { promise in + guard case let itemProvider = self.itemProvider, + itemProvider.canLoadObject(ofClass: UIImage.self) + else { + return promise(.failure(ImageError(message: "Unable to load image."))) + } + + itemProvider.loadObject(of: UIImage.self) { result in + switch result { + case let .success(image): + return promise(.success(image)) + case let .failure(error): + return promise(.failure( + ImageError(message: "\(error.localizedDescription) Asset is not an image.") + )) + } + } + } + } +} + +public struct ImagePickerState: Equatable { + public var showingImagePicker: Bool + public var image: UIImage? + + public init(showingImagePicker: Bool, image: UIImage? = nil) { + self.showingImagePicker = showingImagePicker + self.image = image + } +} + +public enum ImagePickerAction: Equatable { + public static func == (lhs: ImagePickerAction, rhs: ImagePickerAction) -> Bool { + return lhs.value == rhs.value + } + + // only for Equatable + var value: String? { + return String(describing: self).components(separatedBy: "(").first + } + + case setSheet(isPresented: Bool) + + case imagePicked(image: UIImage) + + case pickerResultReceived(result: PHPickerResult) + case picked(result: Result) +} + +public struct ImagePickerEnvironment { + public init() {} +} + +extension ImagePickerEnvironment { + public static let live: ImagePickerEnvironment = .init() +} + +public let imagePickerReducer = Reducer< + ImagePickerState, + ImagePickerAction, + ImagePickerEnvironment +> { + state, action, _ in + + switch action { + case let .setSheet(isPresented: presented): + state.showingImagePicker = presented + return .none + + case let .imagePicked(image: image): + state.image = image + return .none + + case let .pickerResultReceived(result: result): + + return result.loadImage() + .receive(on: DispatchQueue.main) + .catchToEffect(ImagePickerAction.picked(result:)) + + case let .picked(result: .success(image)): + state.image = image + return .none + + case .picked(result: .failure): + return .none + } +} +.debug() + +public struct ImagePicker: UIViewControllerRepresentable { + @Environment(\.presentationMode) var presentationMode + + let viewStore: ViewStore + + public init(store: Store) { + self.viewStore = ViewStore(store) + } + + public func makeUIViewController( + context: UIViewControllerRepresentableContext + ) -> some UIViewController { + var config = PHPickerConfiguration() + config.filter = PHPickerFilter.images + config.selectionLimit = 1 + + let picker = PHPickerViewController(configuration: config) + picker.delegate = context.coordinator + return picker + } + + public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} + + public func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + public class Coordinator: PHPickerViewControllerDelegate { + let parent: ImagePicker + + init(_ parent: ImagePicker) { + self.parent = parent + } + + public func picker( + _ picker: PHPickerViewController, + didFinishPicking results: [PHPickerResult] + ) { + + guard let result = results.first else { + parent.viewStore.send( + .picked(result: .failure(.init(message: "No image picked. or cancel button click"))) + ) + parent.presentationMode.wrappedValue.dismiss() + return + } + + parent.viewStore.send(.pickerResultReceived(result: result)) + + } + } +} + +extension NSItemProvider { + + func loadObject( + of type: Object.Type, + completionHandler: @escaping (Result) -> Void) { + self.loadObject(ofClass: type) { object, error in + if let error = error { + completionHandler(.failure(error)) + } else if let object = object as? Object { + completionHandler(.success(object)) + } else { + let error = NSError( + domain: NSItemProvider.errorDomain, + code: NSItemProvider.ErrorCode.unknownError.rawValue) + completionHandler(.failure(error)) + } + } + } + + func loadObjectPublisher(of type: Object.Type) -> AnyPublisher { + let subject = PassthroughSubject() + + self.loadObject(of: type) { result in + switch result { + case .success(let object): + subject.send(object) + case .failure(let error): + subject.send(completion: .failure(error)) + } + } + + return subject.eraseToAnyPublisher() + } +} diff --git a/Addame/Addame/Sources/InfoPlist/Environment.swift b/AddameSPM/Sources/InfoPlist/Environment.swift similarity index 100% rename from Addame/Addame/Sources/InfoPlist/Environment.swift rename to AddameSPM/Sources/InfoPlist/Environment.swift diff --git a/Addame/Addame/Sources/InfoPlist/InfoPlist.swift b/AddameSPM/Sources/InfoPlist/InfoPlist.swift similarity index 100% rename from Addame/Addame/Sources/InfoPlist/InfoPlist.swift rename to AddameSPM/Sources/InfoPlist/InfoPlist.swift diff --git a/Addame/Addame/Sources/InfoPlist/Resources/settings.plist b/AddameSPM/Sources/InfoPlist/Resources/settings.plist similarity index 100% rename from Addame/Addame/Sources/InfoPlist/Resources/settings.plist rename to AddameSPM/Sources/InfoPlist/Resources/settings.plist diff --git a/Addame/Addame/Sources/KeychainService/AppUserDefaults.swift b/AddameSPM/Sources/KeychainService/AppUserDefaults.swift similarity index 96% rename from Addame/Addame/Sources/KeychainService/AppUserDefaults.swift rename to AddameSPM/Sources/KeychainService/AppUserDefaults.swift index a5f2a1b..9bfc92c 100644 --- a/Addame/Addame/Sources/KeychainService/AppUserDefaults.swift +++ b/AddameSPM/Sources/KeychainService/AppUserDefaults.swift @@ -10,13 +10,13 @@ import Foundation public enum AppUserDefaults {} extension AppUserDefaults { - public enum Key: String { + public enum Key: String, CaseIterable { case isAuthorized case currentUser case token case cllocation case distance - case isUserFristNameUpdated + case isUserFirstNameEmpty } } diff --git a/Addame/Addame/Sources/KeychainService/KeychainService.swift b/AddameSPM/Sources/KeychainService/KeychainService.swift similarity index 98% rename from Addame/Addame/Sources/KeychainService/KeychainService.swift rename to AddameSPM/Sources/KeychainService/KeychainService.swift index 708c399..52040cd 100644 --- a/Addame/Addame/Sources/KeychainService/KeychainService.swift +++ b/AddameSPM/Sources/KeychainService/KeychainService.swift @@ -106,10 +106,10 @@ public class KeychainService: NSObject { } private class func load(_ service: NSString) -> NSString? { - let kCFBooleanTrue = kCFBooleanTrue as Any + let KCFBooleanTrue = kCFBooleanTrue as Any let objects = [ kSecClassGenericPasswordValue, - service, service, kCFBooleanTrue, + service, service, KCFBooleanTrue, kSecMatchLimitOneValue, kSecAttrAccessibleAfterFirstUnlockValue ] let forKeys = [ diff --git a/Addame/Addame/Sources/LocationSearchClient/Client.swift b/AddameSPM/Sources/LocationSearchClient/Client.swift similarity index 100% rename from Addame/Addame/Sources/LocationSearchClient/Client.swift rename to AddameSPM/Sources/LocationSearchClient/Client.swift diff --git a/Addame/Addame/Sources/LocationSearchClient/Live.swift b/AddameSPM/Sources/LocationSearchClient/Live.swift similarity index 100% rename from Addame/Addame/Sources/LocationSearchClient/Live.swift rename to AddameSPM/Sources/LocationSearchClient/Live.swift diff --git a/Addame/Addame/Sources/LocationSearchClient/Mock.swift b/AddameSPM/Sources/LocationSearchClient/Mock.swift similarity index 100% rename from Addame/Addame/Sources/LocationSearchClient/Mock.swift rename to AddameSPM/Sources/LocationSearchClient/Mock.swift diff --git a/Addame/Addame/Sources/LocationSearchClient/Models.swift b/AddameSPM/Sources/LocationSearchClient/Models.swift similarity index 100% rename from Addame/Addame/Sources/LocationSearchClient/Models.swift rename to AddameSPM/Sources/LocationSearchClient/Models.swift diff --git a/Addame/Addame/Sources/MapView/DynamicHeightForTextFieldInSwiftUI.swift b/AddameSPM/Sources/MapView/DynamicHeightForTextFieldInSwiftUI.swift similarity index 100% rename from Addame/Addame/Sources/MapView/DynamicHeightForTextFieldInSwiftUI.swift rename to AddameSPM/Sources/MapView/DynamicHeightForTextFieldInSwiftUI.swift diff --git a/Addame/Addame/Sources/MapView/LocationEnvironment.swift b/AddameSPM/Sources/MapView/LocationEnvironment.swift similarity index 88% rename from Addame/Addame/Sources/MapView/LocationEnvironment.swift rename to AddameSPM/Sources/MapView/LocationEnvironment.swift index ee95ceb..b58e552 100644 --- a/Addame/Addame/Sources/MapView/LocationEnvironment.swift +++ b/AddameSPM/Sources/MapView/LocationEnvironment.swift @@ -41,3 +41,10 @@ public struct LocationEnvironment { } } } + +extension LocationEnvironment { + public static let live: LocationEnvironment = .init( + localSearch: .live, + mainQueue: .main + ) +} diff --git a/Addame/Addame/Sources/MapView/LocationSearchAction.swift b/AddameSPM/Sources/MapView/LocationSearchAction.swift similarity index 100% rename from Addame/Addame/Sources/MapView/LocationSearchAction.swift rename to AddameSPM/Sources/MapView/LocationSearchAction.swift diff --git a/Addame/Addame/Sources/MapView/LocationSearchManager.swift b/AddameSPM/Sources/MapView/LocationSearchManager.swift similarity index 100% rename from Addame/Addame/Sources/MapView/LocationSearchManager.swift rename to AddameSPM/Sources/MapView/LocationSearchManager.swift diff --git a/Addame/Addame/Sources/MapView/LocationSearchReducer.swift b/AddameSPM/Sources/MapView/LocationSearchReducer.swift similarity index 100% rename from Addame/Addame/Sources/MapView/LocationSearchReducer.swift rename to AddameSPM/Sources/MapView/LocationSearchReducer.swift diff --git a/Addame/Addame/Sources/MapView/LocationSearchState.swift b/AddameSPM/Sources/MapView/LocationSearchState.swift similarity index 100% rename from Addame/Addame/Sources/MapView/LocationSearchState.swift rename to AddameSPM/Sources/MapView/LocationSearchState.swift diff --git a/Addame/Addame/Sources/MapView/MapView.swift b/AddameSPM/Sources/MapView/MapView.swift similarity index 100% rename from Addame/Addame/Sources/MapView/MapView.swift rename to AddameSPM/Sources/MapView/MapView.swift diff --git a/Addame/Addame/Sources/MapView/SearchMapView.swift b/AddameSPM/Sources/MapView/SearchMapView.swift similarity index 100% rename from Addame/Addame/Sources/MapView/SearchMapView.swift rename to AddameSPM/Sources/MapView/SearchMapView.swift diff --git a/Addame/Addame/Sources/NotificationHelpers/NotificationHelpers.swift b/AddameSPM/Sources/NotificationHelpers/NotificationHelpers.swift similarity index 100% rename from Addame/Addame/Sources/NotificationHelpers/NotificationHelpers.swift rename to AddameSPM/Sources/NotificationHelpers/NotificationHelpers.swift diff --git a/Addame/Addame/Sources/PathMonitorClient/Interface.swift b/AddameSPM/Sources/PathMonitorClient/Interface.swift similarity index 100% rename from Addame/Addame/Sources/PathMonitorClient/Interface.swift rename to AddameSPM/Sources/PathMonitorClient/Interface.swift diff --git a/Addame/Addame/Sources/PathMonitorClient/Mocks.swift b/AddameSPM/Sources/PathMonitorClient/Mocks.swift similarity index 100% rename from Addame/Addame/Sources/PathMonitorClient/Mocks.swift rename to AddameSPM/Sources/PathMonitorClient/Mocks.swift diff --git a/Addame/Addame/Sources/PathMonitorClientLive/Live.swift b/AddameSPM/Sources/PathMonitorClientLive/Live.swift similarity index 100% rename from Addame/Addame/Sources/PathMonitorClientLive/Live.swift rename to AddameSPM/Sources/PathMonitorClientLive/Live.swift diff --git a/Addame/Addame/Sources/ProfileView/EventRowView.swift b/AddameSPM/Sources/ProfileView/EventRowView.swift similarity index 100% rename from Addame/Addame/Sources/ProfileView/EventRowView.swift rename to AddameSPM/Sources/ProfileView/EventRowView.swift diff --git a/AddameSPM/Sources/ProfileView/File.swift b/AddameSPM/Sources/ProfileView/File.swift new file mode 100644 index 0000000..8a89e2a --- /dev/null +++ b/AddameSPM/Sources/ProfileView/File.swift @@ -0,0 +1,94 @@ +// +// File.swift +// +// +// Created by Saroar Khandoker on 18.10.2021. +// + +import SwiftUI +import SwiftUIExtension + +struct ImageSlider: View { + + // 1 + private let images = ["1", "2", "3", "4"] + + var body: some View { + // 2 + TabView { + ForEach(images, id: \.self) { item in + // 3 + Image(item) + .resizable() + .scaledToFill() + } + } + .tabViewStyle(PageTabViewStyle()) + } +} + +// struct ImageSlider_Previews: PreviewProvider { +// static var previews: some View { +// // 4 +// ImageSlider() +// .previewLayout(.fixed(width: 400, height: 300)) +// } +// } + +// struct ContentView: View { +// var body: some View { +// +// // 1 +// NavigationView { +// // 2 +// List { +// ImageSlider() +// .frame(height: 300) +// .listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) +// } //: List +// .navigationBarTitle("Image Slider", displayMode: .large) +// } //: Navigation View +// } +// +// } + +struct ContentView: View { + @State var index = 0 + + var images = ["person", "ant", "ladybug", "leaf"] + + var body: some View { + VStack(spacing: 0) { + PagingView(index: $index.animation(), maxIndex: images.count - 1) { + ForEach(self.images, id: \.self) { imageName in + Image(systemName: imageName) + .resizable() + .scaledToFit() + .padding() + } + } + .aspectRatio(3 / 4, contentMode: .fit) + .background(Color.red) + Spacer() + +// PagingView(index: $index.animation(), maxIndex: images.count - 1) { +// ForEach(self.images, id: \.self) { imageName in +// Image(systemName: imageName) +// .resizable() +// .scaledToFill() +// } +// } +// .aspectRatio(3/4, contentMode: .fit) +// .clipShape(RoundedRectangle(cornerRadius: 15)) + +// Stepper("Index: \(index)", value: $index.animation(.easeInOut), in: 0...images.count-1) +// .font(Font.body.monospacedDigit()) + } + } +} +// +// struct ContentView_Previews: PreviewProvider { +// static var previews: some View { +// ContentView() +// } +// } diff --git a/Addame/Addame/Sources/ProfileView/ProfileAction.swift b/AddameSPM/Sources/ProfileView/ProfileAction.swift similarity index 76% rename from Addame/Addame/Sources/ProfileView/ProfileAction.swift rename to AddameSPM/Sources/ProfileView/ProfileAction.swift index ee2f6ba..d55054a 100644 --- a/Addame/Addame/Sources/ProfileView/ProfileAction.swift +++ b/AddameSPM/Sources/ProfileView/ProfileAction.swift @@ -5,16 +5,17 @@ // Created by Saroar Khandoker on 06.04.2021. // -import HttpRequest +import HTTPRequestKit import SettingsView import SharedModels import SwiftUI +import ImagePicker public enum ProfileAction: Equatable { case onAppear case alertDismissed case isUploadingImage - case showingImagePicker + case isImagePicker(isPresented: Bool) case settingsView(isNavigation: Bool) case moveToAuthView @@ -23,11 +24,13 @@ public enum ProfileAction: Equatable { case updateUserName(String, String) case createAttachment(_ attachment: Attachment) - case userResponse(Result) - case attacmentResponse(Result) - case myEventsResponse(Result) + case imageUploadResponse(Result) + case userResponse(Result) + case attacmentResponse(Result) + case myEventsResponse(Result) case event(index: EventResponse.Item.ID, action: MyEventAction) case settings(SettingsAction) + case imagePicker(action: ImagePickerAction) case resetAuthData } @@ -45,8 +48,8 @@ extension ProfileAction { return .alertDismissed case .isUploadingImage: return .isUploadingImage - case .showingImagePicker: - return .showingImagePicker + case let .isImagePicker(isPresented: presented): + return .isImagePicker(isPresented: presented) case .moveToSettingsView: return .moveToAuthView case let .settingsView(isNavigation: present): @@ -65,10 +68,13 @@ extension ProfileAction { return .attacmentResponse(res) case let .event(index, action): return .event(index: index, action: action) - case .resetAuthData: - return .resetAuthData case let .settings(action): return .settings(action) + case let .imagePicker(action: action): + return .imagePicker(action: action) + case .resetAuthData: + return .resetAuthData + } } } diff --git a/Addame/Addame/Sources/ProfileView/ProfileEnvironment.swift b/AddameSPM/Sources/ProfileView/ProfileEnvironment.swift similarity index 57% rename from Addame/Addame/Sources/ProfileView/ProfileEnvironment.swift rename to AddameSPM/Sources/ProfileView/ProfileEnvironment.swift index 47971dd..17e18e1 100644 --- a/Addame/Addame/Sources/ProfileView/ProfileEnvironment.swift +++ b/AddameSPM/Sources/ProfileView/ProfileEnvironment.swift @@ -6,11 +6,19 @@ // import AttachmentClient +import AttachmentClientLive import AuthClient +import AuthClientLive import ComposableArchitecture import EventClient +import EventClientLive import SharedModels import UserClient +import UserClientLive +import UIKit +import KeychainService +import Combine +import HTTPRequestKit public struct ProfileEnvironment { public var userClient: UserClient @@ -36,3 +44,24 @@ public struct ProfileEnvironment { self.mainQueue = mainQueue } } + +extension ProfileEnvironment { + public static let live: ProfileEnvironment = .init( + userClient: UserClient.live(api: .build), + eventClient: EventClient.live(api: .build), + authClient: AuthClient.live(api: .build), + attachmentClient: AttachmentClient.live(api: .build), + backgroundQueue: .main, + mainQueue: .main + ) + + public static let happyPath: ProfileEnvironment = .init( + userClient: .happyPath, + eventClient: .happyPath, + authClient: .happyPath, + attachmentClient: .happyPath, + backgroundQueue: .immediate, + mainQueue: .immediate + ) + +} diff --git a/Addame/Addame/Sources/ProfileView/ProfileReducer.swift b/AddameSPM/Sources/ProfileView/ProfileReducer.swift similarity index 54% rename from Addame/Addame/Sources/ProfileView/ProfileReducer.swift rename to AddameSPM/Sources/ProfileView/ProfileReducer.swift index f14ba09..cb08226 100644 --- a/Addame/Addame/Sources/ProfileView/ProfileReducer.swift +++ b/AddameSPM/Sources/ProfileView/ProfileReducer.swift @@ -8,39 +8,35 @@ import AttachmentClient import Combine import ComposableArchitecture +import ComposablePresentation import ComposableArchitectureHelpers import EventClient import Foundation -import HttpRequest +import HTTPRequestKit import KeychainService import SettingsView import SharedModels import SwiftUI import UIKit import UserClient +import ImagePicker -public func getUserFromKeychain() -> Effect { - return Effect.future { callBack in +public func getUserFromKeychain() -> Effect { + return Effect.future { callBack in guard let user: User = KeychainService.loadCodable(for: .user) else { print(#line, "missing token") - return callBack(.failure(HTTPError.missingTokenFromIOS)) + return callBack(.failure(HTTPRequest.HRError.missingTokenFromIOS)) } return callBack(.success(user)) } } -// public let eventReducer = Reducer.combine( -// eventFormReducer.optional().pullback( -// state: \.eventForm, -// action: /EventsAction.eventForm, -// environment: { _ in () } -// ), -// Reducer { state, action, environment in -// struct LocationManagerId: Hashable {} -// - -public let profileReducer = Reducer { +public let profileReducer = Reducer< + ProfileState, + ProfileAction, + ProfileEnvironment +> { state, action, environment in func fetchMoreMyEvents() -> Effect { @@ -52,25 +48,27 @@ public let profileReducer = Reducer Bool { - return lhs.isUserFristNameUpdated == rhs.isUserFristNameUpdated + return lhs.isUserFirstNameEmpty == rhs.isUserFirstNameEmpty } - @AppStorage(AppUserDefaults.Key.isUserFristNameUpdated.rawValue) - public var isUserFristNameUpdated: Bool = false + @AppStorage(AppUserDefaults.Key.isUserFirstNameEmpty.rawValue) + public var isUserFirstNameEmpty: Bool = false public var alert: AlertState? public var isUploadingImage: Bool = false - public var showingImagePicker = false + public var isImagePickerPresented = false public var inputImage: UIImage? public var moveToSettingsView = false public var moveToAuthView: Bool = false @@ -29,15 +30,18 @@ public struct ProfileState: Equatable { public var isUserHaveAvatarLink: Bool = false public var myEvents: IdentifiedArrayOf = [] public var settingsState: SettingsState? + public var imagePickerState: ImagePickerState? + public var imageURLs: [String] = [] public var isLoadingPage = false public var canLoadMorePages = true public var currentPage = 1 + public var index = 0 public init( alert: AlertState? = nil, isUploadingImage: Bool = false, - showingImagePicker: Bool = false, + isImagePickerPresented: Bool = false, inputImage: UIImage? = nil, moveToSettingsView: Bool = false, moveToAuthView: Bool = false, @@ -45,13 +49,15 @@ public struct ProfileState: Equatable { isUserHaveAvatarLink: Bool = false, myEvents: IdentifiedArrayOf = [], settingsState: SettingsState? = nil, + imagePickerState: ImagePickerState? = nil, + imageURLs: [String] = [], isLoadingPage: Bool = false, canLoadMorePages: Bool = true, currentPage: Int = 1 ) { self.alert = alert self.isUploadingImage = isUploadingImage - self.showingImagePicker = showingImagePicker + self.isImagePickerPresented = isImagePickerPresented self.inputImage = inputImage self.moveToSettingsView = moveToSettingsView self.moveToAuthView = moveToAuthView @@ -59,6 +65,8 @@ public struct ProfileState: Equatable { self.isUserHaveAvatarLink = isUserHaveAvatarLink self.myEvents = myEvents self.settingsState = settingsState + self.imagePickerState = imagePickerState + self.imageURLs = imageURLs self.isLoadingPage = isLoadingPage self.canLoadMorePages = canLoadMorePages self.currentPage = currentPage @@ -70,7 +78,7 @@ extension ProfileState { ProfileView.ViewState( alert: alert, isUploadingImage: isUploadingImage, - showingImagePicker: showingImagePicker, + isImagePickerPresented: isImagePickerPresented, inputImage: inputImage, moveToSettingsView: moveToSettingsView, moveToAuthView: moveToAuthView, @@ -80,14 +88,27 @@ extension ProfileState { isLoadingPage: isLoadingPage, canLoadMorePages: canLoadMorePages, currentPage: currentPage, - settingsState: settingsState + settingsState: settingsState, + imagePickerState: imagePickerState, + imageURLs: imageURLs ) } } // swiftlint:disable all extension ProfileState { - private static var user = User( + private static var userWithoutAvatar = User( + id: "5fabb05d2470c17919b3c0e3", + phoneNumber: "+79218888889", + avatarUrl: nil, + firstName: "Secrect", + lastName: "Super", + email: nil, contactIDs: nil, deviceIDs: nil, + attachments: nil, + createdAt: Date(), updatedAt: Date() + ) + + private static var userWithAvatar = User( id: "5fabb05d2470c17919b3c0e2", phoneNumber: "+79218888888", avatarUrl: nil, firstName: "Alex", lastName: "Khan", email: nil, contactIDs: nil, deviceIDs: nil, attachments: [ @@ -137,35 +158,52 @@ extension ProfileState { createdAt: Date(), updatedAt: Date() ) - public static let events = Self( - user: user, - myEvents: [ - .init( - id: "5fbfe53675a93bda87c7cb16", name: "Cool :)", categories: "General", duration: 14400, - isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", - addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, - overlay: false, coordinates: [60.020532228306031, 30.388014239849944], createdAt: Date(), - updatedAt: Date()), - .init( - id: "5fbe8a8c8ba94be8a688324a", name: "Awesome 🤩 app", categories: "General", - duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", - addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, - overlay: false, coordinates: [60.020525506753494, 30.387988546891499], createdAt: Date(), - updatedAt: Date()), - .init( - id: "5fbea245b226053f0ece711c", name: "Bicycling 🚴🏽", categories: "LookingForAcompany", - duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", - addressName: "9к5 улица Бутлерова Saint Petersburg, Saint Petersburg", type: "Point", - sponsored: false, overlay: false, coordinates: [60.00380571585201, 30.399472870547118], - createdAt: Date(), updatedAt: Date()), - .init( - id: "5fbea245b226053f0ece711c", name: "Walk Around 🚶🏽🚶🏼‍♀️", categories: "LookingForAcompany", - imageUrl: - "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", - duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", - addressName: "188839, Первомайское, СНТ Славино-2 Поселок, 31 Первомайское Россия", - type: "Point", sponsored: false, overlay: false, - coordinates: [60.261340452875721, 29.873706166262373], createdAt: Date(), updatedAt: Date()), + private static var events: IdentifiedArrayOf = [ + .init( + id: "5fbfe53675a93bda87c7cb16", name: "In Future people will be very kind and happy!", categories: "General", duration: 14400, + isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, + overlay: false, coordinates: [60.020532228306031, 30.388014239849944], createdAt: Date(), + updatedAt: Date()), + .init( + id: "5fbe8a8c8ba94be8a688324a", name: "Awesome 🤩 app", categories: "General", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", sponsored: false, + overlay: false, coordinates: [60.020525506753494, 30.387988546891499], createdAt: Date(), + updatedAt: Date()), + .init( + id: "5fbea245b226053f0ece711c", name: "Bicycling 🚴🏽", categories: "LookingForAcompany", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "9к5 улица Бутлерова Saint Petersburg, Saint Petersburg", type: "Point", + sponsored: false, overlay: false, coordinates: [60.00380571585201, 30.399472870547118], + createdAt: Date(), updatedAt: Date()), + .init( + id: "5fbea245b226053f0ece712c", name: "Walk Around 🚶🏽🚶🏼‍♀️", categories: "LookingForAcompany", + imageUrl: + "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "188839, Первомайское, СНТ Славино-2 Поселок, 31 Первомайское Россия", + type: "Point", sponsored: false, overlay: false, + coordinates: [60.261340452875721, 29.873706166262373], createdAt: Date(), updatedAt: Date()), + ] + + public static let profileStateWithUserWithAvatar = Self( + alert: nil, + user: userWithAvatar, + myEvents: events, + imageURLs: [ + "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1607338279849.heic", + "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1607338304864.heic", + "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1605875164101.heic", + "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1605811106589.jpeg", + "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1605796266916.jpeg", + "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/5fabb05d2470c17919b3c0e2_1605792619988.jpeg" ] ) + + public static let profileStateWithUserWithoutAvatar = Self( + alert: nil, + user: userWithoutAvatar, + myEvents: events + ) } diff --git a/AddameSPM/Sources/ProfileView/ProfileView.swift b/AddameSPM/Sources/ProfileView/ProfileView.swift new file mode 100644 index 0000000..736193c --- /dev/null +++ b/AddameSPM/Sources/ProfileView/ProfileView.swift @@ -0,0 +1,381 @@ +import AsyncImageLoder +import AuthenticationView +import ComposableArchitecture +import ComposablePresentation +import HTTPRequestKit +import KeychainService +import SettingsView +import SharedModels +import SwiftUI +import SwiftUIExtension +import UserClient +import ImagePicker + +extension ProfileView { + + public struct ViewState: Equatable { + public var alert: AlertState? + public var isUploadingImage: Bool = false + public var isImagePickerPresented = false + public var inputImage: UIImage? + public var moveToSettingsView = false + public var moveToAuthView: Bool = false + public var user = User.draff + public var isUserHaveAvatarLink: Bool = false + public var myEvents: IdentifiedArrayOf = [] + public var isLoadingPage = false + public var canLoadMorePages = true + public var currentPage = 1 + public var index = 0 + public var settingsState: SettingsState? + public var imagePickerState: ImagePickerState? + public var imageURLs: [String] = [] + } + + public enum ViewAction: Equatable { + case onAppear + case alertDismissed + case isUploadingImage + case isImagePicker(isPresented: Bool) + case moveToSettingsView + case settingsView(isNavigation: Bool) + + case fetchMyData + case uploadAvatar(_ image: UIImage) + case updateUserName(String, String) + case createAttachment(_ attachment: Attachment) + + case userResponse(Result) + case attacmentResponse(Result) + case event(index: EventResponse.Item.ID, action: MyEventAction) + case settings(SettingsAction) + case imagePicker(action: ImagePickerAction) + + case resetAuthData + } + +} + +public struct ProfileView: View { + @Environment(\.colorScheme) var colorScheme + let store: Store + + public init(store: Store) { + self.store = store + } + + @State var index = 0 + + @ViewBuilder + public var body: some View { + WithViewStore( + self.store.scope( + state: { $0.view }, + action: ProfileAction.view + ) + ) { viewStore in + + ScrollView(.vertical) { + + if !viewStore.state.imageURLs.isEmpty { + PagingView( + index: $index.animation(), + maxIndex: viewStore.state.imageURLs.count - 1 + ) { + ForEach(viewStore.state.imageURLs, id: \.self) { url in + AsyncImage( + urlString: url, + placeholder: { + HUDProgressView( + placeHolder: "Image is loading...", + show: viewStore.binding( + get: { $0.isUploadingImage }, + send: { _ in ViewAction.isUploadingImage } + ) + ) + .frame(maxWidth: .infinity) + .padding(.bottom, 100) + }, + image: { + Image(uiImage: $0).resizable() + } + ) + .scaledToFit() + .frame(alignment: .center) + .listRowBackground(Color(.secondarySystemBackground)) + } + } + .aspectRatio(5 / 4, contentMode: .fill) + .overlay( + ProfileImageOverlay(store: self.store), + alignment: .bottomTrailing + ) + .edgesIgnoringSafeArea(.horizontal) + } else { + Text("Upload your avatar!") + .font(.system(size: 20, weight: .medium)) + .frame(maxWidth: .infinity) + .frame(height: 350) + .foregroundColor( + Color.backgroundColor(for: self.colorScheme) + ) + .background(Color.yellow) + .overlay( + ProfileImageOverlay(store: self.store), + alignment: .bottomTrailing + ) + } + + VStack { + MyEventListView(store: self.store) + } + .padding(.top, 90) + } + .onAppear { viewStore.send(.onAppear) } + .navigationBarTitle("Profile", displayMode: .inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + viewStore.send(.settingsView(isNavigation: true)) + } label: { + Image(systemName: "gear") + .resizable() + .aspectRatio(contentMode: .fill) + .foregroundColor( + Color.backgroundColor(for: self.colorScheme) + ) + } + } + } + .alert(self.store.scope(state: { $0.alert }), dismiss: .alertDismissed) + } + .onAppear { + ViewStore(store.stateless).send(.onAppear) + } + .navigationViewStyle(StackNavigationViewStyle()) + .sheet( + store.scope( + state: \.imagePickerState, + action: ProfileAction.imagePicker + ), + mapState: replayNonNil(), + onDismiss: { + ViewStore(store.stateless) + .send(.isImagePicker(isPresented: false)) + }, + content: ImagePicker.init(store:) + ) + .background( + NavigationLinkWithStore( + store.scope(state: \.settingsState, action: ProfileAction.settings), + mapState: replayNonNil(), + onDeactivate: { ViewStore(store.stateless) + .send(.settingsView(isNavigation: false)) + }, + destination: SettingsView.init(store:) + ) + ) + } +} + +// struct ProfileView_Previews: PreviewProvider { +// +// static let store = Store( +// initialState: ProfileState.profileStateWithUserWithAvatar, +// reducer: profileReducer, // here i am mixing +// environment: ProfileEnvironment.happyPath +// ) +// +// static var previews: some View { +// +// Group { +// NavigationView { +// ProfileView(store: store) +// } +// +// NavigationView { +// ProfileView(store: store) +// .environment(\.colorScheme, .dark) +// } +// } +// } +// } + +public struct ProfileImageOverlay: View { + @Environment(\.colorScheme) var colorScheme + + let store: Store + + public init(store: Store) { + self.store = store + } + + public var body: some View { + WithViewStore( + self.store.scope(state: { $0.view }, action: ProfileAction.view) + ) { viewStore in + ZStack { + if viewStore.state.isUploadingImage { + withAnimation { + HUDProgressView( + placeHolder: "Image uploading...", + show: viewStore.binding( + get: { $0.isUploadingImage }, + send: { _ in .isUploadingImage } + ) + ) + } + } + + VStack { + HStack { + Spacer() + Button(action: { + viewStore.send(.isImagePicker(isPresented: true)) + }, label: { + Image(systemName: "camera") + .font(.system(size: 15, weight: .medium)) + .foregroundColor(Color.backgroundColor(for: colorScheme)) + .frame(width: 40, height: 40) + }) + .imageScale(.large) + .frame(width: 40, height: 40, alignment: .center) + .background( + Circle().strokeBorder(Color.backgroundColor(for: colorScheme), lineWidth: 1.25) + ) + .padding() + } + + Spacer() + + VStack { + Text(viewStore.user.fullName) + .foregroundColor(Color.black) + .font(.title).bold() + .frame(maxWidth: .infinity) + .padding() + .padding(.bottom, -5) + Text(viewStore.user.phoneNumber) + .foregroundColor(Color.black) + .font(.body) + .frame(maxWidth: .infinity) + + Spacer() +// HStack { +// Text("Something Cool:") +// .font(.body).bold() +// .frame(maxWidth: .infinity) +// .padding() +// +// Text("Total events: 99") +// .font(.body).bold() +// .frame(maxWidth: .infinity) +// .padding() +// } + } + .frame(height: 120) + .background( + RoundedRectangle(cornerRadius: 10) + .foregroundColor(Color.white) + .shadow(color: .black.opacity(0.2), radius: 10, x: 0, y: 0) + ) + .padding(30) + .padding(.bottom, -100) + } + } + } + } +} + +// struct ProfileImageOverlay_Previews: PreviewProvider { +// static let environment = ProfileEnvironment( +// userClient: .happyPath, +// eventClient: .happyPath, +// authClient: .happyPath, +// attachmentClient: .happyPath, +// mainQueue: DispatchQueue.main.eraseToAnyScheduler() +// ) +// +// static let store = Store( +// initialState: ProfileState(), +// reducer: profileReducer, +// environment: ProfileEnvironment( +// userClient: .happyPath, +// eventClient: .happyPath, +// authClient: .happyPath, +// attachmentClient: .happyPath, +// mainQueue: DispatchQueue.main.eraseToAnyScheduler() +// ) +// ) +// +// static var previews: some View { +// ProfileImageOverlay(store: store) +// } +// } + +public struct MyEventListView: View { + let store: Store + + public var body: some View { + + WithViewStore(self.store) { _ in + VStack { + Text("My Events").font(.title) + ForEachStore( + self.store.scope(state: \.myEvents, action: ProfileAction.event) + ) { eventStore in + WithViewStore(eventStore) { _ in + // Button(action: { viewStore.send(.eventTapped(eventViewStore.state)) }) { + EventRowView(store: eventStore) + // } + // .buttonStyle(PlainButtonStyle()) + } + // .padding([.leading, .trailing], 30) + } + } + } + } +} + +public struct EventRowView: View { + @Environment(\.colorScheme) var colorScheme + + public init(store: Store) { + self.store = store + } + + public let store: Store + + public var body: some View { + WithViewStore(self.store) { viewStore in + VStack(alignment: .leading) { + Group { + Text(viewStore.name) + .font(.system(.title, design: .rounded)) + .lineLimit(2) + .padding(.top, 8) + .padding(.bottom, 3) + + Text(viewStore.addressName) + .font(.system(.body, design: .rounded)) + .foregroundColor(.blue) + .padding(.bottom, 16) + } + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 16) + } + .background( + RoundedRectangle(cornerRadius: 10) + .foregroundColor( + colorScheme == .dark + ? Color( + #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260520637, alpha: 1)) + : Color( + #colorLiteral( + red: 0.8374180198, green: 0.8374378085, blue: 0.8374271393, alpha: 0.5))) + ) + .padding([.leading, .trailing], 16) + .padding([.top, .bottom], 5) + } + } +} diff --git a/Addame/Addame/Sources/RemoteNotificationsClient/Interface.swift b/AddameSPM/Sources/RemoteNotificationsClient/Interface.swift similarity index 100% rename from Addame/Addame/Sources/RemoteNotificationsClient/Interface.swift rename to AddameSPM/Sources/RemoteNotificationsClient/Interface.swift diff --git a/Addame/Addame/Sources/RemoteNotificationsClient/Live.swift b/AddameSPM/Sources/RemoteNotificationsClient/Live.swift similarity index 100% rename from Addame/Addame/Sources/RemoteNotificationsClient/Live.swift rename to AddameSPM/Sources/RemoteNotificationsClient/Live.swift diff --git a/Addame/Addame/Sources/SettingsView/DistanceFilterView.swift b/AddameSPM/Sources/SettingsView/DistanceFilterView.swift similarity index 97% rename from Addame/Addame/Sources/SettingsView/DistanceFilterView.swift rename to AddameSPM/Sources/SettingsView/DistanceFilterView.swift index eb503c5..d9f1043 100644 --- a/Addame/Addame/Sources/SettingsView/DistanceFilterView.swift +++ b/AddameSPM/Sources/SettingsView/DistanceFilterView.swift @@ -214,6 +214,13 @@ public struct DistanceEnvironment { public var userDefaults: UserDefaultsClient } +extension DistanceEnvironment { + public static let live: DistanceEnvironment = .init( + mainQueue: .main, + userDefaults: .live() + ) +} + public let distanceReducer = Reducer< DistanceState, DistanceAction, DistanceEnvironment > { state, action, environment in diff --git a/AddameSPM/Sources/SettingsView/SettingsView.swift b/AddameSPM/Sources/SettingsView/SettingsView.swift new file mode 100644 index 0000000..e455603 --- /dev/null +++ b/AddameSPM/Sources/SettingsView/SettingsView.swift @@ -0,0 +1,183 @@ +// +// SwiftUIView.swift +// +// +// Created by Saroar Khandoker on 09.04.2021. +// + +import ComposableArchitecture +import KeychainService +import SwiftUI +import UserNotificationClient +import ComposablePresentation +import AuthenticationView + +extension SettingsView { + public struct ViewState: Equatable { + public var alert: AlertState? + public var userNotificationSettings: UserNotificationClient.Notification.Settings? + public var userSettings: UserSettings + public var distance: DistanceState + } + + public enum ViewAction: Equatable { + case leaveUsAReviewButtonTapped + case onAppear + case onDismiss + case distanceView(DistanceAction) + case resetAuthData + case isLogoutButton(tapped: Bool) + case termsSheet(isPresented: Bool, url: String?) + case privacySheet(isPresented: Bool, url: String?) + } +} + +public struct SettingsView: View { + let store: Store + + public init(store: Store) { + self.store = store + } + + public var body: some View { + WithViewStore( + self.store.scope( + state: { $0.view }, + action: SettingsAction.view + ) + ) { viewStore in + VStack { + VStack(alignment: .leading, spacing: 20) { + Text("Settings") + .font(.title) + .bold() + .padding() + +// Toggle(isOn: +// viewStore.binding( +// get: \.distanceTypeToggleisOn, +// send: ViewAction.distanceTypeToggleChanged +// ) +// ) { +// Text("Remote Notifications") +// .font(.system(.title2, design: .rounded)) +// .bold() +// .foregroundColor( +// viewStore.distanceTypeToggleisOn == true ? .green : .gray +// ) +// } +// .padding() + + DistanceFilterView( + store: self.store.scope( + state: \.distance, + action: SettingsAction.distanceView + ) + ) + .padding([.top, .bottom], 20) + .transition(.opacity) + + HStack { + Spacer() + Button( + action: { + viewStore.send(.termsSheet(isPresented: true, url: "https://addame.com/terms") ) + }, + label: { + Text("Terms") + .font(.title) + .bold() + .foregroundColor(.blue) + .padding() + }) + + Text("&") + .font(.title3) + .bold() + .padding([.leading, .trailing], 10) + .foregroundColor(Color(UIColor.systemBackground)) + + Button( + action: { viewStore.send(.termsSheet(isPresented: true, url: "https://addame.com/privacy") ) }, + label: { + Text("Privacy") + .font(.title) + .bold() + .foregroundColor(.blue) + .padding() + }) + + Spacer() + } + // .frame(width: .infinity, height: 100, alignment: .center) + .background(Color.yellow) + .clipShape(RoundedRectangle(cornerRadius: 13, style: .continuous)) + .padding() + + Spacer() + } + + HStack { + Spacer() + Button { + viewStore.send(.isLogoutButton(tapped: true)) + } label: { + Text("Logout") + .font(.body) + .bold() + } + .padding(10) + .background(Color.yellow) + .clipShape(RoundedRectangle(cornerRadius: 13, style: .continuous)) + .padding([.bottom, .trailing], 20) + } + } + .sheet( + store.scope(state: \.termsAndPrivacyState, action: SettingsAction.termsAndPrivacy), + mapState: replayNonNil(), + onDismiss: { + ViewStore(store.stateless) + .send(.termsSheet(isPresented: false, url: nil)) + }, + content: TermsAndPrivacyWebView.init(store:) + ) + +// .sheet( +// store.scope( +// state: \.terms, +// action: SettingsAction.terms +// ), +// state: replayNonNil(), +// onDismiss: { ViewStore(store.stateless) +// .send(.termsView(isPresented: false)) +// }, +// destination: EventDetailsView.init(store:) +// ) + } + .background(Color(UIColor.systemBackground).edgesIgnoringSafeArea(.all)) + } +} + +struct SettingsView_Previews: PreviewProvider { + static let env = SettingsEnvironment( + applicationClient: .noop, + backgroundQueue: .immediate, + mainQueue: .immediate, + userDefaults: .noop, + userNotifications: .noop + ) + + static let store = Store( + initialState: SettingsState.settingsSatate, + reducer: settingsReducer, + environment: env + ) + + static var previews: some View { + Group { + SettingsView(store: store) + SettingsView(store: store) + .environment(\.colorScheme, .dark) + } + } +} diff --git a/Addame/Addame/Sources/SettingsView/UserSettings.swift b/AddameSPM/Sources/SettingsView/UserSettings.swift similarity index 69% rename from Addame/Addame/Sources/SettingsView/UserSettings.swift rename to AddameSPM/Sources/SettingsView/UserSettings.swift index 017b18f..571cc61 100644 --- a/Addame/Addame/Sources/SettingsView/UserSettings.swift +++ b/AddameSPM/Sources/SettingsView/UserSettings.swift @@ -11,6 +11,10 @@ import UIKit // import RemoteNotificationsClient import UserDefaultsClient import UserNotificationClient +import KeychainService +import SharedModels +import ComposablePresentation +import AuthenticationView public struct UserSettings: Codable, Equatable { public var colorScheme: ColorScheme @@ -51,6 +55,11 @@ public enum SettingsAction: Equatable { case userNotificationAuthorizationResponse(Result) case userNotificationSettingsResponse(UserNotificationClient.Notification.Settings) case distanceView(DistanceAction) + case resetAuthData + case isLogoutButton(tapped: Bool) + case termsSheet(isPresented: Bool, url: String?) + case privacySheet(isPresented: Bool, url: String?) + case termsAndPrivacy(TermsAndPrivacyAction) } extension SettingsAction { @@ -64,6 +73,14 @@ extension SettingsAction { return onDismiss case let .distanceView(action): return distanceView(action) + case .resetAuthData: + return resetAuthData + case let .isLogoutButton(tapped: tapped): + return .isLogoutButton(tapped: tapped) + case let .termsSheet(isPresented: isPresented, url: url): + return termsSheet(isPresented: isPresented, url: url) + case let .privacySheet(isPresented: isPresented, url: url): + return privacySheet(isPresented: isPresented, url: url) } } } @@ -84,18 +101,21 @@ public struct SettingsState: Equatable { alert: AlertState? = nil, userNotificationSettings: UserNotificationClient.Notification.Settings? = nil, userSettings: UserSettings = UserSettings(), - distance: DistanceState = DistanceState() + distance: DistanceState = DistanceState(), + termsAndPrivacyState: TermsAndPrivacyState? = nil ) { self.alert = alert self.userNotificationSettings = userNotificationSettings self.userSettings = userSettings self.distance = distance + self.termsAndPrivacyState = termsAndPrivacyState } public var alert: AlertState? public var userNotificationSettings: UserNotificationClient.Notification.Settings? public var userSettings: UserSettings public var distance: DistanceState + public var termsAndPrivacyState: TermsAndPrivacyState? } extension SettingsState { @@ -130,20 +150,25 @@ public struct SettingsEnvironment { } } +extension SettingsEnvironment { + public static let live: SettingsEnvironment = .init( + applicationClient: .noop, + backgroundQueue: .main, + mainQueue: .main, + userDefaults: .live(), + userNotifications: .live + ) +} + public let settingsReducer = Reducer< SettingsState, SettingsAction, SettingsEnvironment >.combine( distanceReducer.pullback( state: \.distance, action: /SettingsAction.distanceView, - environment: { - DistanceEnvironment( - mainQueue: $0.mainQueue, - userDefaults: .live() - ) - } + environment: { _ in DistanceEnvironment.live } ), - Reducer { _, action, _ in + Reducer { state, action, _ in switch action { case let .binding(settingsState): return .none @@ -161,6 +186,26 @@ public let settingsReducer = Reducer< return .none case let .distanceView(action): return .none + case .resetAuthData: + return .none + case let .isLogoutButton(tapped: tapped): + return .none + // swiftlint:disable pattern_matching_keywords + case .termsSheet(isPresented: let isPresented, url: let url): + state.termsAndPrivacyState = isPresented ? TermsAndPrivacyState(urlString: url) : nil + return .none + + // swiftlint:disable pattern_matching_keywords + case .privacySheet(isPresented: let isPresented, url: let url): + return .none + case .termsAndPrivacy(_): + return .none } } ) +.presenting( + termsAndPrivacyReducer, + state: \.termsAndPrivacyState, + action: /SettingsAction.termsAndPrivacy, + environment: { _ in TermsAndPrivacyEnvironment.live } +) diff --git a/Addame/Addame/Sources/SharedModels/Attachment/Attachment.swift b/AddameSPM/Sources/SharedModels/Attachment/Attachment.swift similarity index 97% rename from Addame/Addame/Sources/SharedModels/Attachment/Attachment.swift rename to AddameSPM/Sources/SharedModels/Attachment/Attachment.swift index 545407d..b406df4 100644 --- a/Addame/Addame/Sources/SharedModels/Attachment/Attachment.swift +++ b/AddameSPM/Sources/SharedModels/Attachment/Attachment.swift @@ -48,3 +48,5 @@ public struct Attachment: Codable, Equatable { return lhsDate > rhsDate } } + +extension Attachment: Hashable {} diff --git a/Addame/Addame/Sources/SharedModels/Auth/AuthResponse.swift b/AddameSPM/Sources/SharedModels/Auth/AuthResponse.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Auth/AuthResponse.swift rename to AddameSPM/Sources/SharedModels/Auth/AuthResponse.swift diff --git a/Addame/Addame/Sources/SharedModels/Chat/ChatMessage.swift b/AddameSPM/Sources/SharedModels/Chat/ChatMessage.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Chat/ChatMessage.swift rename to AddameSPM/Sources/SharedModels/Chat/ChatMessage.swift diff --git a/Addame/Addame/Sources/SharedModels/Chat/ChatOutGoingEvent.swift b/AddameSPM/Sources/SharedModels/Chat/ChatOutGoingEvent.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Chat/ChatOutGoingEvent.swift rename to AddameSPM/Sources/SharedModels/Chat/ChatOutGoingEvent.swift diff --git a/Addame/Addame/Sources/SharedModels/Chat/LastMessage.swift b/AddameSPM/Sources/SharedModels/Chat/LastMessage.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Chat/LastMessage.swift rename to AddameSPM/Sources/SharedModels/Chat/LastMessage.swift diff --git a/Addame/Addame/Sources/SharedModels/Contact/Contact.swift b/AddameSPM/Sources/SharedModels/Contact/Contact.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Contact/Contact.swift rename to AddameSPM/Sources/SharedModels/Contact/Contact.swift diff --git a/Addame/Addame/Sources/SharedModels/Conversation/Conversation.swift b/AddameSPM/Sources/SharedModels/Conversation/Conversation.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Conversation/Conversation.swift rename to AddameSPM/Sources/SharedModels/Conversation/Conversation.swift diff --git a/Addame/Addame/Sources/SharedModels/Event/Categories.swift b/AddameSPM/Sources/SharedModels/Event/Categories.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Event/Categories.swift rename to AddameSPM/Sources/SharedModels/Event/Categories.swift diff --git a/Addame/Addame/Sources/SharedModels/Event/DurationButtons.swift b/AddameSPM/Sources/SharedModels/Event/DurationButtons.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/Event/DurationButtons.swift rename to AddameSPM/Sources/SharedModels/Event/DurationButtons.swift diff --git a/Addame/Addame/Sources/SharedModels/Event/Event.swift b/AddameSPM/Sources/SharedModels/Event/Event.swift similarity index 81% rename from Addame/Addame/Sources/SharedModels/Event/Event.swift rename to AddameSPM/Sources/SharedModels/Event/Event.swift index b26b347..826d693 100644 --- a/Addame/Addame/Sources/SharedModels/Event/Event.swift +++ b/AddameSPM/Sources/SharedModels/Event/Event.swift @@ -94,9 +94,12 @@ public struct EventResponse: Codable, Equatable { // MARK: - Item - public class Item: NSObject, Codable, Identifiable, Comparable { + public struct Item: Codable, Comparable, Identifiable { + + public var id: String { _id } + public static func < (lhs: EventResponse.Item, rhs: EventResponse.Item) -> Bool { - return lhs.coordinate < rhs.coordinate && lhs.id < rhs.id + return lhs.id < rhs.id } public init( @@ -107,7 +110,7 @@ public struct EventResponse: Codable, Equatable { overlay: Bool, coordinates: [Double], regionRadius: CLLocationDistance? = 1000, createdAt: Date, updatedAt: Date ) { - _id = id + self._id = id self.name = name self.categories = categories self.imageUrl = imageUrl @@ -167,40 +170,37 @@ public struct Metadata: Codable, Equatable { } } -extension EventResponse.Item: MKAnnotation { - public var coordinate: CLLocationCoordinate2D { location.coordinate } - public var title: String? { addressName } - public var location: CLLocation { - CLLocation(latitude: coordinates[0], longitude: coordinates[1]) - } - - public var region: MKCoordinateRegion { - MKCoordinateRegion( - center: location.coordinate, - latitudinalMeters: regionRadius ?? 1000, - longitudinalMeters: regionRadius ?? 1000 - ) - } - - public var coordinateMongo: CLLocationCoordinate2D { - return CLLocationCoordinate2D(latitude: coordinate.longitude, longitude: coordinate.latitude) - } - - public var coordinatesMongoDouble: [Double] { - return [coordinates[1], coordinates[0]] - } - - public var doubleToCoordinate: CLLocation { - return CLLocation(latitude: coordinates[0], longitude: coordinates[1]) - } - - public func distance(_ currentCLLocation: CLLocation) { - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - currentCLLocation.distance(from: self.location) - } - } -} +// extension EventResponse.Item: MKAnnotation { +// public var coordinate: CLLocationCoordinate2D { location.coordinate } +// public var title: String? { addressName } +// public var location: CLLocation { +// CLLocation(latitude: coordinates[0], longitude: coordinates[1]) +// } +// +// public var region: MKCoordinateRegion { +// MKCoordinateRegion( +// center: location.coordinate, +// latitudinalMeters: regionRadius ?? 1000, +// longitudinalMeters: regionRadius ?? 1000 +// ) +// } +// +// public var coordinateMongo: CLLocationCoordinate2D { +// return CLLocationCoordinate2D(latitude: coordinate.longitude, longitude: coordinate.latitude) +// } +// +// public var coordinatesMongoDouble: [Double] { +// return [coordinates[1], coordinates[0]] +// } +// +// public var doubleToCoordinate: CLLocation { +// return CLLocation(latitude: coordinates[0], longitude: coordinates[1]) +// } +// +// public func distance(_ currentCLLocation: CLLocation) { +// currentCLLocation.distance(from: self.location) +// } +// } extension CLLocation { var double: [Double] { diff --git a/Addame/Addame/Sources/SharedModels/QueryItem/QueryItem.swift b/AddameSPM/Sources/SharedModels/QueryItem/QueryItem.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/QueryItem/QueryItem.swift rename to AddameSPM/Sources/SharedModels/QueryItem/QueryItem.swift diff --git a/Addame/Addame/Sources/SharedModels/User/User.swift b/AddameSPM/Sources/SharedModels/User/User.swift similarity index 100% rename from Addame/Addame/Sources/SharedModels/User/User.swift rename to AddameSPM/Sources/SharedModels/User/User.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/Binding.swift b/AddameSPM/Sources/SwiftUIExtension/Binding.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/Binding.swift rename to AddameSPM/Sources/SwiftUIExtension/Binding.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/Color.swift b/AddameSPM/Sources/SwiftUIExtension/Color.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/Color.swift rename to AddameSPM/Sources/SwiftUIExtension/Color.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/ColorSchemeExtension.swift b/AddameSPM/Sources/SwiftUIExtension/ColorSchemeExtension.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/ColorSchemeExtension.swift rename to AddameSPM/Sources/SwiftUIExtension/ColorSchemeExtension.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/ContinuousCornerRadius.swift b/AddameSPM/Sources/SwiftUIExtension/ContinuousCornerRadius.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/ContinuousCornerRadius.swift rename to AddameSPM/Sources/SwiftUIExtension/ContinuousCornerRadius.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/Date.swift b/AddameSPM/Sources/SwiftUIExtension/Date.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/Date.swift rename to AddameSPM/Sources/SwiftUIExtension/Date.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/ActivityIndicator.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/ActivityIndicator.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/ActivityIndicator.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/ActivityIndicator.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/ActivityView.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/ActivityView.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/ActivityView.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/ActivityView.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/AdaptsToSoftwareKeyboard.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/AdaptsToSoftwareKeyboard.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/AdaptsToSoftwareKeyboard.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/AdaptsToSoftwareKeyboard.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/DynamicHeightTextField.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/DynamicHeightTextField.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/DynamicHeightTextField.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/DynamicHeightTextField.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/HUDProgressView.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/HUDProgressView.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/HUDProgressView.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/HUDProgressView.swift diff --git a/AddameSPM/Sources/SwiftUIExtension/Helper/HidableTabView.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/HidableTabView.swift new file mode 100644 index 0000000..a6000da --- /dev/null +++ b/AddameSPM/Sources/SwiftUIExtension/Helper/HidableTabView.swift @@ -0,0 +1,72 @@ +// +// HidableTabView.swift +// +// +// Created by Saroar Khandoker on 12.11.2021. +// + +import SwiftUI + +public struct HidableTabView: View where SelectionValue: Hashable, Content: View { + @Binding var isHidden: Bool + let selection: Binding? + let content: () -> Content + + @State private var currentTabBarHeight: CGFloat = 0 + + public init( + isHidden: Binding, + selection: Binding?, + @ViewBuilder content: @escaping () -> Content + ) { + self._isHidden = isHidden + self.selection = selection + self.content = content + } + + public init( + isHidden: Binding, + @ViewBuilder content: @escaping () -> Content + ) where SelectionValue == Int { + self._isHidden = isHidden + self.selection = nil + self.content = content + } + + public var body: some View { + tabView + .stackNavigationViewStyle() + .padding(.bottom, isHidden ? -self.currentTabBarHeight : 0) + + } + + @ViewBuilder var tabView: some View { + if selection != nil { + TabView(selection: self.selection!) { self._content } + } else { + TabView { self._content } + } + } + + // swiftlint:disable identifier_name + @ViewBuilder var _content: some View { + self.content() + .background(tabBarHeightReader) + } + + var screenBottomSafeAreaInset: CGFloat { + (UIApplication.shared.windows.first { $0.isKeyWindow }?.safeAreaInsets.bottom ?? 34) + } + + var tabBarHeightReader: some View { + GeometryReader { proxy in + Color.clear + .onAppear { + self.currentTabBarHeight = proxy.safeAreaInsets.bottom + screenBottomSafeAreaInset + } + .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in + self.currentTabBarHeight = proxy.safeAreaInsets.bottom + screenBottomSafeAreaInset + } + } + } +} diff --git a/Addame/Addame/Sources/SwiftUIExtension/KeyboardDismissModifier.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/KeyboardDismissModifier.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/KeyboardDismissModifier.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/KeyboardDismissModifier.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/LazyView.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/LazyView.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/LazyView.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/LazyView.swift diff --git a/AddameSPM/Sources/SwiftUIExtension/Helper/PagingView.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/PagingView.swift new file mode 100644 index 0000000..7d13f6e --- /dev/null +++ b/AddameSPM/Sources/SwiftUIExtension/Helper/PagingView.swift @@ -0,0 +1,95 @@ +// +// PagingView.swift +// +// +// Created by Saroar Khandoker on 19.10.2021. +// + +import SwiftUI + +public struct PagingView: View where Content: View { + + @Binding var index: Int + let maxIndex: Int + let content: () -> Content + + @State private var offset = CGFloat.zero + @State private var dragging = false + + public init( + index: Binding, + maxIndex: Int, + @ViewBuilder content: @escaping () -> Content + ) { + self._index = index + self.maxIndex = maxIndex + self.content = content + } + + public var body: some View { + ZStack(alignment: .topLeading) { + + GeometryReader { geometry in + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 0) { + self.content() + .frame(width: geometry.size.width, height: geometry.size.height) + .clipped() + } + } + .content.offset(x: self.offset(in: geometry), y: 0) + .frame(width: geometry.size.width, alignment: .leading) + .gesture( + DragGesture().onChanged { value in + self.dragging = true + self.offset = -CGFloat(self.index) * geometry.size.width + value.translation.width + } + .onEnded { value in + let predictedEndOffset = -CGFloat(self.index) * + geometry.size.width + + value.predictedEndTranslation.width + let predictedIndex = Int(round(predictedEndOffset / -geometry.size.width)) + self.index = self.clampedIndex(from: predictedIndex) + withAnimation(.easeOut) { + self.dragging = false + } + } + ) + } + .clipped() + + PageControl(index: $index, maxIndex: maxIndex) + } + } + + func offset(in geometry: GeometryProxy) -> CGFloat { + if self.dragging { + return max(min(self.offset, 0), -CGFloat(self.maxIndex) * geometry.size.width) + } else { + return -CGFloat(self.index) * geometry.size.width + } + } + + func clampedIndex(from predictedIndex: Int) -> Int { + let newIndex = min(max(predictedIndex, self.index - 1), self.index + 1) + guard newIndex >= 0 else { return 0 } + guard newIndex <= maxIndex else { return maxIndex } + return newIndex + } +} + +struct PageControl: View { + @Binding var index: Int + let maxIndex: Int + + var body: some View { + HStack(spacing: 8) { + ForEach(0...maxIndex, id: \.self) { index in + Circle() + .fill(index == self.index ? Color.white : Color.gray) + .frame(width: 8, height: 8) + } + } + .padding(15) + } +} diff --git a/Addame/Addame/Sources/SwiftUIHelpers/Preview.swift b/AddameSPM/Sources/SwiftUIExtension/Helper/Preview.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/Preview.swift rename to AddameSPM/Sources/SwiftUIExtension/Helper/Preview.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/ResignKeyboardOnDragGesture.swift b/AddameSPM/Sources/SwiftUIExtension/ResignKeyboardOnDragGesture.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/ResignKeyboardOnDragGesture.swift rename to AddameSPM/Sources/SwiftUIExtension/ResignKeyboardOnDragGesture.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/Shape+Extension.swift b/AddameSPM/Sources/SwiftUIExtension/Shape+Extension.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/Shape+Extension.swift rename to AddameSPM/Sources/SwiftUIExtension/Shape+Extension.swift diff --git a/Addame/Addame/Sources/SwiftUIExtension/SwiftUIExtension.swift b/AddameSPM/Sources/SwiftUIExtension/SwiftUIExtension.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIExtension/SwiftUIExtension.swift rename to AddameSPM/Sources/SwiftUIExtension/SwiftUIExtension.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/SwiftUIShims.swift b/AddameSPM/Sources/SwiftUIExtension/SwiftUIShims.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/SwiftUIShims.swift rename to AddameSPM/Sources/SwiftUIExtension/SwiftUIShims.swift diff --git a/Addame/Addame/Sources/SwiftUIHelpers/UIColor.swift b/AddameSPM/Sources/SwiftUIExtension/UIColor.swift similarity index 100% rename from Addame/Addame/Sources/SwiftUIHelpers/UIColor.swift rename to AddameSPM/Sources/SwiftUIExtension/UIColor.swift diff --git a/AddameSPM/Sources/SwiftUIExtension/View+Extension.swift b/AddameSPM/Sources/SwiftUIExtension/View+Extension.swift new file mode 100644 index 0000000..570d516 --- /dev/null +++ b/AddameSPM/Sources/SwiftUIExtension/View+Extension.swift @@ -0,0 +1,29 @@ +// +// View+Extension.swift +// +// +// Created by Saroar Khandoker on 12.11.2021. +// + +import SwiftUI + +extension View { + + @ViewBuilder public func listRowSeparatorHidden() -> some View { + if #available(iOS 15.0, *) { + self.listRowSeparator(.hidden) + } else { // ios 14 + self.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) + .listRowInsets(EdgeInsets(top: -1, leading: 16, bottom: -1, trailing: 16)) + .background(Color(.systemBackground)) + } + } + + @ViewBuilder public func stackNavigationViewStyle() -> some View { + if #available(iOS 15.0, *) { + self.navigationViewStyle(.stack) + } else { + self.navigationViewStyle(StackNavigationViewStyle()) + } + } +} diff --git a/AddameSPM/Sources/TabsView/TabsAction.swift b/AddameSPM/Sources/TabsView/TabsAction.swift new file mode 100644 index 0000000..6382c94 --- /dev/null +++ b/AddameSPM/Sources/TabsView/TabsAction.swift @@ -0,0 +1,48 @@ +// +// TabsAction.swift +// +// +// Created by Saroar Khandoker on 05.04.2021. +// + +import EventView +import ConversationsView +import ProfileView +import Foundation +import HTTPRequestKit +import WebSocketClient +import SwiftUI + +public enum TabsAction: Equatable { + case onAppear + case didSelectTab(Tab) + case event(EventsAction) + case conversation(ConversationsAction) + case profile(ProfileAction) + + case webSocket(WebSocketClient.Action) + case getAccessToketFromKeyChain(Result) + case receivedSocketMessage(Result) + case sendResponse(NSError?) + case tabViewIsHidden(Bool) + case scenePhase(ScenePhase) +} + +extension TabsAction { + static func view(_ localAction: TabsView.ViewAction) -> Self { + switch localAction { + case .onAppear: + return .onAppear + case let .didSelectTab(tab): + return .didSelectTab(tab) + case let .event(action): + return .event(action) + case let .conversation(action): + return .conversation(action) + case let .profile(action): + return .profile(action) + case let .tabViewIsHidden(value): + return .tabViewIsHidden(value) + } + } +} diff --git a/Addame/Addame/Sources/TabsView/TabsEnvironment.swift b/AddameSPM/Sources/TabsView/TabsEnvironment.swift similarity index 74% rename from Addame/Addame/Sources/TabsView/TabsEnvironment.swift rename to AddameSPM/Sources/TabsView/TabsEnvironment.swift index 30fba65..ad74b84 100644 --- a/Addame/Addame/Sources/TabsView/TabsEnvironment.swift +++ b/AddameSPM/Sources/TabsView/TabsEnvironment.swift @@ -7,7 +7,7 @@ import Combine import ComposableArchitecture -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels @@ -28,15 +28,14 @@ public struct TabsEnvironment { self.webSocketClient = webSocketClient } - public func getAccessToken() -> AnyPublisher { + public func getAccessToken() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { - assertionFailure("not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } @@ -49,3 +48,11 @@ public struct TabsEnvironment { return currentUSER } } + +extension TabsEnvironment { + public static let live: TabsEnvironment = .init( + backgroundQueue: .main, + mainQueue: .main, + webSocketClient: .live + ) +} diff --git a/Addame/Addame/Sources/TabsView/TabsReducer.swift b/AddameSPM/Sources/TabsView/TabsReducer.swift similarity index 76% rename from Addame/Addame/Sources/TabsView/TabsReducer.swift rename to AddameSPM/Sources/TabsView/TabsReducer.swift index 2950ff6..a494a91 100644 --- a/Addame/Addame/Sources/TabsView/TabsReducer.swift +++ b/AddameSPM/Sources/TabsView/TabsReducer.swift @@ -5,67 +5,34 @@ // Created by Saroar Khandoker on 06.04.2021. // -import AttachmentClient -import AttachmentClientLive -import AuthClient -import AuthClientLive import ComposableArchitecture import ComposableCoreLocation -import ConversationClient -import ConversationClientLive import ConversationsView -import EventClient -import EventClientLive import EventView import InfoPlist import KeychainService -import PathMonitorClient -import PathMonitorClientLive import ProfileView import SharedModels -import UserClient -import UserClientLive -public let tabsReducer = Reducer.combine( - eventReducer.pullback( +public let tabsReducer = Reducer< + TabsViewState, + TabsAction, + TabsEnvironment +>.combine( + eventsReducer.pullback( state: \.event, action: /TabsAction.event, - environment: { - EventsEnvironment( - pathMonitorClient: PathMonitorClient.live(queue: .main), - locationManager: LocationManager.live, - eventClient: EventClient.live(api: .build), - backgroundQueue: $0.backgroundQueue, - mainQueue: $0.mainQueue, - userDefaults: .live() - ) - } + environment: { _ in EventsEnvironment.live } ), conversationsReducer.pullback( state: \.conversations, action: /TabsAction.conversation, - environment: { - ConversationEnvironment( - conversationClient: ConversationClient.live(api: .build), - websocketClient: .live, - backgroundQueue: $0.backgroundQueue, - mainQueue: $0.mainQueue - ) - } + environment: { _ in ConversationEnvironment.live } ), profileReducer.pullback( state: \.profile, action: /TabsAction.profile, - environment: { - ProfileEnvironment( - userClient: UserClient.live(api: .build), - eventClient: EventClient.live(api: .build), - authClient: AuthClient.live(api: .build), - attachmentClient: AttachmentClient.live(api: .build), - backgroundQueue: $0.backgroundQueue, - mainQueue: $0.mainQueue - ) - } + environment: { _ in ProfileEnvironment.live } ), Reducer { state, action, environment in @@ -87,11 +54,24 @@ public let tabsReducer = Reducer.combine } switch action { + case let .scenePhase(phase): + switch phase { + case .background: debugPrint(#line, "background") + return .none + case .inactive: debugPrint(#line, "inactive") + return .none + case .active: debugPrint(#line, "active") + return getAcceccToken + @unknown default: + debugPrint(#line, "default") + return .none + } case .onAppear: - return getAcceccToken + return .none case let .didSelectTab(tab): state.selectedTab = tab + return .none case .event: @@ -103,6 +83,15 @@ public let tabsReducer = Reducer.combine case .profile: return .none + case let .tabViewIsHidden(value): +// let tab = state.selectedTab +// if value == true { +// state.isHidden = true +// } else if (tab == .event || tab == .conversation || tab == .profile) == true { +// state.isHidden = false +// } + + return .none case let .getAccessToketFromKeyChain(.success(accessToken)): @@ -111,6 +100,7 @@ public let tabsReducer = Reducer.combine return .none } + state.accessToken = accessToken var baseURL: URL { EnvironmentKeys.webSocketURL } return .merge( @@ -196,3 +186,4 @@ public let tabsReducer = Reducer.combine } } ) +.debug() diff --git a/AddameSPM/Sources/TabsView/TabsState.swift b/AddameSPM/Sources/TabsView/TabsState.swift new file mode 100644 index 0000000..3d26cd7 --- /dev/null +++ b/AddameSPM/Sources/TabsView/TabsState.swift @@ -0,0 +1,50 @@ +// +// TabsState.swift +// +// +// Created by Saroar Khandoker on 06.04.2021. +// + +import ConversationsView +import EventView +import ProfileView + +public enum Tab: Equatable { + case event + case conversation + case profile +} + +public struct TabsViewState: Equatable { + public init( + selectedTab: Tab, + event: EventsState, + conversations: ConversationsState, + profile: ProfileState + ) { + self.selectedTab = selectedTab + self.event = event + self.conversations = conversations + self.profile = profile + } + + public var selectedTab: Tab = .event + public var event: EventsState + public var conversations: ConversationsState + public var profile: ProfileState + public var isHidden = false + public var accessToken = "" +} + +extension TabsViewState { + public var view: TabsView.ViewState { + TabsView.ViewState( + selectedTab: selectedTab, + event: event, + conversations: conversations, + profile: profile, + isHidden: isHidden, + accessToken: accessToken + ) + } +} diff --git a/AddameSPM/Sources/TabsView/TabsView.swift b/AddameSPM/Sources/TabsView/TabsView.swift new file mode 100644 index 0000000..3aa320e --- /dev/null +++ b/AddameSPM/Sources/TabsView/TabsView.swift @@ -0,0 +1,163 @@ +// +// TabsView.swift +// +// +// Created by Saroar Khandoker on 06.04.2021. +// + +import ComposableArchitecture +import ConversationsView +import EventView +import ProfileView +import SwiftUI +import SwiftUIExtension + +public struct TabsView: View { + + public struct ViewState: Equatable { + public init( + selectedTab: Tab, + event: EventsState, + conversations: ConversationsState, + profile: ProfileState, + isHidden: Bool, + accessToken: String + ) { + self.selectedTab = selectedTab + self.event = event + self.conversations = conversations + self.profile = profile + self.isHidden = isHidden + self.accessToken = accessToken + } + + public var selectedTab: Tab + public var event: EventsState + public var conversations: ConversationsState + public var profile: ProfileState + public var isHidden = false + public var accessToken: String + } + + public enum ViewAction: Equatable { + case onAppear + case didSelectTab(Tab) + case event(EventsAction) + case conversation(ConversationsAction) + case profile(ProfileAction) + case tabViewIsHidden(Bool) + } + + @Environment(\.scenePhase) private var scenePhase + let store: Store + + public init(store: Store) { + self.store = store + } + + @State var isHidden = false + @State var tab: Tab = .event + + public var body: some View { + WithViewStore( + self.store.scope( + state: { $0.view }, + action: TabsAction.view + ) + ) { viewStore in + + HidableTabView( + isHidden: viewStore.binding(get: { $0.isHidden }, send: ViewAction.tabViewIsHidden), + selection: viewStore.binding(get: { $0.selectedTab }, send: ViewAction.didSelectTab) + ) { + NavigationView { + EventView( + store: store.scope(state: \.event, action: TabsAction.event) + ) + .onAppear { + ViewStore(store.stateless).send(.event(.onAppear)) + } + + } + .tabItem { + Image(systemName: "list.bullet.below.rectangle") + Text("Event") + } + .tag(Tab.event) + + NavigationView { + ConversationsView( + store: store.scope(state: \.conversations, action: TabsAction.conversation) + ) + .onAppear { + self.isHidden = false + print("### \(self.isHidden) ConversationsView onAppear") + print("### \(self.tab) ConversationsView onAppear") +// viewStore.send(.tabViewIsHidden) + ViewStore(store.stateless).send(.conversation(.onAppear)) + } + .onDisappear { +// self.isHidden.toggle() + print("### \(self.isHidden) ConversationsView onDisAppear") + viewStore.send(.tabViewIsHidden(true)) + } + } + .tabItem { + Image(systemName: "bubble.left.and.bubble.right") + Text("Chat") + } + .tag(Tab.conversation) + + NavigationView { + ProfileView( + store: store.scope(state: \.profile, action: TabsAction.profile) + ) + .onAppear { +// viewStore.send(.tabViewIsHidden) + ViewStore(store.stateless).send(.profile(.onAppear)) + } + .onDisappear { + viewStore.send(.tabViewIsHidden(true)) + } + } + .tabItem { + Image(systemName: "person") + Text("Profile") + } + .tag(Tab.profile) + + } + .onAppear { + viewStore.send(.onAppear) + } + .onChange(of: scenePhase) { phase in + ViewStore(store.stateless).send(.scenePhase(phase)) + } + } + } +} + +// struct TabsView_Previews: PreviewProvider { +// static let tabsEnv = TabsEnvironment( +// backgroundQueue: .immediate, +// mainQueue: .immediate, +// webSocketClient: .live +// ) +// +// static let tabsState = TabsState( +// selectedTab: .event, +// event: EventsState.placeholderEvents, +// conversations: ConversationsState.placholderConversations, +// profile: ProfileState() +// ) +// +// static let store = Store( +// initialState: tabsState, +// reducer: tabsReducer, +// environment: tabsEnv +// ) +// +// static var previews: some View { +// TabsView(store: store) +// } +// } diff --git a/Addame/Addame/Sources/UIApplicationClient/Client.swift b/AddameSPM/Sources/UIApplicationClient/Client.swift similarity index 100% rename from Addame/Addame/Sources/UIApplicationClient/Client.swift rename to AddameSPM/Sources/UIApplicationClient/Client.swift diff --git a/Addame/Addame/Sources/UIApplicationClient/Live.swift b/AddameSPM/Sources/UIApplicationClient/Live.swift similarity index 100% rename from Addame/Addame/Sources/UIApplicationClient/Live.swift rename to AddameSPM/Sources/UIApplicationClient/Live.swift diff --git a/Addame/Addame/Sources/UIApplicationClient/Mocks.swift b/AddameSPM/Sources/UIApplicationClient/Mocks.swift similarity index 100% rename from Addame/Addame/Sources/UIApplicationClient/Mocks.swift rename to AddameSPM/Sources/UIApplicationClient/Mocks.swift diff --git a/Addame/Addame/Sources/UserClient/Mocks.swift b/AddameSPM/Sources/UserClient/Mocks.swift similarity index 93% rename from Addame/Addame/Sources/UserClient/Mocks.swift rename to AddameSPM/Sources/UserClient/Mocks.swift index ff1600e..324157b 100644 --- a/Addame/Addame/Sources/UserClient/Mocks.swift +++ b/AddameSPM/Sources/UserClient/Mocks.swift @@ -7,7 +7,7 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import KeychainService import SharedModels @@ -59,25 +59,25 @@ extension UserClient { public static let happyPath = Self( userMeHandler: { _, _ in Just(user) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() }, update: { _, _ in user.firstName = "Swift" user.lastName = "Xcode" return Just(user) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } ) public static let failed = Self( userMeHandler: { _, _ in - Fail(error: HTTPError.authError(404)) + Fail(error: HTTPRequest.HRError.authError(404)) .eraseToAnyPublisher() }, update: { _, _ in - Fail(error: HTTPError.authError(404)) + Fail(error: HTTPRequest.HRError.authError(404)) .eraseToAnyPublisher() } ) diff --git a/Addame/Addame/Sources/UserClient/UserClient.swift b/AddameSPM/Sources/UserClient/UserClient.swift similarity index 84% rename from Addame/Addame/Sources/UserClient/UserClient.swift rename to AddameSPM/Sources/UserClient/UserClient.swift index 84ce276..800547b 100644 --- a/Addame/Addame/Sources/UserClient/UserClient.swift +++ b/AddameSPM/Sources/UserClient/UserClient.swift @@ -1,11 +1,11 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import SharedModels public struct UserClient { - public typealias UserMeHandler = (String, String) -> AnyPublisher - public typealias UserUpdateHandler = (User, String) -> AnyPublisher + public typealias UserMeHandler = (String, String) -> AnyPublisher + public typealias UserUpdateHandler = (User, String) -> AnyPublisher public let userMeHandler: UserMeHandler public let update: UserUpdateHandler diff --git a/Addame/Addame/Sources/UserClientLive/Live.swift b/AddameSPM/Sources/UserClientLive/Live.swift similarity index 69% rename from Addame/Addame/Sources/UserClientLive/Live.swift rename to AddameSPM/Sources/UserClientLive/Live.swift index fa4d62d..b4c30e6 100644 --- a/Addame/Addame/Sources/UserClientLive/Live.swift +++ b/AddameSPM/Sources/UserClientLive/Live.swift @@ -7,21 +7,21 @@ import Combine import Foundation -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels import UserClient -func token() -> AnyPublisher { +func token() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { print(#line, "not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } @@ -32,10 +32,10 @@ public struct UserAPI { private func tokenHandle( input: Input, path: String, - method: HTTPMethod - ) -> AnyPublisher { - return token().flatMap { token -> AnyPublisher in - let builder: HttpRequest = .build( + method: HTTPRequest.Method + ) -> AnyPublisher { + return token().flatMap { token -> AnyPublisher in + let builder: HTTPRequest = .build( baseURL: baseURL, method: method, authType: .bearer(token: token), @@ -45,31 +45,31 @@ public struct UserAPI { ) return builder.send(scheduler: RunLoop.main) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func me(id: String, path: String) -> AnyPublisher { + public func me(id: String, path: String) -> AnyPublisher { return tokenHandle(input: id, path: path, method: .get) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } - public func update(user: User, path: String) -> AnyPublisher { + public func update(user: User, path: String) -> AnyPublisher { return tokenHandle(input: user, path: path, method: .post) - .catch { (error: HTTPError) -> AnyPublisher in + .catch { (error: HTTPRequest.HRError) -> AnyPublisher in Fail(error: error).eraseToAnyPublisher() } .receive(on: DispatchQueue.main) diff --git a/Addame/Addame/Sources/UserDefaultsClient/Interface.swift b/AddameSPM/Sources/UserDefaultsClient/Interface.swift similarity index 100% rename from Addame/Addame/Sources/UserDefaultsClient/Interface.swift rename to AddameSPM/Sources/UserDefaultsClient/Interface.swift diff --git a/Addame/Addame/Sources/UserDefaultsClient/Live.swift b/AddameSPM/Sources/UserDefaultsClient/Live.swift similarity index 95% rename from Addame/Addame/Sources/UserDefaultsClient/Live.swift rename to AddameSPM/Sources/UserDefaultsClient/Live.swift index d31617d..6c00c61 100644 --- a/Addame/Addame/Sources/UserDefaultsClient/Live.swift +++ b/AddameSPM/Sources/UserDefaultsClient/Live.swift @@ -1,3 +1,5 @@ +import Combine +import ComposableArchitecture import Foundation extension UserDefaultsClient { diff --git a/Addame/Addame/Sources/UserDefaultsClient/Mocks.swift b/AddameSPM/Sources/UserDefaultsClient/Mocks.swift similarity index 100% rename from Addame/Addame/Sources/UserDefaultsClient/Mocks.swift rename to AddameSPM/Sources/UserDefaultsClient/Mocks.swift diff --git a/Addame/Addame/Sources/UserNotificationClient/Interface.swift b/AddameSPM/Sources/UserNotificationClient/Interface.swift similarity index 100% rename from Addame/Addame/Sources/UserNotificationClient/Interface.swift rename to AddameSPM/Sources/UserNotificationClient/Interface.swift diff --git a/Addame/Addame/Sources/UserNotificationClient/Live.swift b/AddameSPM/Sources/UserNotificationClient/Live.swift similarity index 100% rename from Addame/Addame/Sources/UserNotificationClient/Live.swift rename to AddameSPM/Sources/UserNotificationClient/Live.swift diff --git a/Addame/Addame/Sources/UserNotificationClient/Mocks.swift b/AddameSPM/Sources/UserNotificationClient/Mocks.swift similarity index 100% rename from Addame/Addame/Sources/UserNotificationClient/Mocks.swift rename to AddameSPM/Sources/UserNotificationClient/Mocks.swift diff --git a/Addame/Addame/Sources/WebSocketClient/WebSocketClient.swift b/AddameSPM/Sources/WebSocketClient/WebSocketClient.swift similarity index 88% rename from Addame/Addame/Sources/WebSocketClient/WebSocketClient.swift rename to AddameSPM/Sources/WebSocketClient/WebSocketClient.swift index c80ccb3..e7e9f3c 100644 --- a/Addame/Addame/Sources/WebSocketClient/WebSocketClient.swift +++ b/AddameSPM/Sources/WebSocketClient/WebSocketClient.swift @@ -1,6 +1,6 @@ import Combine import ComposableArchitecture -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels @@ -9,13 +9,13 @@ import SwiftUI public struct WebSocketClient { public init( cancel: @escaping (String, URLSessionWebSocketTask.CloseCode, Data?) -> Effect, - open: @escaping (String, URL, String, [String]) -> Effect, + `open`: @escaping (AnyHashable, URL, String, [String]) -> Effect, receive: @escaping (String) -> Effect, send: @escaping (String, URLSessionWebSocketTask.Message) -> Effect, sendPing: @escaping (String) -> Effect ) { self.cancel = cancel - self.open = open + self.open = `open` self.receive = receive self.send = send self.sendPing = sendPing @@ -56,7 +56,7 @@ public struct WebSocketClient { } public var cancel: (String, URLSessionWebSocketTask.CloseCode, Data?) -> Effect - public var open: (String, URL, String, [String]) -> Effect + public var `open`: (AnyHashable, URL, String, [String]) -> Effect public var receive: (String) -> Effect public var send: (String, URLSessionWebSocketTask.Message) -> Effect public var sendPing: (String) -> Effect diff --git a/Addame/Addame/Sources/WebSocketClientLive/Live.swift b/AddameSPM/Sources/WebSocketClientLive/Live.swift similarity index 96% rename from Addame/Addame/Sources/WebSocketClientLive/Live.swift rename to AddameSPM/Sources/WebSocketClientLive/Live.swift index f95537b..3d4be15 100644 --- a/Addame/Addame/Sources/WebSocketClientLive/Live.swift +++ b/AddameSPM/Sources/WebSocketClientLive/Live.swift @@ -7,22 +7,22 @@ import Combine import ComposableArchitecture -import HttpRequest +import HTTPRequestKit import InfoPlist import KeychainService import SharedModels import SwiftUI import WebSocketClient -func token() -> AnyPublisher { +func token() -> AnyPublisher { guard let token: AuthTokenResponse = KeychainService.loadCodable(for: .token) else { print(#line, "not Authorized Token are missing") - return Fail(error: HTTPError.missingTokenFromIOS) + return Fail(error: HTTPRequest.HRError.missingTokenFromIOS) .eraseToAnyPublisher() } return Just(token.accessToken) - .setFailureType(to: HTTPError.self) + .setFailureType(to: HTTPRequest.HRError.self) .eraseToAnyPublisher() } diff --git a/Addame/Addame/Tests/AppFeatureTests/AppFeatureTests.swift b/AddameSPM/Tests/AppFeatureTests/AppFeatureTests.swift similarity index 100% rename from Addame/Addame/Tests/AppFeatureTests/AppFeatureTests.swift rename to AddameSPM/Tests/AppFeatureTests/AppFeatureTests.swift diff --git a/AddameSPM/Tests/AuthenticationViewTests/AuthenticationViewTests.swift b/AddameSPM/Tests/AuthenticationViewTests/AuthenticationViewTests.swift new file mode 100644 index 0000000..306cb09 --- /dev/null +++ b/AddameSPM/Tests/AuthenticationViewTests/AuthenticationViewTests.swift @@ -0,0 +1,172 @@ +// +// AuthenticationViewTests.swift +// +// +// Created by Saroar Khandoker on 17.09.2021. +// + +import ComposableArchitecture +import KeychainService +import PhoneNumberKit +import SharedModels +import HTTPRequestKit +import SwiftUI +import Combine +import AuthClient + +@testable import AuthenticationView +import XCTest + +class AuthenticationViewTests: XCTestCase { + let scheduler = DispatchQueue.test + + func testFlow_Success_WithValidPhoneNumber() { + + let state = LoginState() + + let environment = AuthenticationEnvironment( + authClient: .happyPath, userDefaults: .live(), + mainQueue: scheduler.eraseToAnyScheduler() + ) + + let store = TestStore( + initialState: state, + reducer: loginReducer, + environment: environment + ) + + store.send(.sendPhoneNumberButtonTapped("+79218888888")) { + $0.isLoginRequestInFlight = true + } + scheduler.advance() + store.receive( + .loninResponse( + .success( + .init(phoneNumber: "+79218888888", + attemptId: "165541EC-692E-440A-9CF8-565776E9DC99", + code: "336699") + ) + ) + ) { + $0.isLoginRequestInFlight = false + $0.isValidationCodeIsSend = true + $0.authResponse = AuthResponse( + phoneNumber: "+79218888888", + attemptId: "165541EC-692E-440A-9CF8-565776E9DC99", + code: "336699" + ) + } + store.send(.verificationRequest("336699")) { + if $0.authResponse.code!.count == 6 { + $0.isLoginRequestInFlight = true + $0.authResponse.code = "336699" + } + } + scheduler.advance() + store.receive( + .verificationResponse( + .success(.init( + status: "online", + user: User( + id: "5fabb05d2470c17919b3c0e2", + phoneNumber: "+79218888888", + firstName: "AuthClientMock", + createdAt: Date(), updatedAt: Date() + ), + access: AuthTokenResponse(accessToken: "", refreshToken: "") + ) + ) + ) + ) + + } + + func testFlow_Fail_WithInvalidPhoneNumber() { + let authRes = AuthResponse(phoneNumber: "+7921888888") + let state = LoginState() + + let environment = AuthenticationEnvironment( + authClient: .failing, userDefaults: .live(), + mainQueue: scheduler.eraseToAnyScheduler() + ) + + let store = TestStore( + initialState: state, + reducer: loginReducer, + environment: environment + ) + + store.send(.sendPhoneNumberButtonTapped(authRes.phoneNumber)) { + $0.isLoginRequestInFlight = false + } + + } + + // swiftlint:disable function_body_length + func testFlow_Fail_WithValidPhoneNumber_AndInvalidCode() { + + var authClient = AuthClient.failing + authClient.login = { _ in + Just( + AuthResponse( + phoneNumber: "+79218888888", + attemptId: "165541EC-692E-440A-9CF8-565776E9DC99", + code: "336699" + ) + ) + .setFailureType(to: HTTPRequest.HRError.self) + .eraseToAnyPublisher() + } + + let state = LoginState() + + let environment = AuthenticationEnvironment( + authClient: authClient, userDefaults: .live(), + mainQueue: scheduler.eraseToAnyScheduler() + ) + + let store = TestStore( + initialState: state, + reducer: loginReducer, + environment: environment + ) + + store.send(.sendPhoneNumberButtonTapped("+79218888888")) { + $0.isLoginRequestInFlight = true + } + scheduler.advance() + store.receive( + .loninResponse( + .success( + .init(phoneNumber: "+79218888888", + attemptId: "165541EC-692E-440A-9CF8-565776E9DC99", + code: "336699") + ) + ) + ) { + $0.isLoginRequestInFlight = false + $0.isValidationCodeIsSend = true + $0.authResponse = AuthResponse( + phoneNumber: "+79218888888", + attemptId: "165541EC-692E-440A-9CF8-565776E9DC99", + code: "336699" + ) + } + store.send(.verificationRequest("336699")) { + if $0.authResponse.code!.count == 6 { + $0.isLoginRequestInFlight = true + $0.authResponse.code = "336699" + } + } + scheduler.advance() + store.receive( + .verificationResponse( + .failure( + HTTPRequest.HRError.custom("verification fail", "") + ) + ) + ) { + $0.alert = .init(title: TextState("Please try again!") ) + } + } +} diff --git a/Addame/Addame/Tests/EventFormViewTests/EventFormViewTests.swift b/AddameSPM/Tests/EventFormViewTests/EventFormViewTests.swift similarity index 86% rename from Addame/Addame/Tests/EventFormViewTests/EventFormViewTests.swift rename to AddameSPM/Tests/EventFormViewTests/EventFormViewTests.swift index badf6c4..19fd3b3 100644 --- a/Addame/Addame/Tests/EventFormViewTests/EventFormViewTests.swift +++ b/AddameSPM/Tests/EventFormViewTests/EventFormViewTests.swift @@ -8,7 +8,7 @@ import ComposableArchitecture import Contacts import CoreLocation -import HttpRequest +import HTTPRequestKit import Intents import KeychainService import MapKit @@ -19,10 +19,11 @@ import XCTest class EventFormViewTests: XCTestCase { let scheduler = DispatchQueue.test + let now = Date(timeIntervalSince1970: 0) // swiftlint:disable function_body_length line_length func testCreatEvent() { - let now = Date() + let attachments = [ Attachment( id: "5fb6736c1432f950f8ea2d33", @@ -127,16 +128,15 @@ class EventFormViewTests: XCTestCase { store.receive( .eventsResponse( .success( - .init( - id: "5fb1510012de9980bd0c2efc", - name: "Testing data", - details: "Waitting for details", - imageUrl: - "https://avatars.mds.yandex.net/get-pdb/2776508/af73774d-7409-4e73-81c8-c8ab127c2f8b/s1200?webp=false", - duration: 14400, categories: "General", - isActive: true, addressName: "8к1литД улица Вавиловых , Saint Petersburg", - type: .Point, sponsored: false, overlay: false, - coordinates: [60.020532228306031, 30.388014239849944] + EventResponse.Item( + id: "5fbfe53675a93bda87c7cb16", name: "Cool :)", categories: "General", + imageUrl: "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/1605811270871.jpeg", + duration: 14400, isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", + sponsored: false, overlay: false, + coordinates: [60.020532228306031, 30.388014239849944], + createdAt: now, + updatedAt: now ) ) ) diff --git a/AddameSPM/Tests/EventViewTests/EventsViewTests.swift b/AddameSPM/Tests/EventViewTests/EventsViewTests.swift new file mode 100644 index 0000000..3ccaca7 --- /dev/null +++ b/AddameSPM/Tests/EventViewTests/EventsViewTests.swift @@ -0,0 +1,208 @@ +// +// EventsViewTests.swift +// +// +// Created by Saroar Khandoker on 14.09.2021. +// + +import XCTest +import ComposableArchitecture +import ComposableCoreLocation +import HTTPRequestKit +import KeychainService +import SharedModels +import PathMonitorClient +import Combine +import CoreLocation +import MapKit + +@testable import EventView +@testable import EventFormView + +class EventsView: XCTestCase { + let scheduler = DispatchQueue.test + let data = Date(timeIntervalSince1970: 0) + + // swiftlint:disable function_body_length + func testRequestLocation_Allow() { + let state = EventsState.placeholderEvents + + let environment = EventsEnvironment( + pathMonitorClient: .satisfied, + locationManager: .failing, + eventClient: .empty, + backgroundQueue: scheduler.eraseToAnyScheduler(), + mainQueue: scheduler.eraseToAnyScheduler(), + userDefaults: .noop + ) + + let store = TestStore( + initialState: state, + reducer: eventReducer, + environment: environment + ) + + var didRequestInUseAuthorization = false + var didRequestLocation = false + let locationManagerSubject = PassthroughSubject() + + store.environment.locationManager.authorizationStatus = { .notDetermined } + store.environment.locationManager.delegate = { locationManagerSubject.eraseToEffect() } + store.environment.locationManager.locationServicesEnabled = { true } + store.environment.locationManager.requestLocation = { + .fireAndForget { didRequestLocation = true } + } + + store.environment.locationManager.requestWhenInUseAuthorization = { + .fireAndForget { didRequestInUseAuthorization = true } + } + + let currentLocation = Location( + altitude: 0, + coordinate: CLLocationCoordinate2D(latitude: 60.020532228306031, longitude: 30.388014239849944), + course: 0, + horizontalAccuracy: 0, + speed: 0, + timestamp: Date(timeIntervalSince1970: 0), + verticalAccuracy: 0 + ) + + store.send(.onAppear) + + store.send(.currentLocationButtonTapped) { + $0.isRequestingCurrentLocation = true + } + XCTAssertTrue(didRequestInUseAuthorization) + + // Simulate being given authorized to access location + locationManagerSubject.send(.didChangeAuthorization(.authorizedAlways)) + store.receive(.locationManager(.didChangeAuthorization(.authorizedAlways))) + XCTAssertTrue(didRequestLocation) + + // Simulate finding the user's current location + locationManagerSubject.send(.didUpdateLocations([currentLocation])) + store.receive(.locationManager(.didUpdateLocations([currentLocation]))) { + $0.isRequestingCurrentLocation = false + } + + locationManagerSubject.send(completion: .finished) + } + + // swiftlint:disable function_body_length + func testFlow_Success_GetEvents() { + + let state = EventsState.placeholderEvents + + let environment = EventsEnvironment( + pathMonitorClient: .satisfied, + locationManager: .failing, + eventClient: .happyPath, + backgroundQueue: scheduler.eraseToAnyScheduler(), + mainQueue: scheduler.eraseToAnyScheduler(), + userDefaults: .noop + ) + + let store = TestStore( + initialState: state, + reducer: eventReducer, + environment: environment + ) + + var didRequestInUseAuthorization = false + var didRequestLocation = false + let locationManagerSubject = PassthroughSubject() + + store.environment.locationManager.authorizationStatus = { .notDetermined } + store.environment.locationManager.delegate = { locationManagerSubject.eraseToEffect() } + store.environment.locationManager.locationServicesEnabled = { true } + store.environment.locationManager.requestLocation = { + .fireAndForget { didRequestLocation = true } + } + + store.environment.locationManager.requestWhenInUseAuthorization = { + .fireAndForget { didRequestInUseAuthorization = true } + } + + let currentLocation = Location( + altitude: 0, + coordinate: CLLocationCoordinate2D(latitude: 60.020532228306031, longitude: 30.388014239849944), + course: 0, + horizontalAccuracy: 0, + speed: 0, + timestamp: Date(timeIntervalSince1970: 0), + verticalAccuracy: 0 + ) + + store.send(.onAppear) + + store.send(.currentLocationButtonTapped) { + $0.isRequestingCurrentLocation = true + } + XCTAssertTrue(didRequestInUseAuthorization) + + // Simulate being given authorized to access location + locationManagerSubject.send(.didChangeAuthorization(.authorizedAlways)) + scheduler.advance() + store.receive(.locationManager(.didChangeAuthorization(.authorizedAlways))) + XCTAssertTrue(didRequestLocation) + + // Simulate finding the user's current location + locationManagerSubject.send(.didUpdateLocations([currentLocation])) + scheduler.advance() + store.receive(.locationManager(.didUpdateLocations([currentLocation]))) { + $0.isRequestingCurrentLocation = false + } + + locationManagerSubject.send(completion: .finished) + + scheduler.advance() + store.send(.eventsResponse(.success( + EventResponse( + items: [ + .init( + id: "5fbfe53675a93bda87c7cb10", name: "Cool :)", categories: "General", + duration: 14400, isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", + sponsored: false, overlay: false, + coordinates: [60.020532228306031, 30.388014239849944], createdAt: data, + updatedAt: data), + .init( + id: "5fbe8a8c8ba94be8a688324c", name: "Awesome 🤩 app", categories: "General", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", + sponsored: false, overlay: false, + coordinates: [60.020525506753494, 30.387988546891499], createdAt: data, + updatedAt: data) + ], + metadata: .init(per: 2, total: 4, page: 1) + ) + ))) { + $0.waitingForUpdateLocation = false + $0.canLoadMorePages = $0.events.count < 4 + $0.isLoadingPage = false +// $0.currentPage += 1 + + let events = ( + $0.events + + [ + .init( + id: "5fbfe53675a93bda87c7cb10", name: "Cool :)", categories: "General", + duration: 14400, isActive: true, conversationsId: "5fbfe5361cdd72e23297914a", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", + sponsored: false, overlay: false, + coordinates: [60.020532228306031, 30.388014239849944], createdAt: self.data, + updatedAt: self.data), + .init( + id: "5fbe8a8c8ba94be8a688324c", name: "Awesome 🤩 app", categories: "General", + duration: 14400, isActive: true, conversationsId: "5fbe8a8c492346f651b57946", + addressName: "8к1литД улица Вавиловых , Saint Petersburg", type: "Point", + sponsored: false, overlay: false, + coordinates: [60.020525506753494, 30.387988546891499], createdAt: self.data, + updatedAt: self.data) + ] + ) + $0.events = .init(uniqueElements: events) + } + } + +} diff --git a/Addame/Addame/Tests/MapViewTests/MapViewTests.swift b/AddameSPM/Tests/MapViewTests/MapViewTests.swift similarity index 100% rename from Addame/Addame/Tests/MapViewTests/MapViewTests.swift rename to AddameSPM/Tests/MapViewTests/MapViewTests.swift diff --git a/Gemfile.lock b/Gemfile.lock index 5617844..78e685c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,23 +1,24 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.3) + CFPropertyList (3.0.4) + rexml addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.496.0) - aws-sdk-core (3.121.0) + aws-partitions (1.516.0) + aws-sdk-core (3.121.2) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.239.0) aws-sigv4 (~> 1.1) jmespath (~> 1.0) - aws-sdk-kms (1.48.0) - aws-sdk-core (~> 3, >= 3.120.0) + aws-sdk-kms (1.50.0) + aws-sdk-core (~> 3, >= 3.121.2) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.102.0) - aws-sdk-core (~> 3, >= 3.120.0) + aws-sdk-s3 (1.104.0) + aws-sdk-core (~> 3, >= 3.121.2) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) aws-sigv4 (1.4.0) @@ -34,9 +35,9 @@ GEM domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) dotenv (2.7.6) - emoji_regex (3.2.2) - excon (0.85.0) - faraday (1.7.1) + emoji_regex (3.2.3) + excon (0.87.0) + faraday (1.8.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -58,10 +59,10 @@ GEM faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) - faraday_middleware (1.1.0) + faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.5) - fastlane (2.193.1) + fastlane (2.196.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -101,7 +102,7 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.11.0) + google-apis-androidpublisher_v3 (0.12.0) google-apis-core (>= 0.4, < 2.a) google-apis-core (0.4.1) addressable (~> 2.5, >= 2.5.1) @@ -116,14 +117,14 @@ GEM google-apis-core (>= 0.4, < 2.a) google-apis-playcustomapp_v1 (0.5.0) google-apis-core (>= 0.4, < 2.a) - google-apis-storage_v1 (0.6.0) + google-apis-storage_v1 (0.8.0) google-apis-core (>= 0.4, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.5.0) faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.1.0) + google-cloud-errors (1.2.0) google-cloud-storage (1.34.1) addressable (~> 2.5) digest-crc (~> 0.4) @@ -132,30 +133,30 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (0.17.1) + googleauth (1.0.0) faraday (>= 0.17.3, < 2.0) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.15) + signet (>= 0.16, < 2.a) highline (2.0.3) http-cookie (1.0.4) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.4.0) - json (2.3.1) - jwt (2.2.3) + json (2.6.0) + jwt (2.3.0) memoist (0.16.2) - mini_magick (4.10.1) - mini_mime (1.1.1) + mini_magick (4.11.0) + mini_mime (1.1.2) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) naturally (2.2.1) optparse (0.1.1) os (1.1.1) - plist (3.5.0) + plist (3.6.0) public_suffix (4.0.6) rake (13.0.6) representable (3.1.1) @@ -166,7 +167,7 @@ GEM rexml (3.2.5) rouge (2.0.7) ruby2_keywords (0.0.5) - rubyzip (2.3.0) + rubyzip (2.3.2) security (0.1.3) signet (0.16.0) addressable (~> 2.8) @@ -187,19 +188,20 @@ GEM uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.7) - unicode-display_width (1.7.0) + unf_ext (0.0.8) + unicode-display_width (1.8.0) webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.19.0) + xcodeproj (1.21.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.0) + xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS diff --git a/fastlane/Fastfile.swift b/fastlane/Fastfile.swift index 5e5108a..755e02f 100644 --- a/fastlane/Fastfile.swift +++ b/fastlane/Fastfile.swift @@ -26,7 +26,7 @@ class Fastfile: LaneFile { func buildLane() { desc("Build for testing") scan(workspace: "Addame.xcworkspace", - scheme: "Addame", + scheme: "AddameCI", derivedDataPath: "derivedData", buildForTesting: .userDefined(true), xcargs: "CI=true") @@ -36,7 +36,7 @@ class Fastfile: LaneFile { desc("Run unit tests") scan( workspace: "Addame.xcworkspace", - scheme: "Addame", + scheme: "AddameCI", device: "iPhone 12 Pro", resetSimulator: false, onlyTesting: ["EventFormViewTests"], @@ -61,12 +61,27 @@ class Fastfile: LaneFile { } desc("Push a new beta build to TestFlight") - incrementBuildNumber(xcodeproj: "Addame.xcodeproj") - incrementVersionNumber(bumpType: "minor", xcodeproj: "Addame.xcodeproj") - buildApp(workspace: "Addame.xcworkspace", scheme: "Addame") +// incrementBuildNumber(xcodeproj: "Addame.xcodeproj") + echo(message: "DumpType parameter value \(dumpType)") + incrementVersionNumber(bumpType: dumpType, xcodeproj: "Addame.xcodeproj") + buildApp(workspace: "Addame.xcworkspace", scheme: "AddamePro") uploadToTestflight(username: "\(appleID)", teamId: "\(teamId)") } + func releaseLane() { +// lane :release do +// capture_screenshots # generate new screenshots for the App Store +// sync_code_signing(type: "appstore") +// # see code signing guide for more information +// build_app(scheme: "MyApp") +// upload_to_app_store # upload your app to App Store Connect +// slack(message: "Successfully uploaded a new App Store build") +// end + // getPushCertificate(appIdentifier: <#String#>, username: <#String#>, p12Password: <#String#>) + buildApp() + uploadToAppStore() + } + func sandbox() { desc("Sandbox start") captureScreenshots() @@ -87,52 +102,3 @@ class Fastfile: LaneFile { ) } } - -// platform :ios do -// desc "Push a new beta build to TestFlight" -// lane :tf do -// increment_build_number(xcodeproj: "AddaMeIOS.xcodeproj") -// build_app(scheme: "AddaMeIOS") -// upload_to_testflight -// end -// -// desc "Push a new release build" -// lane :release do -// precheck -// increment_build_number(xcodeproj: "AddaMeIOS.xcodeproj") -// snapshot -// frameit -// deliver( -// submit_for_review: true, -// automatic_release: true, -// force: true, # Skip HTMl report verification -// skip_metadata: true, -// skip_screenshots: false, -// skip_binary_upload: true -// ) -// end -// -// desc "Generate new localized screenshots" -// lane :screenshots do -// capture_screenshots(workspace: "AddaMeIOS.xcodeproj", scheme: "AddaMeIOSUITests") -// end -// -// lane :sandbox do -// capture_screenshots -// frame_screenshots(white: true) -// frameit(path: "./fastlane/screenshots") -// end -// -// lane :submit_review do -// frame_screenshots(white: true) -// frameit(path: "./fastlane/screenshots") -// deliver( -// submit_for_review: true, -// automatic_release: true, -// force: true, # Skip HTMl report verification -// skip_metadata: true, -// skip_screenshots: false, -// skip_binary_upload: true -// ) -// end -// end diff --git a/test_output/report.html b/test_output/report.html deleted file mode 100644 index 4bb3d78..0000000 --- a/test_output/report.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - Test Results | xcpretty - - - - -
-
-

Test Results

-
-
-
-

0 tests

- -
-
- AllFailingPassing -
-
-
-
- -
- - - diff --git a/test_output/report.junit b/test_output/report.junit deleted file mode 100644 index 1e19aa8..0000000 --- a/test_output/report.junit +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file