From 5ad8409ab1190d67c7acf74916410ad444cd7d27 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Tue, 2 Aug 2022 23:30:53 -0600 Subject: [PATCH 1/8] refactor: many fixes and improvements for beta.6 release adds conditional intercepting, changes to flutter_lints, updates example project, removes barrel files --- .metadata | 27 +- CHANGELOG.md | 5 + README.md | 2 +- analysis_options.yaml | 4 + analysis_options.yml | 1 - example/.metadata | 27 +- example/analysis_options.yaml | 29 + example/android/.gitignore | 2 + example/android/app/build.gradle | 26 +- .../android/app/src/debug/AndroidManifest.xml | 3 +- .../android/app/src/main/AndroidManifest.xml | 18 +- .../com/example/example/MainActivity.kt | 6 - .../app/src/main/res/values-night/styles.xml | 4 +- .../app/src/main/res/values/styles.xml | 14 +- .../app/src/profile/AndroidManifest.xml | 3 +- example/android/build.gradle | 8 +- example/android/gradle.properties | 1 - .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 18 +- example/ios/.gitignore | 2 + example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile.lock | 18 +- example/ios/Runner.xcodeproj/project.pbxproj | 126 +- .../xcshareddata/xcschemes/Runner.xcscheme | 10 +- example/ios/Runner/Info.plist | 92 +- example/ios/Runner/Runner-Bridging-Header.h | 2 +- example/lib/cities.dart | 8865 +++++++---------- example/lib/common.dart | 25 + example/lib/credentials.dart | 5 +- example/lib/main.dart | 378 +- example/lib/multipart_app.dart | 178 + example/lib/weather_app.dart | 357 + example/pubspec.yaml | 7 +- lib/extensions/base_request.dart | 7 +- lib/extensions/base_response_io.dart | 6 +- lib/extensions/base_response_none.dart | 6 +- lib/extensions/extensions.dart | 10 - lib/extensions/streamed_request.dart | 2 +- lib/extensions/uri.dart | 2 +- lib/http/http.dart | 2 +- lib/http/http_methods.dart | 1 + lib/http/intercepted_client.dart | 31 +- lib/http/intercepted_http.dart | 2 +- lib/http_interceptor.dart | 21 +- lib/models/http_interceptor_exception.dart | 3 +- .../interceptor_contract.dart | 4 + lib/models/models.dart | 2 - lib/utils/query_parameters.dart | 2 +- pubspec.yaml | 8 +- test/extensions/request_test.dart | 8 +- 50 files changed, 4478 insertions(+), 5906 deletions(-) create mode 100644 analysis_options.yaml delete mode 100644 analysis_options.yml create mode 100644 example/analysis_options.yaml create mode 100644 example/lib/common.dart create mode 100644 example/lib/multipart_app.dart create mode 100644 example/lib/weather_app.dart delete mode 100644 lib/extensions/extensions.dart rename lib/{http => models}/interceptor_contract.dart (89%) delete mode 100644 lib/models/models.dart diff --git a/.metadata b/.metadata index 2c8ec56..8472cba 100644 --- a/.metadata +++ b/.metadata @@ -1,10 +1,33 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713 + revision: f1875d570e39de09040c8f79aa13cc56baab8db1 channel: stable project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: android + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: ios + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/CHANGELOG.md b/CHANGELOG.md index 54a118c..a9aa44f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 2.0.0-beta.6 + +- ✨  Added: `Future shouldInterceptRequest()` and `Future shouldInterceptResponse()`. This enables individual interceptor checks and conditional intercepting configurations. +- 📖  Changed: **example** project to showcase updated Flutter 3.0, new library APIs and `MultipartRequest` handling. + ## 2.0.0-beta.5 - ✨  Added: Support for `onRequestTimeout` when setting up `requestTimeout` on the interceptor. diff --git a/README.md b/README.md index 9722d15..d077906 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ This is a plugin that lets you intercept the different requests and responses fr Include the package with the latest version available in your `pubspec.yaml`. ```dart -http_interceptor: ^1.0.1 +http_interceptor: ``` ## Features diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/analysis_options.yml b/analysis_options.yml deleted file mode 100644 index c9cf67f..0000000 --- a/analysis_options.yml +++ /dev/null @@ -1 +0,0 @@ -include: package:effective_dart/analysis_options.1.2.1.yaml \ No newline at end of file diff --git a/example/.metadata b/example/.metadata index 07763f7..985adcc 100644 --- a/example/.metadata +++ b/example/.metadata @@ -1,10 +1,33 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713 + revision: f1875d570e39de09040c8f79aa13cc56baab8db1 channel: stable project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: android + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + - platform: ios + create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..1a78a08 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + avoid_print: false # Uncomment to disable the `avoid_print` rule + prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/android/.gitignore b/example/android/.gitignore index 0a741cb..6f56801 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -9,3 +9,5 @@ GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app key.properties +**/*.keystore +**/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 0f6a5e5..0833ecf 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,24 +26,31 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 28 + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' } - lintOptions { - disable 'InvalidPackage' + sourceSets { + main.java.srcDirs += 'src/main/kotlin' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.example" - minSdkVersion 16 - targetSdkVersion 28 + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -61,7 +68,4 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' } diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index c208884..45d523a 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,7 @@ - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 8bc6007..3f41384 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,25 @@ - - + + diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt index 1656503..e793a00 100644 --- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -1,12 +1,6 @@ package com.example.example -import androidx.annotation.NonNull; import io.flutter.embedding.android.FlutterActivity -import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant class MainActivity: FlutterActivity() { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } } diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml index 449a9f9..06952be 100644 --- a/example/android/app/src/main/res/values-night/styles.xml +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -3,14 +3,14 @@ + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index c208884..45d523a 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,7 @@ - diff --git a/example/android/build.gradle b/example/android/build.gradle index 3100ad2..83ae220 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.6.10' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -14,7 +14,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 38c8d45..94adc3a 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,3 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true android.useAndroidX=true android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 296b146..cc5527d 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14f..44e62bc 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,15 +1,11 @@ include ':app' -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/.gitignore b/example/ios/.gitignore index e96ef60..7a7f987 100644 --- a/example/ios/.gitignore +++ b/example/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index f2872cf..8d4492f 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 524060c..99177d3 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,22 +1,28 @@ PODS: - Flutter (1.0.0) - - shared_preferences (0.0.1): + - image_picker_ios (0.0.1): + - Flutter + - shared_preferences_ios (0.0.1): - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) EXTERNAL SOURCES: Flutter: :path: Flutter - shared_preferences: - :path: ".symlinks/plugins/shared_preferences/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + shared_preferences_ios: + :path: ".symlinks/plugins/shared_preferences_ios/ios" SPEC CHECKSUMS: Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a - shared_preferences: 5033afbb22d372e15aff8ff766df9021b845f273 + image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb + shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c -COCOAPODS: 1.11.0 +COCOAPODS: 1.11.3 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 5e18f77..038db1e 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,13 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 65B907C60867061250A77D6E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A76843E3596405C7B6DFF1B /* Pods_Runner.framework */; }; + 6BAA54477CF3FAD50BF7552F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E51A4745C75F5F7D7BB44E54 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -30,12 +30,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0F9682D7879846A313BD8569 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 00EB70272B6C4A72F1656FE9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 16D45B47C2DEFF381707ABA5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 185E66FDA5475F7AE96C4738 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 65B9DA6E65158B5A69155CD5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 6DE2CE631932059D90A38FAB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -46,7 +46,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9A76843E3596405C7B6DFF1B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E51A4745C75F5F7D7BB44E54 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,30 +54,30 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 65B907C60867061250A77D6E /* Pods_Runner.framework in Frameworks */, + 6BAA54477CF3FAD50BF7552F /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 18592708EC18A958100A9026 /* Pods */ = { + 4709EB77F738D5E7DB70DF01 /* Frameworks */ = { isa = PBXGroup; children = ( - 65B9DA6E65158B5A69155CD5 /* Pods-Runner.debug.xcconfig */, - 0F9682D7879846A313BD8569 /* Pods-Runner.release.xcconfig */, - 6DE2CE631932059D90A38FAB /* Pods-Runner.profile.xcconfig */, + E51A4745C75F5F7D7BB44E54 /* Pods_Runner.framework */, ); - name = Pods; - path = Pods; + name = Frameworks; sourceTree = ""; }; - 3994D8CD7A88340F930600D1 /* Frameworks */ = { + 5126606FDAD2AC2EC3C25678 /* Pods */ = { isa = PBXGroup; children = ( - 9A76843E3596405C7B6DFF1B /* Pods_Runner.framework */, + 16D45B47C2DEFF381707ABA5 /* Pods-Runner.debug.xcconfig */, + 185E66FDA5475F7AE96C4738 /* Pods-Runner.release.xcconfig */, + 00EB70272B6C4A72F1656FE9 /* Pods-Runner.profile.xcconfig */, ); - name = Frameworks; + name = Pods; + path = Pods; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { @@ -97,8 +97,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 18592708EC18A958100A9026 /* Pods */, - 3994D8CD7A88340F930600D1 /* Frameworks */, + 5126606FDAD2AC2EC3C25678 /* Pods */, + 4709EB77F738D5E7DB70DF01 /* Frameworks */, ); sourceTree = ""; }; @@ -117,7 +117,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, - 97C146F11CF9000F007C117D /* Supporting Files */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, @@ -126,13 +125,6 @@ path = Runner; sourceTree = ""; }; - 97C146F11CF9000F007C117D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -140,14 +132,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 985586E5047784C00F0EE9EF /* [CP] Check Pods Manifest.lock */, + 850A4ECA972ED4FFEFE92E29 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - D272D0CB52AEB248E1813299 /* [CP] Embed Pods Frameworks */, + D30A53883C6622F256B2B80D /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -164,8 +156,8 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = "The Chromium Authors"; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; @@ -174,7 +166,7 @@ }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -220,21 +212,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - 985586E5047784C00F0EE9EF /* [CP] Check Pods Manifest.lock */ = { + 850A4ECA972ED4FFEFE92E29 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -256,18 +234,31 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - D272D0CB52AEB248E1813299 /* [CP] Embed Pods Frameworks */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", ); - name = "[CP] Embed Pods Frameworks"; + name = "Run Script"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + D30A53883C6622F256B2B80D /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -365,16 +356,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 6J278GP3YQ; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -484,7 +471,8 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -497,16 +485,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 6J278GP3YQ; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -524,16 +508,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 6J278GP3YQ; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( + LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Flutter", + "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.example.example; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..c87d15a 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + NSPhotoLibraryUsageDescription + We need camera access to choose pictures and then removing background. + NSCameraUsageDescription + We need camera access to take pictures and then removing background. + + \ No newline at end of file diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h index 7335fdf..308a2a5 100644 --- a/example/ios/Runner/Runner-Bridging-Header.h +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" \ No newline at end of file +#import "GeneratedPluginRegistrant.h" diff --git a/example/lib/cities.dart b/example/lib/cities.dart index 546bd30..5f8e2a0 100644 --- a/example/lib/cities.dart +++ b/example/lib/cities.dart @@ -1,5321 +1,3548 @@ const cities = [ { - "id": 707860, - "name": "Hurzuf", - "country": "UA", - "coord": { - "lon": 34.283333, - "lat": 44.549999 - } - }, - { - "id": 519188, - "name": "Novinki", - "country": "RU", - "coord": { - "lon": 37.666668, - "lat": 55.683334 - } - }, - { - "id": 1283378, - "name": "Gorkhā", - "country": "NP", - "coord": { - "lon": 84.633331, - "lat": 28 - } - }, - { - "id": 1270260, - "name": "State of Haryāna", - "country": "IN", - "coord": { - "lon": 76, - "lat": 29 - } - }, - { - "id": 708546, - "name": "Holubynka", - "country": "UA", - "coord": { - "lon": 33.900002, - "lat": 44.599998 - } - }, - { - "id": 1283710, - "name": "Bāgmatī Zone", - "country": "NP", - "coord": { - "lon": 85.416664, - "lat": 28 - } - }, - { - "id": 529334, - "name": "Mar’ina Roshcha", - "country": "RU", - "coord": { - "lon": 37.611111, - "lat": 55.796391 - } - }, - { - "id": 1269750, - "name": "Republic of India", - "country": "IN", - "coord": { - "lon": 77, - "lat": 20 - } - }, - { - "id": 1283240, - "name": "Kathmandu", - "country": "NP", - "coord": { - "lon": 85.316666, - "lat": 27.716667 - } - }, - { - "id": 703363, - "name": "Laspi", - "country": "UA", - "coord": { - "lon": 33.733334, - "lat": 44.416668 - } - }, - { - "id": 3632308, - "name": "Merida", - "country": "VE", - "coord": { - "lon": -71.144997, - "lat": 8.598333 - } - }, - { - "id": 473537, - "name": "Vinogradovo", - "country": "RU", - "coord": { - "lon": 38.545555, - "lat": 55.423332 - } - }, - { - "id": 384848, - "name": "Qarah Gawl al ‘Ulyā", - "country": "IQ", - "coord": { - "lon": 45.6325, - "lat": 35.353889 - } - }, - { - "id": 569143, - "name": "Cherkizovo", - "country": "RU", - "coord": { - "lon": 37.728889, - "lat": 55.800835 - } - }, - { - "id": 713514, - "name": "Alupka", - "country": "UA", - "coord": { - "lon": 34.049999, - "lat": 44.416668 - } - }, - { - "id": 2878044, - "name": "Lichtenrade", - "country": "DE", - "coord": { - "lon": 13.40637, - "lat": 52.398441 - } - }, - { - "id": 464176, - "name": "Zavety Il’icha", - "country": "RU", - "coord": { - "lon": 37.849998, - "lat": 56.049999 - } - }, - { - "id": 295582, - "name": "‘Azriqam", - "country": "IL", - "coord": { - "lon": 34.700001, - "lat": 31.75 - } - }, - { - "id": 1271231, - "name": "Ghūra", - "country": "IN", - "coord": { - "lon": 79.883331, - "lat": 24.766666 - } - }, - { - "id": 690856, - "name": "Tyuzler", - "country": "UA", - "coord": { - "lon": 34.083332, - "lat": 44.466667 - } - }, - { - "id": 464737, - "name": "Zaponor’ye", - "country": "RU", - "coord": { - "lon": 38.861942, - "lat": 55.639999 - } - }, - { - "id": 707716, - "name": "Il’ichëvka", - "country": "UA", - "coord": { - "lon": 34.383331, - "lat": 44.666668 - } - }, - { - "id": 697959, - "name": "Partyzans’ke", - "country": "UA", - "coord": { - "lon": 34.083332, - "lat": 44.833332 - } - }, - { - "id": 803611, - "name": "Yurevichi", - "country": "RU", - "coord": { - "lon": 39.934444, - "lat": 43.600555 - } - }, - { - "id": 614371, - "name": "Gumist’a", - "country": "GE", - "coord": { - "lon": 40.973888, - "lat": 43.026943 - } - }, - { - "id": 874560, - "name": "Ptitsefabrika", - "country": "GE", - "coord": { - "lon": 40.290558, - "lat": 43.183613 - } - }, - { - "id": 874652, - "name": "Orekhovo", - "country": "GE", - "coord": { - "lon": 40.146111, - "lat": 43.351391 - } - }, - { - "id": 2347078, - "name": "Birim", - "country": "NG", - "coord": { - "lon": 9.997027, - "lat": 10.062094 - } - }, - { - "id": 2051302, - "name": "Priiskovyy", - "country": "RU", - "coord": { - "lon": 132.822495, - "lat": 42.819168 - } - }, - { - "id": 563692, - "name": "Dzhaga", - "country": "RU", - "coord": { - "lon": 42.650002, - "lat": 43.25 - } - }, - { - "id": 481725, - "name": "Tret’ya Rota", - "country": "RU", - "coord": { - "lon": 39.681389, - "lat": 43.741943 - } - }, - { - "id": 2638976, - "name": "Ruislip", - "country": "GB", - "coord": { - "lon": -0.42341, - "lat": 51.573441 - } - }, - { - "id": 2892705, - "name": "Karow", - "country": "DE", - "coord": { - "lon": 13.48117, - "lat": 52.609039 - } - }, - { - "id": 2922336, - "name": "Gatow", - "country": "DE", - "coord": { - "lon": 13.18285, - "lat": 52.483238 - } - }, - { - "id": 975511, - "name": "Mkuze", - "country": "ZA", - "coord": { - "lon": 32.038609, - "lat": -27.616409 - } - }, - { - "id": 1280737, - "name": "Lhasa", - "country": "CN", - "coord": { - "lon": 91.099998, - "lat": 29.65 - } - }, - { - "id": 745042, - "name": "İstanbul", - "country": "TR", - "coord": { - "lon": 28.983311, - "lat": 41.03508 - } - }, - { - "id": 3496831, - "name": "Mao", - "country": "DO", - "coord": { - "lon": -71.078133, - "lat": 19.551861 - } - }, - { - "id": 2017370, - "name": "Russian Federation", - "country": "RU", - "coord": { - "lon": 100, - "lat": 60 - } - }, - { - "id": 2045761, - "name": "De-Friz", - "country": "RU", - "coord": { - "lon": 131.991394, - "lat": 43.27861 - } - }, - { - "id": 1257986, - "name": "Rumbak", - "country": "IN", - "coord": { - "lon": 77.416664, - "lat": 34.049999 - } - }, - { - "id": 476350, - "name": "Vavibet", - "country": "RU", - "coord": { - "lon": 34.916668, - "lat": 67.933334 - } - }, - { - "id": 1343000, - "name": "Surtagān Chib", - "country": "PK", - "coord": { - "lon": 64.656113, - "lat": 26.474443 - } - }, - { - "id": 456169, - "name": "Rīgas Rajons", - "country": "LV", - "coord": { - "lon": 24.333332, - "lat": 57 - } - }, - { - "id": 475279, - "name": "Verkhneye Shchekotikhino", - "country": "RU", - "coord": { - "lon": 36.133331, - "lat": 53 - } - }, - { - "id": 711349, - "name": "Bucha", - "country": "UA", - "coord": { - "lon": 30.366671, - "lat": 50.583328 - } - }, - { - "id": 798544, - "name": "Republic of Poland", - "country": "PL", - "coord": { - "lon": 20, - "lat": 52 - } - }, - { - "id": 3094325, - "name": "Kuchary", - "country": "PL", - "coord": { - "lon": 19.383329, - "lat": 52.150002 - } - }, - { - "id": 6255149, - "name": "North America", - "country": "", - "coord": { - "lon": -100.546883, - "lat": 46.073231 - } - }, - { - "id": 3575514, - "name": "Brumaire", - "country": "KN", - "coord": { - "lon": -62.73333, - "lat": 17.299999 - } - }, - { - "id": 1861387, - "name": "Ishikawa-ken", - "country": "JP", - "coord": { - "lon": 136.770493, - "lat": 36.77145 - } - }, - { - "id": 1857578, - "name": "Matoba", - "country": "JP", - "coord": { - "lon": 133.949997, - "lat": 34.25 - } - }, - { - "id": 1299298, - "name": "Pya", - "country": "MM", - "coord": { - "lon": 95.599998, - "lat": 21.51667 - } - }, - { - "id": 3256023, - "name": "Kalanac", - "country": "BA", - "coord": { - "lon": 18.78389, - "lat": 44.86861 - } - }, - { - "id": 2921044, - "name": "Federal Republic of Germany", - "country": "DE", - "coord": { - "lon": 10.5, - "lat": 51.5 - } - }, - { - "id": 2861876, - "name": "Land Nordrhein-Westfalen", - "country": "DE", - "coord": { - "lon": 7, - "lat": 51.5 - } - }, - { - "id": 802899, - "name": "Mutaykutan", - "country": "RU", - "coord": { - "lon": 47.660641, - "lat": 42.818859 - } - }, - { - "id": 523523, - "name": "Nalchik", - "country": "RU", - "coord": { - "lon": 43.618889, - "lat": 43.498058 - } - }, - { - "id": 546448, - "name": "Kolganov", - "country": "RU", - "coord": { - "lon": 40.066669, - "lat": 44.366669 - } - }, - { - "id": 500023, - "name": "Rybatskiy", - "country": "RU", - "coord": { - "lon": 44.166389, - "lat": 44.799171 - } - }, - { - "id": 2207349, - "name": "Bellara", - "country": "AU", - "coord": { - "lon": 153.149597, - "lat": -27.063919 - } - }, - { - "id": 7870412, - "name": "Bartlett", - "country": "ZA", - "coord": { - "lon": 28.25263, - "lat": -26.17061 - } - }, - { - "id": 961935, - "name": "Rietfontein", - "country": "ZA", - "coord": { - "lon": 29.200001, - "lat": -25.5 - } - }, - { - "id": 3371200, - "name": "Hardap", - "country": "NA", - "coord": { - "lon": 17.25, - "lat": -24.5 - } - }, - { - "id": 1016666, - "name": "Botswana", - "country": "ZA", - "coord": { - "lon": 30.533331, - "lat": -24.33333 - } - }, - { - "id": 3858204, - "name": "El Destierro", - "country": "AR", - "coord": { - "lon": -62.47662, - "lat": -24.1 - } - }, - { - "id": 4070245, - "name": "Jones Crossroads", - "country": "US", - "coord": { - "lon": -85.484657, - "lat": 31.21073 - } - }, - { - "id": 4344544, - "name": "Vernon Parish", - "country": "US", - "coord": { - "lon": -93.183502, - "lat": 31.11685 - } - }, - { - "id": 4215307, - "name": "Pennick", - "country": "US", - "coord": { - "lon": -81.55899, - "lat": 31.313 - } - }, - { - "id": 5285039, - "name": "Black Bear Spring", - "country": "US", - "coord": { - "lon": -110.288139, - "lat": 31.386209 - } - }, - { - "id": 4673179, - "name": "Bee House", - "country": "US", - "coord": { - "lon": -98.081139, - "lat": 31.40266 - } - }, - { - "id": 6078447, - "name": "Morden", - "country": "CA", - "coord": { - "lon": -98.101357, - "lat": 49.191898 - } - }, - { - "id": 2201316, - "name": "Nasirotu", - "country": "FJ", - "coord": { - "lon": 178.25, - "lat": -18.033331 - } - }, - { - "id": 1938756, - "name": "Sisali", - "country": "ID", - "coord": { - "lon": 124.531387, - "lat": -9.19167 - } - }, - { - "id": 2009359, - "name": "Puntan", - "country": "ID", - "coord": { - "lon": 110.553329, - "lat": -7.51944 - } - }, - { - "id": 2566086, - "name": "Tsiémé-Mandiélé", - "country": "CG", - "coord": { - "lon": 15.2875, - "lat": -4.22694 - } - }, - { - "id": 154733, - "name": "Masama", - "country": "TZ", - "coord": { - "lon": 37.183331, - "lat": -3.23333 - } - }, - { - "id": 1630349, - "name": "Purukcahu", - "country": "ID", - "coord": { - "lon": 114.583328, - "lat": -0.58333 - } - }, - { - "id": 2224928, - "name": "Néméyong II", - "country": "CM", - "coord": { - "lon": 13.5, - "lat": 2.91667 - } - }, - { - "id": 6716279, - "name": "Pondok Genteng", - "country": "ID", - "coord": { - "lon": 99.0709, - "lat": 3.2245 - } - }, - { - "id": 2384618, - "name": "Mbongoté", - "country": "CF", - "coord": { - "lon": 18.283331, - "lat": 4.25 - } - }, - { - "id": 378867, - "name": "Amiling", - "country": "SS", - "coord": { - "lon": 32.355831, - "lat": 4.19417 - } - }, - { - "id": 2230362, - "name": "Kélkoto", - "country": "CM", - "coord": { - "lon": 11.16667, - "lat": 4.43333 - } - }, - { - "id": 343846, - "name": "Angetu", - "country": "ET", - "coord": { - "lon": 39.48333, - "lat": 6.33333 - } - }, - { - "id": 370366, - "name": "Massa", - "country": "SD", - "coord": { - "lon": 29.466669, - "lat": 10.98333 - } - }, - { - "id": 365618, - "name": "Tumko", - "country": "SD", - "coord": { - "lon": 24.6, - "lat": 12.01667 - } - }, - { - "id": 524894, - "name": "Moskva", - "country": "RU", - "coord": { - "lon": 37.606667, - "lat": 55.761665 - } - }, - { - "id": 1861060, - "name": "Japan", - "country": "JP", - "coord": { - "lon": 139.753098, - "lat": 35.68536 - } - }, - { - "id": 2130037, - "name": "Hokkaidō", - "country": "JP", - "coord": { - "lon": 141.346603, - "lat": 43.06451 - } - }, - { - "id": 6199126, - "name": "Sanggrahan", - "country": "ID", - "coord": { - "lon": 110.246109, - "lat": -7.46056 - } - }, - { - "id": 6388445, - "name": "Karangmangle", - "country": "ID", - "coord": { - "lon": 109.0075, - "lat": -7.43028 - } - }, - { - "id": 494806, - "name": "Sheremetyevskiy", - "country": "RU", - "coord": { - "lon": 37.491112, - "lat": 55.98 - } - }, - { - "id": 467104, - "name": "Yershovo", - "country": "RU", - "coord": { - "lon": 36.858055, - "lat": 55.771111 - } - }, - { - "id": 462352, - "name": "Znamenka", - "country": "RU", - "coord": { - "lon": 35.981392, - "lat": 52.896671 - } - }, - { - "id": 2267057, - "name": "Lisbon", - "country": "PT", - "coord": { - "lon": -9.13333, - "lat": 38.716671 - } - }, - { - "id": 3082707, - "name": "Walbrzych", - "country": "PL", - "coord": { - "lon": 16.284321, - "lat": 50.771412 - } - }, - { - "id": 3091150, - "name": "Naklo nad Notecia", - "country": "PL", - "coord": { - "lon": 17.60181, - "lat": 53.142139 - } - }, - { - "id": 1784658, - "name": "Zhengzhou", - "country": "CN", - "coord": { - "lon": 113.648613, - "lat": 34.757778 - } - }, - { - "id": 7301040, - "name": "Tonyrefail", - "country": "GB", - "coord": { - "lon": -3.41503, - "lat": 51.580238 - } - }, - { - "id": 1348747, - "name": "Bankra", - "country": "IN", - "coord": { - "lon": 88.298058, - "lat": 22.627501 - } - }, - { - "id": 6255148, - "name": "Europe", - "country": "", - "coord": { - "lon": 9.140625, - "lat": 48.69096 - } - }, - { - "id": 524925, - "name": "Moskovskaya Oblast’", - "country": "RU", - "coord": { - "lon": 37.628334, - "lat": 55.75639 - } - }, - { - "id": 4047656, - "name": "Provo", - "country": "US", - "coord": { - "lon": -94.107697, - "lat": 34.037609 - } - }, - { - "id": 5493998, - "name": "Tejon", - "country": "US", - "coord": { - "lon": -105.28611, - "lat": 34.58979 - } - }, - { - "id": 1463749, - "name": "Guliston", - "country": "UZ", - "coord": { - "lon": 65.518929, - "lat": 38.510029 - } - }, - { - "id": 749184, - "name": "Ciciler", - "country": "TR", - "coord": { - "lon": 30.063601, - "lat": 40.442982 - } - }, - { - "id": 750594, - "name": "Bilmece", - "country": "TR", - "coord": { - "lon": 36.150002, - "lat": 41.150002 - } - }, - { - "id": 3113208, - "name": "Provincia de Pontevedra", - "country": "ES", - "coord": { - "lon": -8.5, - "lat": 42.5 - } - }, - { - "id": 2653753, - "name": "Carmarthenshire", - "country": "GB", - "coord": { - "lon": -4.16667, - "lat": 51.833328 - } - }, - { - "id": 658226, - "name": "Helsinki", - "country": "FI", - "coord": { - "lon": 24.93417, - "lat": 60.17556 - } - }, - { - "id": 2744819, - "name": "Gemeente Wervershoof", - "country": "NL", - "coord": { - "lon": 5.13333, - "lat": 52.716671 - } - }, - { - "id": 3017680, - "name": "Forville", - "country": "FR", - "coord": { - "lon": 6.6239, - "lat": 44.913849 - } - }, - { - "id": 448961, - "name": "Tall ‘Alāwī", - "country": "IQ", - "coord": { - "lon": 44.552891, - "lat": 31.59358 - } - }, - { - "id": 3007202, - "name": "La Portanière", - "country": "FR", - "coord": { - "lon": 6.17341, - "lat": 43.248611 - } - }, - { - "id": 2650353, - "name": "East Portlemouth", - "country": "GB", - "coord": { - "lon": -3.75578, - "lat": 50.232159 - } - }, - { - "id": 2058430, - "name": "Whyalla", - "country": "AU", - "coord": { - "lon": 137.583328, - "lat": -33.033329 - } - }, - { - "id": 2181258, - "name": "Terrace End", - "country": "NZ", - "coord": { - "lon": 175.616669, - "lat": -40.349998 - } - }, - { - "id": 2130135, - "name": "Hashimoto", - "country": "JP", - "coord": { - "lon": 140.75, - "lat": 40.816669 - } - }, - { - "id": 2110681, - "name": "Tsukuba-kenkyūgakuen-toshi", - "country": "JP", - "coord": { - "lon": 140.116669, - "lat": 36.083328 - } - }, - { - "id": 1862845, - "name": "Higashi-asahimachi", - "country": "JP", - "coord": { - "lon": 133.066666, - "lat": 35.466671 - } - }, - { - "id": 1863250, - "name": "Hanabatachō", - "country": "JP", - "coord": { - "lon": 130.699997, - "lat": 32.799999 - } - }, - { - "id": 1852699, - "name": "Senzaki", - "country": "JP", - "coord": { - "lon": 131.199997, - "lat": 34.383331 - } - }, - { - "id": 1853163, - "name": "Sakaki", - "country": "JP", - "coord": { - "lon": 138.183334, - "lat": 36.466671 - } - }, - { - "id": 1864427, - "name": "Daisen", - "country": "JP", - "coord": { - "lon": 133.533325, - "lat": 35.383331 - } - }, - { - "id": 1861816, - "name": "Ikaruga", - "country": "JP", - "coord": { - "lon": 134.583328, - "lat": 34.833328 - } - }, - { - "id": 1857451, - "name": "Matsuzaki", - "country": "JP", - "coord": { - "lon": 138.783325, - "lat": 34.75 - } - }, - { - "id": 2128894, - "name": "Noboribetsu", - "country": "JP", - "coord": { - "lon": 141.173065, - "lat": 42.451389 - } - }, - { - "id": 3175936, - "name": "Grandate", - "country": "IT", - "coord": { - "lon": 9.05784, - "lat": 45.775181 - } - }, - { - "id": 6539582, - "name": "Biella", - "country": "IT", - "coord": { - "lon": 8.05002, - "lat": 45.55986 - } - }, - { - "id": 6542288, - "name": "Soverato", - "country": "IT", - "coord": { - "lon": 16.54991, - "lat": 38.684978 - } - }, - { - "id": 6540662, - "name": "Pinerolo", - "country": "IT", - "coord": { - "lon": 7.33312, - "lat": 44.883942 - } - }, - { - "id": 3333225, - "name": "Dundee City", - "country": "GB", - "coord": { - "lon": -2.91667, - "lat": 56.466671 - } - }, - { - "id": 7290647, - "name": "Nuneaton and Bedworth District", - "country": "GB", - "coord": { - "lon": -1.47802, - "lat": 52.500641 - } - }, - { - "id": 7291924, - "name": "Rhyl", - "country": "GB", - "coord": { - "lon": -3.47247, - "lat": 53.31905 - } - }, - { - "id": 2649140, - "name": "Foulridge", - "country": "GB", - "coord": { - "lon": -2.16864, - "lat": 53.87579 - } - }, - { - "id": 2647062, - "name": "Hermitage", - "country": "GB", - "coord": { - "lon": -1.26823, - "lat": 51.455399 - } - }, - { - "id": 2648355, - "name": "Golcar", - "country": "GB", - "coord": { - "lon": -1.8557, - "lat": 53.639919 - } - }, - { - "id": 2636001, - "name": "Thornbury", - "country": "GB", - "coord": { - "lon": -2.55, - "lat": 52.23333 - } - }, - { - "id": 510291, - "name": "Peterhof", - "country": "RU", - "coord": { - "lon": 29.9, - "lat": 59.883331 - } - }, - { - "id": 518858, - "name": "Grebnevo", - "country": "RU", - "coord": { - "lon": 38.072777, - "lat": 55.961945 - } - }, - { - "id": 3746183, - "name": "Centro Habana", - "country": "CU", - "coord": { - "lon": -82.364166, - "lat": 23.13833 - } - }, - { - "id": 1014012, - "name": "Carolina", - "country": "ZA", - "coord": { - "lon": 30.114889, - "lat": -26.069269 - } - }, - { - "id": 3579132, - "name": "Gustavia", - "country": "BL", - "coord": { - "lon": -62.849781, - "lat": 17.896179 - } - }, - { - "id": 1790413, - "name": "Xianju", - "country": "CN", - "coord": { - "lon": 120.73333, - "lat": 28.85 - } - }, - { - "id": 1850144, - "name": "Tōkyō-to", - "country": "JP", - "coord": { - "lon": 139.691711, - "lat": 35.689499 - } - }, - { - "id": 5815135, - "name": "Washington", - "country": "US", - "coord": { - "lon": -120.501472, - "lat": 47.500118 - } - }, - { - "id": 5391891, - "name": "San Dimas", - "country": "US", - "coord": { - "lon": -117.806732, - "lat": 34.106682 - } - }, - { - "id": 148251, - "name": "Culfa", - "country": "AZ", - "coord": { - "lon": 45.630798, - "lat": 38.955799 - } - }, - { - "id": 141668, - "name": "Bandar Emām Khomeynī", - "country": "IR", - "coord": { - "lon": 49.076279, - "lat": 30.429831 - } - }, - { - "id": 66108, - "name": "Shāhrūd", - "country": "IR", - "coord": { - "lon": 55.01667, - "lat": 36.416672 - } - }, - { - "id": 2410048, - "name": "Bo", - "country": "SL", - "coord": { - "lon": -11.73833, - "lat": 7.96472 - } - }, - { - "id": 1092342, - "name": "Daché", - "country": "KM", - "coord": { - "lon": 43.251389, - "lat": -11.7125 - } - }, - { - "id": 3719432, - "name": "Département de l'Ouest", - "country": "HT", - "coord": { - "lon": -72.291412, - "lat": 18.663811 - } - }, - { - "id": 6538016, - "name": "Montescudo", - "country": "IT", - "coord": { - "lon": 12.54295, - "lat": 43.91946 - } - }, - { - "id": 3428577, - "name": "San Pedro", - "country": "AR", - "coord": { - "lon": -54.108421, - "lat": -26.62207 - } - }, - { - "id": 7871309, - "name": "Wels(Stadt)", - "country": "AT", - "coord": { - "lon": 14.02164, - "lat": 48.16082 - } - }, - { - "id": 7839407, - "name": "Palmerston", - "country": "AU", - "coord": { - "lon": 130.977966, - "lat": -12.4962 - } - }, - { - "id": 147059, - "name": "Telmankend", - "country": "AZ", - "coord": { - "lon": 48.399021, - "lat": 39.87867 - } - }, - { - "id": 147425, - "name": "Neftcala", - "country": "AZ", - "coord": { - "lon": 49.247219, - "lat": 39.374168 - } - }, - { - "id": 148340, - "name": "Pushkino", - "country": "AZ", - "coord": { - "lon": 48.544998, - "lat": 39.458328 - } - }, - { - "id": 2784549, - "name": "Visé", - "country": "BE", - "coord": { - "lon": 5.7019, - "lat": 50.738628 - } - }, - { - "id": 2793079, - "name": "Lede", - "country": "BE", - "coord": { - "lon": 3.94544, - "lat": 50.962582 - } - }, - { - "id": 2795101, - "name": "Ieper", - "country": "BE", - "coord": { - "lon": 2.86733, - "lat": 50.85704 - } - }, - { - "id": 2354349, - "name": "Titao", - "country": "BF", - "coord": { - "lon": -2.06667, - "lat": 13.76667 - } - }, - { - "id": 6930703, - "name": "Cascades", - "country": "BF", - "coord": { - "lon": -4.76292, - "lat": 10.65015 - } - }, - { - "id": 3901501, - "name": "Villazon", - "country": "BO", - "coord": { - "lon": -65.594223, - "lat": -22.08659 - } - }, - { - "id": 6050612, - "name": "Laval", - "country": "CA", - "coord": { - "lon": -73.749184, - "lat": 45.583382 - } - }, - { - "id": 203717, - "name": "Yangambi", - "country": "CD", - "coord": { - "lon": 24.43359, - "lat": 0.81021 - } - }, - { - "id": 204283, - "name": "Watsa", - "country": "CD", - "coord": { - "lon": 29.535509, - "lat": 3.03716 - } - }, - { - "id": 204318, - "name": "Wamba", - "country": "CD", - "coord": { - "lon": 27.994659, - "lat": 2.14838 - } - }, - { - "id": 210379, - "name": "Lusambo", - "country": "CD", - "coord": { - "lon": 23.450001, - "lat": -4.96667 - } - }, - { - "id": 210939, - "name": "Luebo", - "country": "CD", - "coord": { - "lon": 21.41667, - "lat": -5.35 - } - }, - { - "id": 211098, - "name": "Lubao", - "country": "CD", - "coord": { - "lon": 25.75, - "lat": -5.36667 - } - }, - { - "id": 214575, - "name": "Kampene", - "country": "CD", - "coord": { - "lon": 26.66667, - "lat": -3.6 - } - }, - { - "id": 215527, - "name": "Kabinda", - "country": "CD", - "coord": { - "lon": 24.48333, - "lat": -6.13333 - } - }, - { - "id": 215605, - "name": "Kabare", - "country": "CD", - "coord": { - "lon": 28.824169, - "lat": -2.46833 - } - }, - { - "id": 217637, - "name": "Businga", - "country": "CD", - "coord": { - "lon": 20.883329, - "lat": 3.33333 - } - }, - { - "id": 2311968, - "name": "Nioki", - "country": "CD", - "coord": { - "lon": 17.683331, - "lat": -2.71667 - } - }, - { - "id": 2312249, - "name": "Mushie", - "country": "CD", - "coord": { - "lon": 16.9, - "lat": -3.01667 - } - }, - { - "id": 2313084, - "name": "Mangai", - "country": "CD", - "coord": { - "lon": 19.533331, - "lat": -4.05 - } - }, - { - "id": 2314300, - "name": "Ville de Kinshasa", - "country": "CD", - "coord": { - "lon": 15.5, - "lat": -4.5 - } - }, - { - "id": 7286409, - "name": "Luzern", - "country": "CH", - "coord": { - "lon": 8.32518, - "lat": 47.047138 - } - }, - { - "id": 6295429, - "name": "Fahrweid (südl. Teil)", - "country": "CH", - "coord": { - "lon": 8.41367, - "lat": 47.408138 - } - }, - { - "id": 7286907, - "name": "Riehen", - "country": "CH", - "coord": { - "lon": 7.65117, - "lat": 47.579418 - } - }, - { - "id": 6291739, - "name": "Bärenbohl", - "country": "CH", - "coord": { - "lon": 8.51832, - "lat": 47.434929 - } - }, - { - "id": 6295642, - "name": "Letten", - "country": "CH", - "coord": { - "lon": 8.53458, - "lat": 47.32811 - } - }, - { - "id": 2280376, - "name": "Touba", - "country": "CI", - "coord": { - "lon": -7.68333, - "lat": 8.28333 - } - }, - { - "id": 2221394, - "name": "Tonga", - "country": "CM", - "coord": { - "lon": 10.7, - "lat": 4.96667 - } - }, - { - "id": 3072342, - "name": "Lahovičky", - "country": "CZ", - "coord": { - "lon": 14.39698, - "lat": 50.001339 - } - }, - { - "id": 3064531, - "name": "Svépravice", - "country": "CZ", - "coord": { - "lon": 14.6131, - "lat": 50.100712 - } - }, - { - "id": 6547426, - "name": "Wardenburg", - "country": "DE", - "coord": { - "lon": 8.19785, - "lat": 53.062222 - } - }, - { - "id": 6553084, - "name": "Wachtberg", - "country": "DE", - "coord": { - "lon": 7.1259, - "lat": 50.6213 - } - }, - { - "id": 2835344, - "name": "Schwalmtal", - "country": "DE", - "coord": { - "lon": 6.26667, - "lat": 51.216671 - } - }, - { - "id": 7602475, - "name": "Pfaffenhofen an der Ilm", - "country": "DE", - "coord": { - "lon": 11.502, - "lat": 48.528431 - } - }, - { - "id": 6553078, - "name": "Odenthal", - "country": "DE", - "coord": { - "lon": 7.1182, - "lat": 51.034801 - } - }, - { - "id": 6553081, - "name": "Much", - "country": "DE", - "coord": { - "lon": 7.3537, - "lat": 50.874699 - } - }, - { - "id": 2915013, - "name": "Großstädteln", - "country": "DE", - "coord": { - "lon": 12.38333, - "lat": 51.26667 - } - }, - { - "id": 6553073, - "name": "Lindlar", - "country": "DE", - "coord": { - "lon": 7.3665, - "lat": 51.033199 - } - }, - { - "id": 6553056, - "name": "Kreuzau", - "country": "DE", - "coord": { - "lon": 6.4771, - "lat": 50.729401 - } - }, - { - "id": 6557629, - "name": "Höxter, Stadt", - "country": "DE", - "coord": { - "lon": 9.39737, - "lat": 51.796371 - } - }, - { - "id": 2820086, - "name": "Kreis Unna", - "country": "DE", - "coord": { - "lon": 7.7175, - "lat": 51.568611 - } - }, - { - "id": 6553128, - "name": "Hille", - "country": "DE", - "coord": { - "lon": 8.7722, - "lat": 52.330898 - } - }, - { - "id": 6556314, - "name": "Haar", - "country": "DE", - "coord": { - "lon": 11.7333, - "lat": 48.099998 - } - }, - { - "id": 2916630, - "name": "Grossenhain", - "country": "DE", - "coord": { - "lon": 13.55, - "lat": 51.283329 - } - }, - { - "id": 6553174, - "name": "Ginsheim-Gustavsburg", - "country": "DE", - "coord": { - "lon": 8.3425, - "lat": 49.985802 - } - }, - { - "id": 6553072, - "name": "Engelskirchen", - "country": "DE", - "coord": { - "lon": 7.4, - "lat": 50.983299 - } - }, - { - "id": 6555618, - "name": "Eggenstein-Leopoldshafen", - "country": "DE", - "coord": { - "lon": 8.39056, - "lat": 49.095299 - } - }, - { - "id": 6553040, - "name": "Brüggen", - "country": "DE", - "coord": { - "lon": 6.1886, - "lat": 51.2379 - } - }, - { - "id": 2957818, - "name": "Bönen", - "country": "DE", - "coord": { - "lon": 7.76667, - "lat": 51.583328 - } - }, - { - "id": 3221125, - "name": "Kreisfreie Stadt Bielefeld", - "country": "DE", - "coord": { - "lon": 8.55861, - "lat": 52.017502 - } - }, - { - "id": 2949188, - "name": "Bielefeld", - "country": "DE", - "coord": { - "lon": 8.5, - "lat": 52 - } - }, - { - "id": 6555717, - "name": "Baiersbronn", - "country": "DE", - "coord": { - "lon": 8.3495, - "lat": 48.515499 - } - }, - { - "id": 6552854, - "name": "Bad Zwischenahn", - "country": "DE", - "coord": { - "lon": 8.04142, - "lat": 53.1717 - } - }, - { - "id": 6557561, - "name": "Bad Honnef, Stadt", - "country": "DE", - "coord": { - "lon": 7.26114, - "lat": 50.647579 - } - }, - { - "id": 6553094, - "name": "Ascheberg", - "country": "DE", - "coord": { - "lon": 7.61667, - "lat": 51.783298 - } - }, - { - "id": 2856307, - "name": "Ostfildern", - "country": "DE", - "coord": { - "lon": 9.25143, - "lat": 48.7267 - } - }, - { - "id": 7602483, - "name": "Spremberg, Stadt", - "country": "DE", - "coord": { - "lon": 14.37355, - "lat": 51.56971 - } - }, - { - "id": 6543938, - "name": "Høje-Taastrup Kommune", - "country": "DK", - "coord": { - "lon": 12.24854, - "lat": 55.656429 - } - }, - { - "id": 2616011, - "name": "Nyborg Kommune", - "country": "DK", - "coord": { - "lon": 10.75, - "lat": 55.333328 - } - }, - { - "id": 2618525, - "name": "Kolding Kommune", - "country": "DK", - "coord": { - "lon": 9.46667, - "lat": 55.533329 - } - }, - { - "id": 3495858, - "name": "Neiba", - "country": "DO", - "coord": { - "lon": -71.416672, - "lat": 18.5 - } - }, - { - "id": 3496332, - "name": "Moca", - "country": "DO", - "coord": { - "lon": -70.5, - "lat": 19.5 - } - }, - { - "id": 2476412, - "name": "el hed", - "country": "DZ", - "coord": { - "lon": 4.77361, - "lat": 36.650002 - } - }, - { - "id": 2479183, - "name": "Souma", - "country": "DZ", - "coord": { - "lon": 2.90528, - "lat": 36.51833 - } - }, - { - "id": 2482939, - "name": "Rouached", - "country": "DZ", - "coord": { - "lon": 6.04267, - "lat": 36.457741 - } - }, - { - "id": 2483761, - "name": "Reggane", - "country": "DZ", - "coord": { - "lon": 0.1714, - "lat": 26.715759 - } - }, - { - "id": 2487620, - "name": "Metlili Chaamba", - "country": "DZ", - "coord": { - "lon": 3.63333, - "lat": 32.26667 - } - }, - { - "id": 2498775, - "name": "El Abiodh Sidi Cheikh", - "country": "DZ", - "coord": { - "lon": 0.54839, - "lat": 32.893002 - } - }, - { - "id": 6361023, - "name": "Osuna", - "country": "ES", - "coord": { - "lon": -5.11371, - "lat": 37.22229 - } - }, - { - "id": 6361010, - "name": "Lora del Río", - "country": "ES", - "coord": { - "lon": -5.48845, - "lat": 37.660149 - } - }, - { - "id": 6359459, - "name": "Fuengirola", - "country": "ES", - "coord": { - "lon": -4.61206, - "lat": 36.551491 - } - }, - { - "id": 6358465, - "name": "Bailén", - "country": "ES", - "coord": { - "lon": -3.78418, - "lat": 38.080231 - } - }, - { - "id": 6362958, - "name": "Utebo", - "country": "ES", - "coord": { - "lon": -1.00454, - "lat": 41.715591 - } - }, - { - "id": 6356273, - "name": "Barberà del Vallès", - "country": "ES", - "coord": { - "lon": 2.13201, - "lat": 41.517361 - } - }, - { - "id": 6359334, - "name": "Pinto", - "country": "ES", - "coord": { - "lon": -3.68321, - "lat": 40.258942 - } - }, - { - "id": 6533993, - "name": "Pineda de Mar", - "country": "ES", - "coord": { - "lon": 2.66524, - "lat": 41.636478 - } - }, - { - "id": 6534092, - "name": "Palamós", - "country": "ES", - "coord": { - "lon": 3.14432, - "lat": 41.860611 - } - }, - { - "id": 6359320, - "name": "Navalcarnero", - "country": "ES", - "coord": { - "lon": -3.99743, - "lat": 40.282101 - } - }, - { - "id": 6359308, - "name": "Mejorada del Campo", - "country": "ES", - "coord": { - "lon": -3.47564, - "lat": 40.402061 - } - }, - { - "id": 6356141, - "name": "Manlleu", - "country": "ES", - "coord": { - "lon": 2.28035, - "lat": 41.999298 - } - }, - { - "id": 6359300, - "name": "Leganés", - "country": "ES", - "coord": { - "lon": -3.77931, - "lat": 40.327358 - } - }, - { - "id": 6362203, - "name": "Laguna de Duero", - "country": "ES", - "coord": { - "lon": -4.72002, - "lat": 41.56963 - } - }, - { - "id": 6357300, - "name": "Coruña (A)", - "country": "ES", - "coord": { - "lon": -8.4188, - "lat": 43.371262 - } - }, - { - "id": 6361741, - "name": "Illescas", - "country": "ES", - "coord": { - "lon": -3.85713, - "lat": 40.135811 - } - }, - { - "id": 6356206, - "name": "la Roca del Vallès", - "country": "ES", - "coord": { - "lon": 2.32741, - "lat": 41.601181 - } - }, - { - "id": 6362379, - "name": "Ermua", - "country": "ES", - "coord": { - "lon": -2.50305, - "lat": 43.18774 - } - }, - { - "id": 6358120, - "name": "Eibar", - "country": "ES", - "coord": { - "lon": -2.46165, - "lat": 43.19978 - } - }, - { - "id": 6362372, - "name": "Durango", - "country": "ES", - "coord": { - "lon": -2.6498, - "lat": 43.16481 - } - }, - { - "id": 6359273, - "name": "Collado Villalba", - "country": "ES", - "coord": { - "lon": -3.99052, - "lat": 40.642971 - } - }, - { - "id": 6359266, - "name": "Ciempozuelos", - "country": "ES", - "coord": { - "lon": -3.6001, - "lat": 40.153599 - } - }, - { - "id": 6356068, - "name": "Caldes de Montbui", - "country": "ES", - "coord": { - "lon": 2.14934, - "lat": 41.65057 - } - }, - { - "id": 6359026, - "name": "Calahorra", - "country": "ES", - "coord": { - "lon": -1.95262, - "lat": 42.307869 - } - }, - { - "id": 6356985, - "name": "Benicasim/Benicàssim", - "country": "ES", - "coord": { - "lon": 0.06334, - "lat": 40.052799 - } - }, - { - "id": 6360635, - "name": "Realejos (Los)", - "country": "ES", - "coord": { - "lon": -16.59104, - "lat": 28.381981 - } - }, - { - "id": 3128528, - "name": "Basauri", - "country": "ES", - "coord": { - "lon": -2.88271, - "lat": 43.234821 - } - }, - { - "id": 6357735, - "name": "Lobras", - "country": "ES", - "coord": { - "lon": -3.20859, - "lat": 36.90868 - } - }, - { - "id": 329586, - "name": "Robit", - "country": "ET", - "coord": { - "lon": 39.633331, - "lat": 12.01667 - } - }, - { - "id": 331180, - "name": "Mekele", - "country": "ET", - "coord": { - "lon": 39.475281, - "lat": 13.49667 - } - }, - { - "id": 332880, - "name": "Kolito", - "country": "ET", - "coord": { - "lon": 38.083328, - "lat": 7.31667 - } - }, - { - "id": 2204582, - "name": "Lambasa", - "country": "FJ", - "coord": { - "lon": 179.383331, - "lat": -16.41667 - } - }, - { - "id": 7626930, - "name": "Sokehs Municipality", - "country": "FM", - "coord": { - "lon": 158.1427, - "lat": 6.93273 - } - }, - { - "id": 6441676, - "name": "Wittenheim", - "country": "FR", - "coord": { - "lon": 7.33333, - "lat": 47.816669 - } - }, - { - "id": 6438569, - "name": "Wattrelos", - "country": "FR", - "coord": { - "lon": 3.21667, - "lat": 50.700001 - } - }, - { - "id": 6454050, - "name": "Vitré", - "country": "FR", - "coord": { - "lon": -1.2, - "lat": 48.133331 - } - }, - { - "id": 6446231, - "name": "Viry-Châtillon", - "country": "FR", - "coord": { - "lon": 2.38333, - "lat": 48.666672 - } - }, - { - "id": 6452039, - "name": "Villeneuve-le-Roi", - "country": "FR", - "coord": { - "lon": 2.41667, - "lat": 48.73333 - } - }, - { - "id": 6453748, - "name": "Vierzon", - "country": "FR", - "coord": { - "lon": 2.08333, - "lat": 47.216671 - } - }, - { - "id": 6446218, - "name": "Verrières-le-Buisson", - "country": "FR", - "coord": { - "lon": 2.26667, - "lat": 48.75 - } - }, - { - "id": 6457368, - "name": "Arrondissement d'Antony", - "country": "FR", - "coord": { - "lon": 2.3006, - "lat": 48.7617 - } - }, - { - "id": 6425695, - "name": "Vallauris", - "country": "FR", - "coord": { - "lon": 7.05, - "lat": 43.583328 - } - }, - { - "id": 6438526, - "name": "Tourcoing", - "country": "FR", - "coord": { - "lon": 3.15, - "lat": 50.716671 - } - }, - { - "id": 6446342, - "name": "Taverny", - "country": "FR", - "coord": { - "lon": 2.21667, - "lat": 49.033329 - } - }, - { - "id": 6446340, - "name": "Soisy-sous-Montmorency", - "country": "FR", - "coord": { - "lon": 2.3, - "lat": 48.98333 - } - }, - { - "id": 6438498, - "name": "Sin-le-Noble", - "country": "FR", - "coord": { - "lon": 3.11667, - "lat": 50.366669 - } - }, - { - "id": 6451981, - "name": "Sèvres", - "country": "FR", - "coord": { - "lon": 2.2, - "lat": 48.816669 - } - }, - { - "id": 6427088, - "name": "Salon-de-Provence", - "country": "FR", - "coord": { - "lon": 5.1, - "lat": 43.633331 - } - }, - { - "id": 6455342, - "name": "Saint-Ouen", - "country": "FR", - "coord": { - "lon": 2.33333, - "lat": 48.900002 - } - }, - { - "id": 6441760, - "name": "Saint-Fons", - "country": "FR", - "coord": { - "lon": 4.86667, - "lat": 45.700001 - } - }, - { - "id": 6454369, - "name": "Saint-Avold", - "country": "FR", - "coord": { - "lon": 6.7, - "lat": 49.099998 - } - }, - { - "id": 6454153, - "name": "Rezé", - "country": "FR", - "coord": { - "lon": -1.56667, - "lat": 47.200001 - } - }, - { - "id": 6454341, - "name": "Pontivy", - "country": "FR", - "coord": { - "lon": -2.98333, - "lat": 48.066669 - } - }, - { - "id": 6454014, - "name": "Pessac", - "country": "FR", - "coord": { - "lon": -0.61667, - "lat": 44.799999 - } - }, - { - "id": 6446184, - "name": "Palaiseau", - "country": "FR", - "coord": { - "lon": 2.25, - "lat": 48.716671 - } - }, - { - "id": 6443784, - "name": "Ozoir-la-Ferrière", - "country": "FR", - "coord": { - "lon": 2.66667, - "lat": 48.76667 - } - }, - { - "id": 6441724, - "name": "Oullins", - "country": "FR", - "coord": { - "lon": 4.8, - "lat": 45.716671 - } - }, - { - "id": 6446721, - "name": "Mougins", - "country": "FR", - "coord": { - "lon": 7, - "lat": 43.599998 - } - }, - { - "id": 6446177, - "name": "Morsang-sur-Orge", - "country": "FR", - "coord": { - "lon": 2.35, - "lat": 48.666672 - } - }, - { - "id": 6430140, - "name": "Montélimar", - "country": "FR", - "coord": { - "lon": 4.75, - "lat": 44.566669 - } - }, - { - "id": 6453858, - "name": "Montbéliard", - "country": "FR", - "coord": { - "lon": 6.8, - "lat": 47.51667 - } - }, - { - "id": 6452024, - "name": "Maisons-Alfort", - "country": "FR", - "coord": { - "lon": 2.43333, - "lat": 48.799999 - } - }, - { - "id": 6430468, - "name": "Louviers", - "country": "FR", - "coord": { - "lon": 1.16667, - "lat": 49.216671 - } - }, - { - "id": 6452023, - "name": "Limeil-Brévannes", - "country": "FR", - "coord": { - "lon": 2.4893, - "lat": 48.7467 - } - }, - { - "id": 6457185, - "name": "Les Pavillons-sous-Bois", - "country": "FR", - "coord": { - "lon": 2.51667, - "lat": 48.900002 - } - }, - { - "id": 6432528, - "name": "Lattes", - "country": "FR", - "coord": { - "lon": 3.9, - "lat": 43.566669 - } - }, - { - "id": 6446146, - "name": "Grigny", - "country": "FR", - "coord": { - "lon": 2.39382, - "lat": 48.653931 - } - }, - { - "id": 6446274, - "name": "Goussainville", - "country": "FR", - "coord": { - "lon": 2.474, - "lat": 49.032001 - } - }, - { - "id": 6454157, - "name": "Gien", - "country": "FR", - "coord": { - "lon": 2.6297, - "lat": 47.689201 - } - }, - { - "id": 6451993, - "name": "Gagny", - "country": "FR", - "coord": { - "lon": 2.53333, - "lat": 48.883331 - } - }, - { - "id": 6455107, - "name": "Firminy", - "country": "FR", - "coord": { - "lon": 4.3, - "lat": 45.383331 - } - }, - { - "id": 6433192, - "name": "Échirolles", - "country": "FR", - "coord": { - "lon": 5.71667, - "lat": 45.133331 - } - }, - { - "id": 6441821, - "name": "Décines-Charpieu", - "country": "FR", - "coord": { - "lon": 4.9598, - "lat": 45.7686 - } - }, - { - "id": 6455404, - "name": "Dammarie-les-Lys", - "country": "FR", - "coord": { - "lon": 2.65, - "lat": 48.51667 - } - }, - { - "id": 6455339, - "name": "Colombes", - "country": "FR", - "coord": { - "lon": 2.25, - "lat": 48.916672 - } - }, - { - "id": 6453697, - "name": "Cognac", - "country": "FR", - "coord": { - "lon": -0.33333, - "lat": 45.700001 - } - }, - { - "id": 6428545, - "name": "Chenôve", - "country": "FR", - "coord": { - "lon": 5, - "lat": 47.283329 - } - }, - { - "id": 6443604, - "name": "Chelles", - "country": "FR", - "coord": { - "lon": 2.6, - "lat": 48.883331 - } - }, - { - "id": 6618272, - "name": "Cesson-Sévigné", - "country": "FR", - "coord": { - "lon": -1.603, - "lat": 48.121201 - } - }, - { - "id": 3028097, - "name": "Cayenne", - "country": "FR", - "coord": { - "lon": 1.62803, - "lat": 49.558578 - } - }, - { - "id": 6439436, - "name": "Carvin", - "country": "FR", - "coord": { - "lon": 2.96667, - "lat": 50.48333 - } - }, - { - "id": 6452010, - "name": "Bonneuil-sur-Marne", - "country": "FR", - "coord": { - "lon": 2.48333, - "lat": 48.76667 - } - }, - { - "id": 6455331, - "name": "Belfort", - "country": "FR", - "coord": { - "lon": 6.86667, - "lat": 47.633331 - } - }, - { - "id": 6447202, - "name": "Bayeux", - "country": "FR", - "coord": { - "lon": -0.703, - "lat": 49.278599 - } - }, - { - "id": 6613166, - "name": "Bagnolet", - "country": "FR", - "coord": { - "lon": 2.41667, - "lat": 48.866669 - } - }, - { - "id": 6450845, - "name": "Autun", - "country": "FR", - "coord": { - "lon": 4.3, - "lat": 46.950001 - } - }, - { - "id": 6448311, - "name": "Auch", - "country": "FR", - "coord": { - "lon": 0.58333, - "lat": 43.650002 - } - }, - { - "id": 6451006, - "name": "Annecy-le-Vieux", - "country": "FR", - "coord": { - "lon": 6.15, - "lat": 45.916672 - } - }, - { - "id": 6452610, - "name": "Alfortville", - "country": "FR", - "coord": { - "lon": 2.41667, - "lat": 48.799999 - } - }, - { - "id": 6455394, - "name": "Les Ulis", - "country": "FR", - "coord": { - "lon": 2.16932, - "lat": 48.68174 - } - }, - { - "id": 7300065, - "name": "Yate", - "country": "GB", - "coord": { - "lon": -2.40944, - "lat": 51.54805 - } - }, - { - "id": 7292818, - "name": "Caia Park", - "country": "GB", - "coord": { - "lon": -2.97767, - "lat": 53.045219 - } - }, - { - "id": 7290657, - "name": "Worcester District", - "country": "GB", - "coord": { - "lon": -2.20886, - "lat": 52.196121 - } - }, - { - "id": 3333222, - "name": "Borough of Wolverhampton", - "country": "GB", - "coord": { - "lon": -2.11667, - "lat": 52.583328 - } - }, - { - "id": 7299965, - "name": "Winsford", - "country": "GB", - "coord": { - "lon": -2.52331, - "lat": 53.19191 - } - }, - { - "id": 2634551, - "name": "Welwyn Hatfield", - "country": "GB", - "coord": { - "lon": -0.21667, - "lat": 51.75 - } - }, - { - "id": 3333211, - "name": "Borough of Trafford", - "country": "GB", - "coord": { - "lon": -2.33333, - "lat": 53.416672 - } - }, - { - "id": 7290632, - "name": "Tamworth District", - "country": "GB", - "coord": { - "lon": -1.6829, - "lat": 52.62273 - } - }, - { - "id": 7291961, - "name": "Wroughton", - "country": "GB", - "coord": { - "lon": -1.8056, - "lat": 51.517849 - } - }, - { - "id": 7290571, - "name": "Dartford District", - "country": "GB", - "coord": { - "lon": 0.24851, - "lat": 51.43388 - } - }, - { - "id": 7290673, - "name": "South Derbyshire District", - "country": "GB", - "coord": { - "lon": -1.53296, - "lat": 52.821999 - } - }, - { - "id": 3333208, - "name": "Borough of Tameside", - "country": "GB", - "coord": { - "lon": -2.08333, - "lat": 53.5 - } - }, - { - "id": 7291795, - "name": "Mossley", - "country": "GB", - "coord": { - "lon": -2.02418, - "lat": 53.516338 - } - }, - { - "id": 7294483, - "name": "Seaham", - "country": "GB", - "coord": { - "lon": -1.34838, - "lat": 54.8391 - } - }, - { - "id": 7295275, - "name": "Sandown", - "country": "GB", - "coord": { - "lon": -1.14195, - "lat": 50.661251 - } - }, - { - "id": 7297739, - "name": "Ryton", - "country": "GB", - "coord": { - "lon": -2.35315, - "lat": 52.624569 - } - }, - { - "id": 7290656, - "name": "Redditch District", - "country": "GB", - "coord": { - "lon": -1.94565, - "lat": 52.279331 - } - }, - { - "id": 7294048, - "name": "Prestatyn", - "country": "GB", - "coord": { - "lon": -3.40514, - "lat": 53.334641 - } - }, - { - "id": 7294693, - "name": "Peterlee", - "country": "GB", - "coord": { - "lon": -1.32905, - "lat": 54.758461 - } - }, - { - "id": 7301708, - "name": "Penarth", - "country": "GB", - "coord": { - "lon": -3.18138, - "lat": 51.43095 - } - }, - { - "id": 7292284, - "name": "Oswestry", - "country": "GB", - "coord": { - "lon": -3.05832, - "lat": 52.857101 - } - }, - { - "id": 7294581, - "name": "Northwich", - "country": "GB", - "coord": { - "lon": -2.51575, - "lat": 53.255798 - } - }, - { - "id": 2657122, - "name": "Ards District", - "country": "GB", - "coord": { - "lon": -5.58333, - "lat": 54.5 - } - }, - { - "id": 2641519, - "name": "Newtownards", - "country": "GB", - "coord": { - "lon": -5.69092, - "lat": 54.592361 - } - }, - { - "id": 7300025, - "name": "Newquay", - "country": "GB", - "coord": { - "lon": -5.07426, - "lat": 50.424091 - } - }, - { - "id": 7298888, - "name": "Nailsea", - "country": "GB", - "coord": { - "lon": -2.77756, - "lat": 51.424 - } - }, - { - "id": 7293862, - "name": "Morley", - "country": "GB", - "coord": { - "lon": -1.6034, - "lat": 53.742901 - } - }, - { - "id": 7293814, - "name": "Mirfield", - "country": "GB", - "coord": { - "lon": -1.69404, - "lat": 53.673901 - } - }, - { - "id": 7291605, - "name": "Maesteg", - "country": "GB", - "coord": { - "lon": -3.64713, - "lat": 51.61528 - } - }, - { - "id": 7296039, - "name": "Sutton", - "country": "GB", - "coord": { - "lon": -2.0931, - "lat": 53.227161 - } - }, - { - "id": 3333218, - "name": "City of Westminster", - "country": "GB", - "coord": { - "lon": -0.16667, - "lat": 51.5 - } - }, - { - "id": 7295996, - "name": "Sefton", - "country": "GB", - "coord": { - "lon": -2.97287, - "lat": 53.50441 - } - }, - { - "id": 3333227, - "name": "East Dunbartonshire", - "country": "GB", - "coord": { - "lon": -4.2, - "lat": 55.933331 - } - }, - { - "id": 3333226, - "name": "East Ayrshire", - "country": "GB", - "coord": { - "lon": -4.25, - "lat": 55.5 - } - }, - { - "id": 7296076, - "name": "Keynsham", - "country": "GB", - "coord": { - "lon": -2.49775, - "lat": 51.41251 - } - }, - { - "id": 7301693, - "name": "Kempston", - "country": "GB", - "coord": { - "lon": -0.49955, - "lat": 52.116791 - } - }, - { - "id": 7299757, - "name": "Horwich", - "country": "GB", - "coord": { - "lon": -2.52379, - "lat": 53.603069 - } - }, - { - "id": 7290564, - "name": "Dacorum District", - "country": "GB", - "coord": { - "lon": -0.57377, - "lat": 51.768509 - } - }, - { - "id": 7290687, - "name": "Hastings District", - "country": "GB", - "coord": { - "lon": 0.58145, - "lat": 50.867279 - } - }, - { - "id": 7291323, - "name": "Guisborough", - "country": "GB", - "coord": { - "lon": -1.07738, - "lat": 54.535629 - } - }, - { - "id": 7290595, - "name": "Great Yarmouth District", - "country": "GB", - "coord": { - "lon": 1.6469, - "lat": 52.633961 - } - }, - { - "id": 7290630, - "name": "South Staffordshire District", - "country": "GB", - "coord": { - "lon": -2.15319, - "lat": 52.604481 - } - }, - { - "id": 7296623, - "name": "Goole", - "country": "GB", - "coord": { - "lon": -0.87588, - "lat": 53.70216 - } - }, - { - "id": 7290556, - "name": "Fareham District", - "country": "GB", - "coord": { - "lon": -1.21114, - "lat": 50.8535 - } - }, - { - "id": 7290639, - "name": "Epsom and Ewell District", - "country": "GB", - "coord": { - "lon": -0.26017, - "lat": 51.335732 - } - }, - { - "id": 7290641, - "name": "Runnymede District", - "country": "GB", - "coord": { - "lon": -0.53722, - "lat": 51.394421 - } - }, - { - "id": 7300545, - "name": "Ebbw Vale", - "country": "GB", - "coord": { - "lon": -3.20482, - "lat": 51.77298 - } - }, - { - "id": 7290615, - "name": "Broxtowe District", - "country": "GB", - "coord": { - "lon": -1.25781, - "lat": 52.973049 - } - }, - { - "id": 7296192, - "name": "Dunstable", - "country": "GB", - "coord": { - "lon": -0.5173, - "lat": 51.884651 - } - }, - { - "id": 3333142, - "name": "City of Derby", - "country": "GB", - "coord": { - "lon": -1.47217, - "lat": 52.9207 - } - }, - { - "id": 7300542, - "name": "Eccleshill", - "country": "GB", - "coord": { - "lon": -2.4517, - "lat": 53.706779 - } - }, - { - "id": 7291971, - "name": "Cwmbran Central", - "country": "GB", - "coord": { - "lon": -3.02699, - "lat": 51.641171 - } - }, - { - "id": 7300082, - "name": "Healeyfield", - "country": "GB", - "coord": { - "lon": -1.8608, - "lat": 54.830681 - } - }, - { - "id": 7290582, - "name": "Ribble Valley District", - "country": "GB", - "coord": { - "lon": -2.41624, - "lat": 53.902439 - } - }, - { - "id": 7299112, - "name": "Sodbury", - "country": "GB", - "coord": { - "lon": -2.35653, - "lat": 51.541489 - } - }, - { - "id": 7296198, - "name": "Brymbo", - "country": "GB", - "coord": { - "lon": -3.08351, - "lat": 53.074551 - } - }, - { - "id": 7296060, - "name": "Brixham", - "country": "GB", - "coord": { - "lon": -3.51133, - "lat": 50.390831 - } - }, - { - "id": 7296000, - "name": "Bracknell", - "country": "GB", - "coord": { - "lon": -0.75918, - "lat": 51.406029 - } - }, - { - "id": 7291483, - "name": "Blyth", - "country": "GB", - "coord": { - "lon": -1.53835, - "lat": 55.117748 - } - }, - { - "id": 7299866, - "name": "Biggleswade", - "country": "GB", - "coord": { - "lon": -0.24536, - "lat": 52.078602 - } - }, - { - "id": 7298694, - "name": "Berkhamsted", - "country": "GB", - "coord": { - "lon": -0.5578, - "lat": 51.755138 - } - }, - { - "id": 7296167, - "name": "Bathampton", - "country": "GB", - "coord": { - "lon": -2.32627, - "lat": 51.3923 - } - }, - { - "id": 2641376, - "name": "North Down District", - "country": "GB", - "coord": { - "lon": -5.66667, - "lat": 54.666672 - } - }, - { - "id": 7298620, - "name": "Bangor", - "country": "GB", - "coord": { - "lon": -4.13579, - "lat": 53.222301 - } - }, - { - "id": 2656408, - "name": "Banbridge District", - "country": "GB", - "coord": { - "lon": -6.16667, - "lat": 54.333328 - } - }, - { - "id": 7292321, - "name": "Aberystwyth", - "country": "GB", - "coord": { - "lon": -4.07708, - "lat": 52.41227 - } - }, - { - "id": 6690583, - "name": "Chalk Farm", - "country": "GB", - "coord": { - "lon": -0.14987, - "lat": 51.543129 - } - }, - { - "id": 7290681, - "name": "East Dorset District", - "country": "GB", - "coord": { - "lon": -1.976, - "lat": 50.866901 - } - }, - { - "id": 612366, - "name": "Poti", - "country": "GE", - "coord": { - "lon": 41.67197, - "lat": 42.14616 - } - }, - { - "id": 2294938, - "name": "Tafo", - "country": "GH", - "coord": { - "lon": -1.61275, - "lat": 6.73453 - } - }, - { - "id": 2295385, - "name": "Shama Junction", - "country": "GH", - "coord": { - "lon": -1.63011, - "lat": 5.00872 - } - }, - { - "id": 2295672, - "name": "Saltpond", - "country": "GH", - "coord": { - "lon": -1.06058, - "lat": 5.20913 - } - }, - { - "id": 2301400, - "name": "Dunkwa", - "country": "GH", - "coord": { - "lon": -1.77995, - "lat": 5.96562 - } - }, - { - "id": 2416443, - "name": "Pita", - "country": "GN", - "coord": { - "lon": -12.4, - "lat": 11.08333 - } - }, - { - "id": 6690393, - "name": "Sainte-Anne", - "country": "GP", - "coord": { - "lon": -61.366669, - "lat": 16.23333 - } - }, - { - "id": 6690399, - "name": "Pointe-à-Pitre", - "country": "GP", - "coord": { - "lon": -61.51667, - "lat": 16.23333 - } - }, - { - "id": 6690387, - "name": "Les Abymes", - "country": "GP", - "coord": { - "lon": -61.5, - "lat": 16.26667 - } - }, - { - "id": 6690413, - "name": "Le Moule", - "country": "GP", - "coord": { - "lon": -61.333328, - "lat": 16.33333 - } - }, - { - "id": 6690408, - "name": "Capesterre-Belle-Eau", - "country": "GP", - "coord": { - "lon": -61.549999, - "lat": 16.049999 - } - }, - { - "id": 8133766, - "name": "Dimos Salamis", - "country": "GR", - "coord": { - "lon": 23.47966, - "lat": 37.938259 - } - }, - { - "id": 8133808, - "name": "Dimos Fyli", - "country": "GR", - "coord": { - "lon": 23.668631, - "lat": 38.12466 - } - }, - { - "id": 3426466, - "name": "Grytviken", - "country": "GS", - "coord": { - "lon": -36.509201, - "lat": -54.281109 - } - }, - { - "id": 3589799, - "name": "Municipio de San Marcos", - "country": "GT", - "coord": { - "lon": -91.800003, - "lat": 14.96667 - } - }, - { - "id": 3595722, - "name": "Municipio de Flores", - "country": "GT", - "coord": { - "lon": -89.897087, - "lat": 16.923809 - } - }, - { - "id": 3600456, - "name": "Departamento de Valle", - "country": "HN", - "coord": { - "lon": -87.583328, - "lat": 13.58333 - } - }, - { - "id": 3716661, - "name": "Thor", - "country": "HT", - "coord": { - "lon": -72.401382, - "lat": 18.536461 - } - }, - { - "id": 3740016, - "name": "Ti Port-de-Paix", - "country": "HT", - "coord": { - "lon": -72.833328, - "lat": 19.933331 - } - }, - { - "id": 3053876, - "name": "Csukásitanyák", - "country": "HU", - "coord": { - "lon": 19.316669, - "lat": 47.5 - } - }, - { - "id": 1213547, - "name": "Tanjungbalai", - "country": "ID", - "coord": { - "lon": 99.800003, - "lat": 2.96667 - } - }, - { - "id": 1214055, - "name": "Reuleuet", - "country": "ID", - "coord": { - "lon": 96.283333, - "lat": 5.21667 - } - }, - { - "id": 294622, - "name": "Judieda Makr", - "country": "IL", - "coord": { - "lon": 35.154999, - "lat": 32.92556 - } - }, - { - "id": 1252738, - "name": "Yeola", - "country": "IN", - "coord": { - "lon": 74.48333, - "lat": 20.033331 - } - }, - { - "id": 1252744, - "name": "Yellapur", - "country": "IN", - "coord": { - "lon": 74.716667, - "lat": 14.96667 - } - }, - { - "id": 1252773, - "name": "Yaval", - "country": "IN", - "coord": { - "lon": 75.699997, - "lat": 21.16667 - } - }, - { - "id": 6540553, - "name": "Ventimiglia", - "country": "IT", - "coord": { - "lon": 7.60264, - "lat": 43.793522 - } - }, - { - "id": 6542009, - "name": "Savona", - "country": "IT", - "coord": { - "lon": 8.47375, - "lat": 44.30814 - } - }, - { - "id": 6537557, - "name": "Ruvo di Puglia", - "country": "IT", - "coord": { - "lon": 16.48778, - "lat": 41.113628 - } - }, - { - "id": 6539485, - "name": "Pioltello", - "country": "IT", - "coord": { - "lon": 9.32435, - "lat": 45.497971 - } - }, - { - "id": 6536957, - "name": "Palestrina", - "country": "IT", - "coord": { - "lon": 12.88899, - "lat": 41.835522 - } - }, - { - "id": 6537567, - "name": "Palagiano", - "country": "IT", - "coord": { - "lon": 17.037399, - "lat": 40.57822 - } - }, - { - "id": 6538821, - "name": "Pagani", - "country": "IT", - "coord": { - "lon": 14.61334, - "lat": 40.751511 - } - }, - { - "id": 6541936, - "name": "Orta Nova", - "country": "IT", - "coord": { - "lon": 15.71066, - "lat": 41.329929 - } - }, - { - "id": 6540026, - "name": "Oria", - "country": "IT", - "coord": { - "lon": 17.64131, - "lat": 40.49733 - } - }, - { - "id": 6537554, - "name": "Noicattaro", - "country": "IT", - "coord": { - "lon": 16.98959, - "lat": 41.033829 - } - }, - { - "id": 6542044, - "name": "Nettuno", - "country": "IT", - "coord": { - "lon": 12.67899, - "lat": 41.482609 - } - }, - { - "id": 6541509, - "name": "Negrar", - "country": "IT", - "coord": { - "lon": 10.93798, - "lat": 45.52879 - } - }, - { - "id": 6540220, - "name": "Mira", - "country": "IT", - "coord": { - "lon": 12.13481, - "lat": 45.435799 - } - }, - { - "id": 6540584, - "name": "Lissone", - "country": "IT", - "coord": { - "lon": 9.24655, - "lat": 45.615582 - } - }, - { - "id": 6538560, - "name": "Lastra a Signa", - "country": "IT", - "coord": { - "lon": 11.10282, - "lat": 43.771351 - } - }, - { - "id": 6541484, - "name": "Imperia", - "country": "IT", - "coord": { - "lon": 8.02225, - "lat": 43.88332 - } - }, - { - "id": 6541474, - "name": "Jesi", - "country": "IT", - "coord": { - "lon": 13.24017, - "lat": 43.528759 - } - }, - { - "id": 6541164, - "name": "Giugliano in Campania", - "country": "IT", - "coord": { - "lon": 14.19103, - "lat": 40.92741 - } - }, - { - "id": 6537588, - "name": "Galatone", - "country": "IT", - "coord": { - "lon": 18.070419, - "lat": 40.142921 - } - }, - { - "id": 6542094, - "name": "Gaeta", - "country": "IT", - "coord": { - "lon": 13.56281, - "lat": 41.218311 - } - }, - { - "id": 6541853, - "name": "Frosinone", - "country": "IT", - "coord": { - "lon": 13.3401, - "lat": 41.640018 - } - }, - { - "id": 6538453, - "name": "Formigine", - "country": "IT", - "coord": { - "lon": 10.847, - "lat": 44.57296 - } - }, - { - "id": 6541136, - "name": "Fondi", - "country": "IT", - "coord": { - "lon": 13.43131, - "lat": 41.354111 - } - }, - { - "id": 6540408, - "name": "Fidenza", - "country": "IT", - "coord": { - "lon": 10.06668, - "lat": 44.86396 - } - }, - { - "id": 6536870, - "name": "Corciano", - "country": "IT", - "coord": { - "lon": 12.28736, - "lat": 43.12904 - } - }, - { - "id": 6540023, - "name": "Conversano", - "country": "IT", - "coord": { - "lon": 17.11479, - "lat": 40.966228 - } - }, - { - "id": 6539925, - "name": "Cittadella", - "country": "IT", - "coord": { - "lon": 11.7842, - "lat": 45.650002 - } - }, - { - "id": 6538144, - "name": "Bra", - "country": "IT", - "coord": { - "lon": 7.85563, - "lat": 44.703041 - } - }, - { - "id": 6542123, - "name": "Benevento", - "country": "IT", - "coord": { - "lon": 14.78614, - "lat": 41.12952 - } - }, - { - "id": 6542012, - "name": "Bareggio", - "country": "IT", - "coord": { - "lon": 8.99994, - "lat": 45.487671 - } - }, - { - "id": 6541492, - "name": "Arese", - "country": "IT", - "coord": { - "lon": 9.07654, - "lat": 45.552269 - } - }, - { - "id": 6541135, - "name": "Aprilia", - "country": "IT", - "coord": { - "lon": 12.65009, - "lat": 41.589512 - } - }, - { - "id": 6540534, - "name": "Anagni", - "country": "IT", - "coord": { - "lon": 13.15269, - "lat": 41.74472 - } - }, - { - "id": 6536221, - "name": "Spinea", - "country": "IT", - "coord": { - "lon": 12.16251, - "lat": 45.488701 - } - }, - { - "id": 6542340, - "name": "Volla", - "country": "IT", - "coord": { - "lon": 14.34293, - "lat": 40.87841 - } - }, - { - "id": 3489227, - "name": "Old Harbour", - "country": "JM", - "coord": { - "lon": -77.108978, - "lat": 17.941441 - } - }, - { - "id": 3489297, - "name": "New Kingston", - "country": "JM", - "coord": { - "lon": -76.783188, - "lat": 18.007469 - } - }, - { - "id": 1859472, - "name": "Kimiidera", - "country": "JP", - "coord": { - "lon": 135.199997, - "lat": 34.183331 - } - }, - { - "id": 1037370, - "name": "Mocimboa", - "country": "MZ", - "coord": { - "lon": 40.349998, - "lat": -11.31667 - } - }, - { - "id": 2749810, - "name": "Gemeente Noordwijkerhout", - "country": "NL", - "coord": { - "lon": 4.48333, - "lat": 52.25 - } - }, - { - "id": 2751688, - "name": "Gemeente Leusden", - "country": "NL", - "coord": { - "lon": 5.41667, - "lat": 52.133331 - } - }, - { - "id": 2753467, - "name": "Gemeente Huizen", - "country": "NL", - "coord": { - "lon": 5.23333, - "lat": 52.283329 - } - }, - { - "id": 2753718, - "name": "Gemeente Hoogeveen", - "country": "NL", - "coord": { - "lon": 6.58333, - "lat": 52.683331 - } - }, - { - "id": 2754696, - "name": "Gemeente Heemskerk", - "country": "NL", - "coord": { - "lon": 4.65386, - "lat": 52.509449 - } - }, - { - "id": 2759874, - "name": "Gemeente Alphen aan den Rijn", - "country": "NL", - "coord": { - "lon": 4.65, - "lat": 52.133331 - } - }, - { - "id": 3160606, - "name": "Horten", - "country": "NO", - "coord": { - "lon": 10.48527, - "lat": 59.41547 - } - }, - { - "id": 6453374, - "name": "Haugesund", - "country": "NO", - "coord": { - "lon": 5.27551, - "lat": 59.410149 - } - }, - { - "id": 6453355, - "name": "Gjøvik", - "country": "NO", - "coord": { - "lon": 10.69287, - "lat": 60.79472 - } - }, - { - "id": 6453341, - "name": "Ålesund", - "country": "NO", - "coord": { - "lon": 6.15424, - "lat": 62.471241 - } - }, - { - "id": 1282635, - "name": "Tulsipur", - "country": "NP", - "coord": { - "lon": 82.297256, - "lat": 28.130989 - } - }, - { - "id": 6240770, - "name": "Cambridge", - "country": "NZ", - "coord": { - "lon": 175.440201, - "lat": -37.87822 - } - }, - { - "id": 288721, - "name": "Bidbid", - "country": "OM", - "coord": { - "lon": 58.1283, - "lat": 23.40786 - } - }, - { - "id": 288764, - "name": "Bawshar", - "country": "OM", - "coord": { - "lon": 58.398899, - "lat": 23.55563 - } - }, - { - "id": 288902, - "name": "Badiyah", - "country": "OM", - "coord": { - "lon": 58.799999, - "lat": 22.450001 - } - }, - { - "id": 288955, - "name": "As Suwayq", - "country": "OM", - "coord": { - "lon": 57.43861, - "lat": 23.84944 - } - }, - { - "id": 3691094, - "name": "Uchiza", - "country": "PE", - "coord": { - "lon": -76.463333, - "lat": -8.45917 - } - }, - { - "id": 7530966, - "name": "Włocławek", - "country": "PL", - "coord": { - "lon": 19.060829, - "lat": 52.665379 - } - }, - { - "id": 7531696, - "name": "Świdwin", - "country": "PL", - "coord": { - "lon": 15.7973, - "lat": 53.7742 - } - }, - { - "id": 7530961, - "name": "Jastrzębie-Zdrój", - "country": "PL", - "coord": { - "lon": 18.600531, - "lat": 49.960629 - } - }, - { - "id": 7532652, - "name": "Bełchatów", - "country": "PL", - "coord": { - "lon": 19.3626, - "lat": 51.3545 - } - }, - { - "id": 4562506, - "name": "Aguadilla", - "country": "PR", - "coord": { - "lon": -67.154068, - "lat": 18.42745 - } - }, - { - "id": 8014434, - "name": "Vila Franca de Xira", - "country": "PT", - "coord": { - "lon": -8.96442, - "lat": 38.912411 - } - }, - { - "id": 8012598, - "name": "Ramada", - "country": "PT", - "coord": { - "lon": -9.19464, - "lat": 38.806961 - } - }, - { - "id": 8013113, - "name": "Almada", - "country": "PT", - "coord": { - "lon": -9.16249, - "lat": 38.678871 - } - }, - { - "id": 8012746, - "name": "Gueifães", - "country": "PT", - "coord": { - "lon": -8.6052, - "lat": 41.215248 - } - }, - { - "id": 499452, - "name": "Safonovo", - "country": "RU", - "coord": { - "lon": 33.216671, - "lat": 55.150002 - } - }, - { - "id": 2695079, - "name": "Lillsjönäs", - "country": "SE", - "coord": { - "lon": 17.950001, - "lat": 59.333328 - } - }, - { - "id": 2407660, - "name": "Koidu", - "country": "SL", - "coord": { - "lon": -10.83333, - "lat": 8.41667 - } - }, - { - "id": 1607257, - "name": "Prakhon Chai", - "country": "TH", - "coord": { - "lon": 103.120811, - "lat": 14.60592 - } - }, - { - "id": 1609031, - "name": "Changwat Lop Buri", - "country": "TH", - "coord": { - "lon": 100.75, - "lat": 14.93333 - } - }, - { - "id": 742902, - "name": "Kocaali", - "country": "TR", - "coord": { - "lon": 30.852779, - "lat": 41.05336 - } - }, - { - "id": 148942, - "name": "Vwawa", - "country": "TZ", - "coord": { - "lon": 32.933331, - "lat": -9.11667 - } - }, - { - "id": 4056099, - "name": "Coffee County", - "country": "US", - "coord": { - "lon": -86.000221, - "lat": 31.41683 - } - }, - { - "id": 4151245, - "name": "Clay County", - "country": "US", - "coord": { - "lon": -81.833153, - "lat": 29.99968 - } - }, - { - "id": 4155535, - "name": "Flagler County", - "country": "US", - "coord": { - "lon": -81.291451, - "lat": 29.45859 - } - }, - { - "id": 4158449, - "name": "Hernando County", - "country": "US", - "coord": { - "lon": -82.458153, - "lat": 28.541941 - } - }, - { - "id": 4174301, - "name": "Sumter County", - "country": "US", - "coord": { - "lon": -82.083138, - "lat": 28.708599 - } - }, - { - "id": 4196508, - "name": "Fulton County", - "country": "US", - "coord": { - "lon": -84.449928, - "lat": 33.766769 - } - }, - { - "id": 4191014, - "name": "DeKalb County", - "country": "US", - "coord": { - "lon": -84.233253, - "lat": 33.750381 - } - }, - { - "id": 4255818, - "name": "Clark County", - "country": "US", - "coord": { - "lon": -85.761353, - "lat": 38.483398 - } - }, - { - "id": 4310411, - "name": "Sylvania", - "country": "US", - "coord": { - "lon": -85.87413, - "lat": 38.157009 - } - }, - { - "id": 4287837, - "name": "Clark County", - "country": "US", - "coord": { - "lon": -84.266602, - "lat": 37.98341 - } - }, - { - "id": 4347820, - "name": "City of Baltimore", - "country": "US", - "coord": { - "lon": -76.61219, - "lat": 39.290379 - } - }, - { - "id": 7198188, - "name": "Cashell Estates", - "country": "US", - "coord": { - "lon": -77.138702, - "lat": 39.137199 - } - }, - { - "id": 4372589, - "name": "Wakely Terrace", - "country": "US", - "coord": { - "lon": -76.334961, - "lat": 39.525661 - } - }, - { - "id": 4406835, - "name": "Saint Charles County", - "country": "US", - "coord": { - "lon": -90.733459, - "lat": 38.76672 - } - }, - { - "id": 4407084, - "name": "City of Saint Louis", - "country": "US", - "coord": { - "lon": -90.197891, - "lat": 38.62727 - } - }, - { - "id": 4422178, - "name": "Coahoma County", - "country": "US", - "coord": { - "lon": -90.567879, - "lat": 34.217892 - } - }, - { - "id": 4431425, - "name": "Jackson County", - "country": "US", - "coord": { - "lon": -88.6278, - "lat": 30.42325 - } - }, - { - "id": 4481511, - "name": "Nash County", - "country": "US", - "coord": { - "lon": -77.96637, - "lat": 35.96682 - } - }, - { - "id": 4475520, - "name": "Lee County", - "country": "US", - "coord": { - "lon": -79.183083, - "lat": 35.46682 - } - }, - { - "id": 4527624, - "name": "Warren County", - "country": "US", - "coord": { - "lon": -84.166603, - "lat": 39.433392 - } - }, - { - "id": 4534444, - "name": "Creek County", - "country": "US", - "coord": { - "lon": -96.400291, - "lat": 35.900082 - } - }, - { - "id": 4592843, - "name": "Richland County", - "country": "US", - "coord": { - "lon": -80.916481, - "lat": 34.016819 - } - }, - { - "id": 4735729, - "name": "Taylor County", - "country": "US", - "coord": { - "lon": -99.833702, - "lat": 32.300129 - } - }, - { - "id": 4697444, - "name": "Hidalgo County", - "country": "US", - "coord": { - "lon": -98.200287, - "lat": 26.333679 - } - }, - { - "id": 4740157, - "name": "Washington County", - "country": "US", - "coord": { - "lon": -96.400238, - "lat": 30.233549 - } - }, - { - "id": 4739690, - "name": "Walker County", - "country": "US", - "coord": { - "lon": -95.566887, - "lat": 30.73353 - } - }, - { - "id": 4703071, - "name": "Kerr County", - "country": "US", - "coord": { - "lon": -99.300323, - "lat": 30.050211 - } - }, - { - "id": 4744106, - "name": "City of Alexandria", - "country": "US", - "coord": { - "lon": -77.046921, - "lat": 38.80484 - } - }, - { - "id": 4749005, - "name": "City of Bristol", - "country": "US", - "coord": { - "lon": -82.188469, - "lat": 36.596489 - } - }, - { - "id": 4752046, - "name": "City of Charlottesville", - "country": "US", - "coord": { - "lon": -78.476677, - "lat": 38.029308 - } - }, - { - "id": 4752215, - "name": "City of Chesapeake", - "country": "US", - "coord": { - "lon": -76.312157, - "lat": 36.687649 - } - }, - { - "id": 4753684, - "name": "City of Colonial Heights", - "country": "US", - "coord": { - "lon": -77.410263, - "lat": 37.244041 - } - }, - { - "id": 4755298, - "name": "City of Danville", - "country": "US", - "coord": { - "lon": -79.39502, - "lat": 36.585972 - } - }, - { - "id": 4758109, - "name": "City of Fairfax", - "country": "US", - "coord": { - "lon": -77.306374, - "lat": 38.846218 - } - }, - { - "id": 4760084, - "name": "City of Fredericksburg", - "country": "US", - "coord": { - "lon": -77.460541, - "lat": 38.303181 - } - }, - { - "id": 4763237, - "name": "City of Harrisonburg", - "country": "US", - "coord": { - "lon": -78.868919, - "lat": 38.44957 - } - }, - { - "id": 4764849, - "name": "City of Hopewell", - "country": "US", - "coord": { - "lon": -77.287201, - "lat": 37.304321 - } - }, - { - "id": 4771099, - "name": "City of Lynchburg", - "country": "US", - "coord": { - "lon": -79.14225, - "lat": 37.41375 - } - }, - { - "id": 4771426, - "name": "City of Manassas", - "country": "US", - "coord": { - "lon": -77.475273, - "lat": 38.75095 - } - }, - { - "id": 4776037, - "name": "City of Newport News", - "country": "US", - "coord": { - "lon": -76.508011, - "lat": 37.062649 - } - }, - { - "id": 4776242, - "name": "City of Norfolk", - "country": "US", - "coord": { - "lon": -76.261879, - "lat": 36.891258 - } - }, - { - "id": 4778642, - "name": "City of Petersburg", - "country": "US", - "coord": { - "lon": -77.401932, - "lat": 37.227928 - } - }, - { - "id": 4780019, - "name": "City of Portsmouth", - "country": "US", - "coord": { - "lon": -76.354668, - "lat": 36.85487 - } - }, - { - "id": 4780851, - "name": "City of Radford", - "country": "US", - "coord": { - "lon": -80.576447, - "lat": 37.13179 - } - }, - { - "id": 4781756, - "name": "City of Richmond", - "country": "US", - "coord": { - "lon": -77.460258, - "lat": 37.553761 - } - }, - { - "id": 4782241, - "name": "City of Roanoke", - "country": "US", - "coord": { - "lon": -79.941429, - "lat": 37.270969 - } - }, - { - "id": 4784205, - "name": "City of Salem", - "country": "US", - "coord": { - "lon": -80.054764, - "lat": 37.293468 - } - }, - { - "id": 4788160, - "name": "City of Suffolk", - "country": "US", - "coord": { - "lon": -76.608009, - "lat": 36.708481 - } - }, - { - "id": 4787467, - "name": "City of Staunton", - "country": "US", - "coord": { - "lon": -79.071701, - "lat": 38.149578 - } - }, - { - "id": 4792534, - "name": "City of Waynesboro", - "country": "US", - "coord": { - "lon": -78.889473, - "lat": 38.06847 - } - }, - { - "id": 4794134, - "name": "City of Winchester", - "country": "US", - "coord": { - "lon": -78.16333, - "lat": 39.185661 - } - }, - { - "id": 5151606, - "name": "Cuyahoga County", - "country": "US", - "coord": { - "lon": -81.666519, - "lat": 41.433392 - } - }, - { - "id": 4899519, - "name": "Lee County", - "country": "US", - "coord": { - "lon": -89.283432, - "lat": 41.750591 - } - }, - { - "id": 4898722, - "name": "Knox County", - "country": "US", - "coord": { - "lon": -90.200119, - "lat": 40.933369 - } - }, - { - "id": 5004681, - "name": "Ottawa County", - "country": "US", - "coord": { - "lon": -86.000603, - "lat": 42.95002 - } - }, - { - "id": 4985190, - "name": "Bay County", - "country": "US", - "coord": { - "lon": -84.016647, - "lat": 43.73336 - } - }, - { - "id": 5000477, - "name": "Macomb County", - "country": "US", - "coord": { - "lon": -82.949928, - "lat": 42.700031 - } - }, - { - "id": 4997130, - "name": "Ingham County", - "country": "US", - "coord": { - "lon": -84.383301, - "lat": 42.60004 - } - }, - { - "id": 5009706, - "name": "Shiawassee County", - "country": "US", - "coord": { - "lon": -84.149971, - "lat": 42.950031 - } - }, - { - "id": 5128316, - "name": "Nassau County", - "country": "US", - "coord": { - "lon": -73.582901, - "lat": 40.75066 - } - }, - { - "id": 6941775, - "name": "Kings County", - "country": "US", - "coord": { - "lon": -73.949577, - "lat": 40.650101 - } - }, - { - "id": 5113792, - "name": "Cortland County", - "country": "US", - "coord": { - "lon": -76.082977, - "lat": 42.600071 - } - }, - { - "id": 5112738, - "name": "City Line", - "country": "US", - "coord": { - "lon": -73.887077, - "lat": 40.676208 - } - }, - { - "id": 5118116, - "name": "Fulton County", - "country": "US", - "coord": { - "lon": -74.449577, - "lat": 43.116741 - } - }, - { - "id": 5122534, - "name": "Jamestown", - "country": "US", - "coord": { - "lon": -79.235329, - "lat": 42.097 - } - }, - { - "id": 6332485, - "name": "Queensbridge Houses", - "country": "US", - "coord": { - "lon": -73.945, - "lat": 40.75528 - } - }, - { - "id": 7250946, - "name": "Carnegie Hill", - "country": "US", - "coord": { - "lon": -73.95472, - "lat": 40.783329 - } - }, - { - "id": 5133668, - "name": "Rensselaer County", - "country": "US", - "coord": { - "lon": -73.482887, - "lat": 42.716751 - } - }, - { - "id": 5161640, - "name": "Mahoning County", - "country": "US", - "coord": { - "lon": -80.766472, - "lat": 41.03339 - } - }, - { - "id": 5151896, - "name": "Delaware County", - "country": "US", - "coord": { - "lon": -83.000183, - "lat": 40.266731 - } - }, - { - "id": 5145576, - "name": "Allen County", - "country": "US", - "coord": { - "lon": -84.083282, - "lat": 40.76672 - } - }, - { - "id": 5153362, - "name": "Erie County", - "country": "US", - "coord": { - "lon": -82.599899, - "lat": 41.350052 - } - }, - { - "id": 5221078, - "name": "Bristol County", - "country": "US", - "coord": { - "lon": -71.271721, - "lat": 41.71677 - } - }, - { - "id": 5393068, - "name": "Santa Cruz County", - "country": "US", - "coord": { - "lon": -122.051071, - "lat": 37.066608 - } - }, - { - "id": 5391997, - "name": "San Francisco County", - "country": "US", - "coord": { - "lon": -122.45108, - "lat": 37.766602 - } - }, - { - "id": 5423573, - "name": "Grand Junction", - "country": "US", - "coord": { - "lon": -108.550652, - "lat": 39.063869 - } - }, - { - "id": 5525886, - "name": "Maverick County", - "country": "US", - "coord": { - "lon": -100.350349, - "lat": 28.76692 - } - }, - { - "id": 5522430, - "name": "Gray County", - "country": "US", - "coord": { - "lon": -100.802002, - "lat": 35.416698 - } - }, - { - "id": 1512838, - "name": "Shofirkon", - "country": "UZ", - "coord": { - "lon": 64.501389, - "lat": 40.119999 - } - }, - { - "id": 1512978, - "name": "Qushkupir", - "country": "UZ", - "coord": { - "lon": 60.345558, - "lat": 41.535 - } - }, - { - "id": 1513017, - "name": "Parkent", - "country": "UZ", - "coord": { - "lon": 69.676392, - "lat": 41.294441 - } - }, - { - "id": 1513023, - "name": "Pop", - "country": "UZ", - "coord": { - "lon": 71.108887, - "lat": 40.873611 - } - }, - { - "id": 1513038, - "name": "Paxtakor", - "country": "UZ", - "coord": { - "lon": 67.954437, - "lat": 40.315281 - } - }, - { - "id": 1513092, - "name": "Novyy Turtkul", - "country": "UZ", - "coord": { - "lon": 61.01667, - "lat": 41.549999 - } - }, - { - "id": 1513245, - "name": "Manghit", - "country": "UZ", - "coord": { - "lon": 60.059719, - "lat": 42.115559 - } - }, - { - "id": 1513655, - "name": "Haqqulobod", - "country": "UZ", - "coord": { - "lon": 72.116669, - "lat": 40.916672 - } - }, - { - "id": 1513900, - "name": "Iskandar", - "country": "UZ", - "coord": { - "lon": 69.700829, - "lat": 41.55389 - } - }, - { - "id": 1513957, - "name": "Hazorasp", - "country": "UZ", - "coord": { - "lon": 61.074169, - "lat": 41.319439 - } - }, - { - "id": 1514215, - "name": "Chinoz", - "country": "UZ", - "coord": { - "lon": 68.769722, - "lat": 40.93639 - } - }, - { - "id": 1514330, - "name": "Buka", - "country": "UZ", - "coord": { - "lon": 69.198608, - "lat": 40.810829 - } - }, - { - "id": 1514387, - "name": "Beruniy", - "country": "UZ", - "coord": { - "lon": 60.752499, - "lat": 41.691109 - } - }, - { - "id": 1514396, - "name": "Bektemir", - "country": "UZ", - "coord": { - "lon": 69.334167, - "lat": 41.209721 - } - }, - { - "id": 1526979, - "name": "Quva", - "country": "UZ", - "coord": { - "lon": 72.072922, - "lat": 40.522041 - } - }, - { - "id": 3748724, - "name": "Redemption", - "country": "VC", - "coord": { - "lon": -61.229439, - "lat": 13.16444 - } - }, - { - "id": 3649281, - "name": "Municipio Anaco", - "country": "VE", - "coord": { - "lon": -64.466667, - "lat": 9.33333 - } - }, - { - "id": 3486270, - "name": "Anaco", - "country": "VE", - "coord": { - "lon": -64.472778, - "lat": 9.43889 - } - }, - { - "id": 3625123, - "name": "Municipio Zamora", - "country": "VE", - "coord": { - "lon": -67.5, - "lat": 10.06667 - } - }, - { - "id": 3625547, - "name": "Municipio Valencia", - "country": "VE", - "coord": { - "lon": -68.083328, - "lat": 10.08333 - } - }, - { - "id": 8129205, - "name": "Municipio Santiago Mariño", - "country": "VE", - "coord": { - "lon": -67.472878, - "lat": 10.22388 - } - }, - { - "id": 3628416, - "name": "Municipio San Felipe", - "country": "VE", - "coord": { - "lon": -68.633331, - "lat": 10.5 - } - }, - { - "id": 3645361, - "name": "Municipio Colón", - "country": "VE", - "coord": { - "lon": -72.083328, - "lat": 9 - } - }, - { - "id": 3628494, - "name": "Municipio San Carlos", - "country": "VE", - "coord": { - "lon": -68.583328, - "lat": 9.58333 - } - }, - { - "id": 8129204, - "name": "Municipio Los Salias", - "country": "VE", - "coord": { - "lon": -66.95179, - "lat": 10.38854 - } - }, - { - "id": 8129175, - "name": "Municipio Sucre", - "country": "VE", - "coord": { - "lon": -66.801552, - "lat": 10.47226 - } - }, - { - "id": 8129237, - "name": "Municipio Libertador", - "country": "VE", - "coord": { - "lon": -67.541939, - "lat": 10.17389 - } - }, - { - "id": 3630932, - "name": "Palo Negro", - "country": "VE", - "coord": { - "lon": -67.541939, - "lat": 10.17389 - } - }, - { - "id": 3631506, - "name": "Municipio Nirgua", - "country": "VE", - "coord": { - "lon": -68.666672, - "lat": 10.08333 - } - }, - ]; \ No newline at end of file + 'id': 707860, + 'name': 'Hurzuf', + 'country': 'UA', + 'coord': {'lon': 34.283333, 'lat': 44.549999} + }, + { + 'id': 519188, + 'name': 'Novinki', + 'country': 'RU', + 'coord': {'lon': 37.666668, 'lat': 55.683334} + }, + { + 'id': 1283378, + 'name': 'Gorkhā', + 'country': 'NP', + 'coord': {'lon': 84.633331, 'lat': 28} + }, + { + 'id': 1270260, + 'name': 'State of Haryāna', + 'country': 'IN', + 'coord': {'lon': 76, 'lat': 29} + }, + { + 'id': 708546, + 'name': 'Holubynka', + 'country': 'UA', + 'coord': {'lon': 33.900002, 'lat': 44.599998} + }, + { + 'id': 1283710, + 'name': 'Bāgmatī Zone', + 'country': 'NP', + 'coord': {'lon': 85.416664, 'lat': 28} + }, + { + 'id': 529334, + 'name': 'Mar’ina Roshcha', + 'country': 'RU', + 'coord': {'lon': 37.611111, 'lat': 55.796391} + }, + { + 'id': 1269750, + 'name': 'Republic of India', + 'country': 'IN', + 'coord': {'lon': 77, 'lat': 20} + }, + { + 'id': 1283240, + 'name': 'Kathmandu', + 'country': 'NP', + 'coord': {'lon': 85.316666, 'lat': 27.716667} + }, + { + 'id': 703363, + 'name': 'Laspi', + 'country': 'UA', + 'coord': {'lon': 33.733334, 'lat': 44.416668} + }, + { + 'id': 3632308, + 'name': 'Merida', + 'country': 'VE', + 'coord': {'lon': -71.144997, 'lat': 8.598333} + }, + { + 'id': 473537, + 'name': 'Vinogradovo', + 'country': 'RU', + 'coord': {'lon': 38.545555, 'lat': 55.423332} + }, + { + 'id': 384848, + 'name': 'Qarah Gawl al ‘Ulyā', + 'country': 'IQ', + 'coord': {'lon': 45.6325, 'lat': 35.353889} + }, + { + 'id': 569143, + 'name': 'Cherkizovo', + 'country': 'RU', + 'coord': {'lon': 37.728889, 'lat': 55.800835} + }, + { + 'id': 713514, + 'name': 'Alupka', + 'country': 'UA', + 'coord': {'lon': 34.049999, 'lat': 44.416668} + }, + { + 'id': 2878044, + 'name': 'Lichtenrade', + 'country': 'DE', + 'coord': {'lon': 13.40637, 'lat': 52.398441} + }, + { + 'id': 464176, + 'name': 'Zavety Il’icha', + 'country': 'RU', + 'coord': {'lon': 37.849998, 'lat': 56.049999} + }, + { + 'id': 295582, + 'name': '‘Azriqam', + 'country': 'IL', + 'coord': {'lon': 34.700001, 'lat': 31.75} + }, + { + 'id': 1271231, + 'name': 'Ghūra', + 'country': 'IN', + 'coord': {'lon': 79.883331, 'lat': 24.766666} + }, + { + 'id': 690856, + 'name': 'Tyuzler', + 'country': 'UA', + 'coord': {'lon': 34.083332, 'lat': 44.466667} + }, + { + 'id': 464737, + 'name': 'Zaponor’ye', + 'country': 'RU', + 'coord': {'lon': 38.861942, 'lat': 55.639999} + }, + { + 'id': 707716, + 'name': 'Il’ichëvka', + 'country': 'UA', + 'coord': {'lon': 34.383331, 'lat': 44.666668} + }, + { + 'id': 697959, + 'name': 'Partyzans’ke', + 'country': 'UA', + 'coord': {'lon': 34.083332, 'lat': 44.833332} + }, + { + 'id': 803611, + 'name': 'Yurevichi', + 'country': 'RU', + 'coord': {'lon': 39.934444, 'lat': 43.600555} + }, + { + 'id': 614371, + 'name': 'Gumist’a', + 'country': 'GE', + 'coord': {'lon': 40.973888, 'lat': 43.026943} + }, + { + 'id': 874560, + 'name': 'Ptitsefabrika', + 'country': 'GE', + 'coord': {'lon': 40.290558, 'lat': 43.183613} + }, + { + 'id': 874652, + 'name': 'Orekhovo', + 'country': 'GE', + 'coord': {'lon': 40.146111, 'lat': 43.351391} + }, + { + 'id': 2347078, + 'name': 'Birim', + 'country': 'NG', + 'coord': {'lon': 9.997027, 'lat': 10.062094} + }, + { + 'id': 2051302, + 'name': 'Priiskovyy', + 'country': 'RU', + 'coord': {'lon': 132.822495, 'lat': 42.819168} + }, + { + 'id': 563692, + 'name': 'Dzhaga', + 'country': 'RU', + 'coord': {'lon': 42.650002, 'lat': 43.25} + }, + { + 'id': 481725, + 'name': 'Tret’ya Rota', + 'country': 'RU', + 'coord': {'lon': 39.681389, 'lat': 43.741943} + }, + { + 'id': 2638976, + 'name': 'Ruislip', + 'country': 'GB', + 'coord': {'lon': -0.42341, 'lat': 51.573441} + }, + { + 'id': 2892705, + 'name': 'Karow', + 'country': 'DE', + 'coord': {'lon': 13.48117, 'lat': 52.609039} + }, + { + 'id': 2922336, + 'name': 'Gatow', + 'country': 'DE', + 'coord': {'lon': 13.18285, 'lat': 52.483238} + }, + { + 'id': 975511, + 'name': 'Mkuze', + 'country': 'ZA', + 'coord': {'lon': 32.038609, 'lat': -27.616409} + }, + { + 'id': 1280737, + 'name': 'Lhasa', + 'country': 'CN', + 'coord': {'lon': 91.099998, 'lat': 29.65} + }, + { + 'id': 745042, + 'name': 'İstanbul', + 'country': 'TR', + 'coord': {'lon': 28.983311, 'lat': 41.03508} + }, + { + 'id': 3496831, + 'name': 'Mao', + 'country': 'DO', + 'coord': {'lon': -71.078133, 'lat': 19.551861} + }, + { + 'id': 2017370, + 'name': 'Russian Federation', + 'country': 'RU', + 'coord': {'lon': 100, 'lat': 60} + }, + { + 'id': 2045761, + 'name': 'De-Friz', + 'country': 'RU', + 'coord': {'lon': 131.991394, 'lat': 43.27861} + }, + { + 'id': 1257986, + 'name': 'Rumbak', + 'country': 'IN', + 'coord': {'lon': 77.416664, 'lat': 34.049999} + }, + { + 'id': 476350, + 'name': 'Vavibet', + 'country': 'RU', + 'coord': {'lon': 34.916668, 'lat': 67.933334} + }, + { + 'id': 1343000, + 'name': 'Surtagān Chib', + 'country': 'PK', + 'coord': {'lon': 64.656113, 'lat': 26.474443} + }, + { + 'id': 456169, + 'name': 'Rīgas Rajons', + 'country': 'LV', + 'coord': {'lon': 24.333332, 'lat': 57} + }, + { + 'id': 475279, + 'name': 'Verkhneye Shchekotikhino', + 'country': 'RU', + 'coord': {'lon': 36.133331, 'lat': 53} + }, + { + 'id': 711349, + 'name': 'Bucha', + 'country': 'UA', + 'coord': {'lon': 30.366671, 'lat': 50.583328} + }, + { + 'id': 798544, + 'name': 'Republic of Poland', + 'country': 'PL', + 'coord': {'lon': 20, 'lat': 52} + }, + { + 'id': 3094325, + 'name': 'Kuchary', + 'country': 'PL', + 'coord': {'lon': 19.383329, 'lat': 52.150002} + }, + { + 'id': 6255149, + 'name': 'North America', + 'country': '', + 'coord': {'lon': -100.546883, 'lat': 46.073231} + }, + { + 'id': 3575514, + 'name': 'Brumaire', + 'country': 'KN', + 'coord': {'lon': -62.73333, 'lat': 17.299999} + }, + { + 'id': 1861387, + 'name': 'Ishikawa-ken', + 'country': 'JP', + 'coord': {'lon': 136.770493, 'lat': 36.77145} + }, + { + 'id': 1857578, + 'name': 'Matoba', + 'country': 'JP', + 'coord': {'lon': 133.949997, 'lat': 34.25} + }, + { + 'id': 1299298, + 'name': 'Pya', + 'country': 'MM', + 'coord': {'lon': 95.599998, 'lat': 21.51667} + }, + { + 'id': 3256023, + 'name': 'Kalanac', + 'country': 'BA', + 'coord': {'lon': 18.78389, 'lat': 44.86861} + }, + { + 'id': 2921044, + 'name': 'Federal Republic of Germany', + 'country': 'DE', + 'coord': {'lon': 10.5, 'lat': 51.5} + }, + { + 'id': 2861876, + 'name': 'Land Nordrhein-Westfalen', + 'country': 'DE', + 'coord': {'lon': 7, 'lat': 51.5} + }, + { + 'id': 802899, + 'name': 'Mutaykutan', + 'country': 'RU', + 'coord': {'lon': 47.660641, 'lat': 42.818859} + }, + { + 'id': 523523, + 'name': 'Nalchik', + 'country': 'RU', + 'coord': {'lon': 43.618889, 'lat': 43.498058} + }, + { + 'id': 546448, + 'name': 'Kolganov', + 'country': 'RU', + 'coord': {'lon': 40.066669, 'lat': 44.366669} + }, + { + 'id': 500023, + 'name': 'Rybatskiy', + 'country': 'RU', + 'coord': {'lon': 44.166389, 'lat': 44.799171} + }, + { + 'id': 2207349, + 'name': 'Bellara', + 'country': 'AU', + 'coord': {'lon': 153.149597, 'lat': -27.063919} + }, + { + 'id': 7870412, + 'name': 'Bartlett', + 'country': 'ZA', + 'coord': {'lon': 28.25263, 'lat': -26.17061} + }, + { + 'id': 961935, + 'name': 'Rietfontein', + 'country': 'ZA', + 'coord': {'lon': 29.200001, 'lat': -25.5} + }, + { + 'id': 3371200, + 'name': 'Hardap', + 'country': 'NA', + 'coord': {'lon': 17.25, 'lat': -24.5} + }, + { + 'id': 1016666, + 'name': 'Botswana', + 'country': 'ZA', + 'coord': {'lon': 30.533331, 'lat': -24.33333} + }, + { + 'id': 3858204, + 'name': 'El Destierro', + 'country': 'AR', + 'coord': {'lon': -62.47662, 'lat': -24.1} + }, + { + 'id': 4070245, + 'name': 'Jones Crossroads', + 'country': 'US', + 'coord': {'lon': -85.484657, 'lat': 31.21073} + }, + { + 'id': 4344544, + 'name': 'Vernon Parish', + 'country': 'US', + 'coord': {'lon': -93.183502, 'lat': 31.11685} + }, + { + 'id': 4215307, + 'name': 'Pennick', + 'country': 'US', + 'coord': {'lon': -81.55899, 'lat': 31.313} + }, + { + 'id': 5285039, + 'name': 'Black Bear Spring', + 'country': 'US', + 'coord': {'lon': -110.288139, 'lat': 31.386209} + }, + { + 'id': 4673179, + 'name': 'Bee House', + 'country': 'US', + 'coord': {'lon': -98.081139, 'lat': 31.40266} + }, + { + 'id': 6078447, + 'name': 'Morden', + 'country': 'CA', + 'coord': {'lon': -98.101357, 'lat': 49.191898} + }, + { + 'id': 2201316, + 'name': 'Nasirotu', + 'country': 'FJ', + 'coord': {'lon': 178.25, 'lat': -18.033331} + }, + { + 'id': 1938756, + 'name': 'Sisali', + 'country': 'ID', + 'coord': {'lon': 124.531387, 'lat': -9.19167} + }, + { + 'id': 2009359, + 'name': 'Puntan', + 'country': 'ID', + 'coord': {'lon': 110.553329, 'lat': -7.51944} + }, + { + 'id': 2566086, + 'name': 'Tsiémé-Mandiélé', + 'country': 'CG', + 'coord': {'lon': 15.2875, 'lat': -4.22694} + }, + { + 'id': 154733, + 'name': 'Masama', + 'country': 'TZ', + 'coord': {'lon': 37.183331, 'lat': -3.23333} + }, + { + 'id': 1630349, + 'name': 'Purukcahu', + 'country': 'ID', + 'coord': {'lon': 114.583328, 'lat': -0.58333} + }, + { + 'id': 2224928, + 'name': 'Néméyong II', + 'country': 'CM', + 'coord': {'lon': 13.5, 'lat': 2.91667} + }, + { + 'id': 6716279, + 'name': 'Pondok Genteng', + 'country': 'ID', + 'coord': {'lon': 99.0709, 'lat': 3.2245} + }, + { + 'id': 2384618, + 'name': 'Mbongoté', + 'country': 'CF', + 'coord': {'lon': 18.283331, 'lat': 4.25} + }, + { + 'id': 378867, + 'name': 'Amiling', + 'country': 'SS', + 'coord': {'lon': 32.355831, 'lat': 4.19417} + }, + { + 'id': 2230362, + 'name': 'Kélkoto', + 'country': 'CM', + 'coord': {'lon': 11.16667, 'lat': 4.43333} + }, + { + 'id': 343846, + 'name': 'Angetu', + 'country': 'ET', + 'coord': {'lon': 39.48333, 'lat': 6.33333} + }, + { + 'id': 370366, + 'name': 'Massa', + 'country': 'SD', + 'coord': {'lon': 29.466669, 'lat': 10.98333} + }, + { + 'id': 365618, + 'name': 'Tumko', + 'country': 'SD', + 'coord': {'lon': 24.6, 'lat': 12.01667} + }, + { + 'id': 524894, + 'name': 'Moskva', + 'country': 'RU', + 'coord': {'lon': 37.606667, 'lat': 55.761665} + }, + { + 'id': 1861060, + 'name': 'Japan', + 'country': 'JP', + 'coord': {'lon': 139.753098, 'lat': 35.68536} + }, + { + 'id': 2130037, + 'name': 'Hokkaidō', + 'country': 'JP', + 'coord': {'lon': 141.346603, 'lat': 43.06451} + }, + { + 'id': 6199126, + 'name': 'Sanggrahan', + 'country': 'ID', + 'coord': {'lon': 110.246109, 'lat': -7.46056} + }, + { + 'id': 6388445, + 'name': 'Karangmangle', + 'country': 'ID', + 'coord': {'lon': 109.0075, 'lat': -7.43028} + }, + { + 'id': 494806, + 'name': 'Sheremetyevskiy', + 'country': 'RU', + 'coord': {'lon': 37.491112, 'lat': 55.98} + }, + { + 'id': 467104, + 'name': 'Yershovo', + 'country': 'RU', + 'coord': {'lon': 36.858055, 'lat': 55.771111} + }, + { + 'id': 462352, + 'name': 'Znamenka', + 'country': 'RU', + 'coord': {'lon': 35.981392, 'lat': 52.896671} + }, + { + 'id': 2267057, + 'name': 'Lisbon', + 'country': 'PT', + 'coord': {'lon': -9.13333, 'lat': 38.716671} + }, + { + 'id': 3082707, + 'name': 'Walbrzych', + 'country': 'PL', + 'coord': {'lon': 16.284321, 'lat': 50.771412} + }, + { + 'id': 3091150, + 'name': 'Naklo nad Notecia', + 'country': 'PL', + 'coord': {'lon': 17.60181, 'lat': 53.142139} + }, + { + 'id': 1784658, + 'name': 'Zhengzhou', + 'country': 'CN', + 'coord': {'lon': 113.648613, 'lat': 34.757778} + }, + { + 'id': 7301040, + 'name': 'Tonyrefail', + 'country': 'GB', + 'coord': {'lon': -3.41503, 'lat': 51.580238} + }, + { + 'id': 1348747, + 'name': 'Bankra', + 'country': 'IN', + 'coord': {'lon': 88.298058, 'lat': 22.627501} + }, + { + 'id': 6255148, + 'name': 'Europe', + 'country': '', + 'coord': {'lon': 9.140625, 'lat': 48.69096} + }, + { + 'id': 524925, + 'name': 'Moskovskaya Oblast’', + 'country': 'RU', + 'coord': {'lon': 37.628334, 'lat': 55.75639} + }, + { + 'id': 4047656, + 'name': 'Provo', + 'country': 'US', + 'coord': {'lon': -94.107697, 'lat': 34.037609} + }, + { + 'id': 5493998, + 'name': 'Tejon', + 'country': 'US', + 'coord': {'lon': -105.28611, 'lat': 34.58979} + }, + { + 'id': 1463749, + 'name': 'Guliston', + 'country': 'UZ', + 'coord': {'lon': 65.518929, 'lat': 38.510029} + }, + { + 'id': 749184, + 'name': 'Ciciler', + 'country': 'TR', + 'coord': {'lon': 30.063601, 'lat': 40.442982} + }, + { + 'id': 750594, + 'name': 'Bilmece', + 'country': 'TR', + 'coord': {'lon': 36.150002, 'lat': 41.150002} + }, + { + 'id': 3113208, + 'name': 'Provincia de Pontevedra', + 'country': 'ES', + 'coord': {'lon': -8.5, 'lat': 42.5} + }, + { + 'id': 2653753, + 'name': 'Carmarthenshire', + 'country': 'GB', + 'coord': {'lon': -4.16667, 'lat': 51.833328} + }, + { + 'id': 658226, + 'name': 'Helsinki', + 'country': 'FI', + 'coord': {'lon': 24.93417, 'lat': 60.17556} + }, + { + 'id': 2744819, + 'name': 'Gemeente Wervershoof', + 'country': 'NL', + 'coord': {'lon': 5.13333, 'lat': 52.716671} + }, + { + 'id': 3017680, + 'name': 'Forville', + 'country': 'FR', + 'coord': {'lon': 6.6239, 'lat': 44.913849} + }, + { + 'id': 448961, + 'name': 'Tall ‘Alāwī', + 'country': 'IQ', + 'coord': {'lon': 44.552891, 'lat': 31.59358} + }, + { + 'id': 3007202, + 'name': 'La Portanière', + 'country': 'FR', + 'coord': {'lon': 6.17341, 'lat': 43.248611} + }, + { + 'id': 2650353, + 'name': 'East Portlemouth', + 'country': 'GB', + 'coord': {'lon': -3.75578, 'lat': 50.232159} + }, + { + 'id': 2058430, + 'name': 'Whyalla', + 'country': 'AU', + 'coord': {'lon': 137.583328, 'lat': -33.033329} + }, + { + 'id': 2181258, + 'name': 'Terrace End', + 'country': 'NZ', + 'coord': {'lon': 175.616669, 'lat': -40.349998} + }, + { + 'id': 2130135, + 'name': 'Hashimoto', + 'country': 'JP', + 'coord': {'lon': 140.75, 'lat': 40.816669} + }, + { + 'id': 2110681, + 'name': 'Tsukuba-kenkyūgakuen-toshi', + 'country': 'JP', + 'coord': {'lon': 140.116669, 'lat': 36.083328} + }, + { + 'id': 1862845, + 'name': 'Higashi-asahimachi', + 'country': 'JP', + 'coord': {'lon': 133.066666, 'lat': 35.466671} + }, + { + 'id': 1863250, + 'name': 'Hanabatachō', + 'country': 'JP', + 'coord': {'lon': 130.699997, 'lat': 32.799999} + }, + { + 'id': 1852699, + 'name': 'Senzaki', + 'country': 'JP', + 'coord': {'lon': 131.199997, 'lat': 34.383331} + }, + { + 'id': 1853163, + 'name': 'Sakaki', + 'country': 'JP', + 'coord': {'lon': 138.183334, 'lat': 36.466671} + }, + { + 'id': 1864427, + 'name': 'Daisen', + 'country': 'JP', + 'coord': {'lon': 133.533325, 'lat': 35.383331} + }, + { + 'id': 1861816, + 'name': 'Ikaruga', + 'country': 'JP', + 'coord': {'lon': 134.583328, 'lat': 34.833328} + }, + { + 'id': 1857451, + 'name': 'Matsuzaki', + 'country': 'JP', + 'coord': {'lon': 138.783325, 'lat': 34.75} + }, + { + 'id': 2128894, + 'name': 'Noboribetsu', + 'country': 'JP', + 'coord': {'lon': 141.173065, 'lat': 42.451389} + }, + { + 'id': 3175936, + 'name': 'Grandate', + 'country': 'IT', + 'coord': {'lon': 9.05784, 'lat': 45.775181} + }, + { + 'id': 6539582, + 'name': 'Biella', + 'country': 'IT', + 'coord': {'lon': 8.05002, 'lat': 45.55986} + }, + { + 'id': 6542288, + 'name': 'Soverato', + 'country': 'IT', + 'coord': {'lon': 16.54991, 'lat': 38.684978} + }, + { + 'id': 6540662, + 'name': 'Pinerolo', + 'country': 'IT', + 'coord': {'lon': 7.33312, 'lat': 44.883942} + }, + { + 'id': 3333225, + 'name': 'Dundee City', + 'country': 'GB', + 'coord': {'lon': -2.91667, 'lat': 56.466671} + }, + { + 'id': 7290647, + 'name': 'Nuneaton and Bedworth District', + 'country': 'GB', + 'coord': {'lon': -1.47802, 'lat': 52.500641} + }, + { + 'id': 7291924, + 'name': 'Rhyl', + 'country': 'GB', + 'coord': {'lon': -3.47247, 'lat': 53.31905} + }, + { + 'id': 2649140, + 'name': 'Foulridge', + 'country': 'GB', + 'coord': {'lon': -2.16864, 'lat': 53.87579} + }, + { + 'id': 2647062, + 'name': 'Hermitage', + 'country': 'GB', + 'coord': {'lon': -1.26823, 'lat': 51.455399} + }, + { + 'id': 2648355, + 'name': 'Golcar', + 'country': 'GB', + 'coord': {'lon': -1.8557, 'lat': 53.639919} + }, + { + 'id': 2636001, + 'name': 'Thornbury', + 'country': 'GB', + 'coord': {'lon': -2.55, 'lat': 52.23333} + }, + { + 'id': 510291, + 'name': 'Peterhof', + 'country': 'RU', + 'coord': {'lon': 29.9, 'lat': 59.883331} + }, + { + 'id': 518858, + 'name': 'Grebnevo', + 'country': 'RU', + 'coord': {'lon': 38.072777, 'lat': 55.961945} + }, + { + 'id': 3746183, + 'name': 'Centro Habana', + 'country': 'CU', + 'coord': {'lon': -82.364166, 'lat': 23.13833} + }, + { + 'id': 1014012, + 'name': 'Carolina', + 'country': 'ZA', + 'coord': {'lon': 30.114889, 'lat': -26.069269} + }, + { + 'id': 3579132, + 'name': 'Gustavia', + 'country': 'BL', + 'coord': {'lon': -62.849781, 'lat': 17.896179} + }, + { + 'id': 1790413, + 'name': 'Xianju', + 'country': 'CN', + 'coord': {'lon': 120.73333, 'lat': 28.85} + }, + { + 'id': 1850144, + 'name': 'Tōkyō-to', + 'country': 'JP', + 'coord': {'lon': 139.691711, 'lat': 35.689499} + }, + { + 'id': 5815135, + 'name': 'Washington', + 'country': 'US', + 'coord': {'lon': -120.501472, 'lat': 47.500118} + }, + { + 'id': 5391891, + 'name': 'San Dimas', + 'country': 'US', + 'coord': {'lon': -117.806732, 'lat': 34.106682} + }, + { + 'id': 148251, + 'name': 'Culfa', + 'country': 'AZ', + 'coord': {'lon': 45.630798, 'lat': 38.955799} + }, + { + 'id': 141668, + 'name': 'Bandar Emām Khomeynī', + 'country': 'IR', + 'coord': {'lon': 49.076279, 'lat': 30.429831} + }, + { + 'id': 66108, + 'name': 'Shāhrūd', + 'country': 'IR', + 'coord': {'lon': 55.01667, 'lat': 36.416672} + }, + { + 'id': 2410048, + 'name': 'Bo', + 'country': 'SL', + 'coord': {'lon': -11.73833, 'lat': 7.96472} + }, + { + 'id': 1092342, + 'name': 'Daché', + 'country': 'KM', + 'coord': {'lon': 43.251389, 'lat': -11.7125} + }, + { + 'id': 3719432, + 'name': 'Département de l\'Ouest', + 'country': 'HT', + 'coord': {'lon': -72.291412, 'lat': 18.663811} + }, + { + 'id': 6538016, + 'name': 'Montescudo', + 'country': 'IT', + 'coord': {'lon': 12.54295, 'lat': 43.91946} + }, + { + 'id': 3428577, + 'name': 'San Pedro', + 'country': 'AR', + 'coord': {'lon': -54.108421, 'lat': -26.62207} + }, + { + 'id': 7871309, + 'name': 'Wels(Stadt)', + 'country': 'AT', + 'coord': {'lon': 14.02164, 'lat': 48.16082} + }, + { + 'id': 7839407, + 'name': 'Palmerston', + 'country': 'AU', + 'coord': {'lon': 130.977966, 'lat': -12.4962} + }, + { + 'id': 147059, + 'name': 'Telmankend', + 'country': 'AZ', + 'coord': {'lon': 48.399021, 'lat': 39.87867} + }, + { + 'id': 147425, + 'name': 'Neftcala', + 'country': 'AZ', + 'coord': {'lon': 49.247219, 'lat': 39.374168} + }, + { + 'id': 148340, + 'name': 'Pushkino', + 'country': 'AZ', + 'coord': {'lon': 48.544998, 'lat': 39.458328} + }, + { + 'id': 2784549, + 'name': 'Visé', + 'country': 'BE', + 'coord': {'lon': 5.7019, 'lat': 50.738628} + }, + { + 'id': 2793079, + 'name': 'Lede', + 'country': 'BE', + 'coord': {'lon': 3.94544, 'lat': 50.962582} + }, + { + 'id': 2795101, + 'name': 'Ieper', + 'country': 'BE', + 'coord': {'lon': 2.86733, 'lat': 50.85704} + }, + { + 'id': 2354349, + 'name': 'Titao', + 'country': 'BF', + 'coord': {'lon': -2.06667, 'lat': 13.76667} + }, + { + 'id': 6930703, + 'name': 'Cascades', + 'country': 'BF', + 'coord': {'lon': -4.76292, 'lat': 10.65015} + }, + { + 'id': 3901501, + 'name': 'Villazon', + 'country': 'BO', + 'coord': {'lon': -65.594223, 'lat': -22.08659} + }, + { + 'id': 6050612, + 'name': 'Laval', + 'country': 'CA', + 'coord': {'lon': -73.749184, 'lat': 45.583382} + }, + { + 'id': 203717, + 'name': 'Yangambi', + 'country': 'CD', + 'coord': {'lon': 24.43359, 'lat': 0.81021} + }, + { + 'id': 204283, + 'name': 'Watsa', + 'country': 'CD', + 'coord': {'lon': 29.535509, 'lat': 3.03716} + }, + { + 'id': 204318, + 'name': 'Wamba', + 'country': 'CD', + 'coord': {'lon': 27.994659, 'lat': 2.14838} + }, + { + 'id': 210379, + 'name': 'Lusambo', + 'country': 'CD', + 'coord': {'lon': 23.450001, 'lat': -4.96667} + }, + { + 'id': 210939, + 'name': 'Luebo', + 'country': 'CD', + 'coord': {'lon': 21.41667, 'lat': -5.35} + }, + { + 'id': 211098, + 'name': 'Lubao', + 'country': 'CD', + 'coord': {'lon': 25.75, 'lat': -5.36667} + }, + { + 'id': 214575, + 'name': 'Kampene', + 'country': 'CD', + 'coord': {'lon': 26.66667, 'lat': -3.6} + }, + { + 'id': 215527, + 'name': 'Kabinda', + 'country': 'CD', + 'coord': {'lon': 24.48333, 'lat': -6.13333} + }, + { + 'id': 215605, + 'name': 'Kabare', + 'country': 'CD', + 'coord': {'lon': 28.824169, 'lat': -2.46833} + }, + { + 'id': 217637, + 'name': 'Businga', + 'country': 'CD', + 'coord': {'lon': 20.883329, 'lat': 3.33333} + }, + { + 'id': 2311968, + 'name': 'Nioki', + 'country': 'CD', + 'coord': {'lon': 17.683331, 'lat': -2.71667} + }, + { + 'id': 2312249, + 'name': 'Mushie', + 'country': 'CD', + 'coord': {'lon': 16.9, 'lat': -3.01667} + }, + { + 'id': 2313084, + 'name': 'Mangai', + 'country': 'CD', + 'coord': {'lon': 19.533331, 'lat': -4.05} + }, + { + 'id': 2314300, + 'name': 'Ville de Kinshasa', + 'country': 'CD', + 'coord': {'lon': 15.5, 'lat': -4.5} + }, + { + 'id': 7286409, + 'name': 'Luzern', + 'country': 'CH', + 'coord': {'lon': 8.32518, 'lat': 47.047138} + }, + { + 'id': 6295429, + 'name': 'Fahrweid (südl. Teil)', + 'country': 'CH', + 'coord': {'lon': 8.41367, 'lat': 47.408138} + }, + { + 'id': 7286907, + 'name': 'Riehen', + 'country': 'CH', + 'coord': {'lon': 7.65117, 'lat': 47.579418} + }, + { + 'id': 6291739, + 'name': 'Bärenbohl', + 'country': 'CH', + 'coord': {'lon': 8.51832, 'lat': 47.434929} + }, + { + 'id': 6295642, + 'name': 'Letten', + 'country': 'CH', + 'coord': {'lon': 8.53458, 'lat': 47.32811} + }, + { + 'id': 2280376, + 'name': 'Touba', + 'country': 'CI', + 'coord': {'lon': -7.68333, 'lat': 8.28333} + }, + { + 'id': 2221394, + 'name': 'Tonga', + 'country': 'CM', + 'coord': {'lon': 10.7, 'lat': 4.96667} + }, + { + 'id': 3072342, + 'name': 'Lahovičky', + 'country': 'CZ', + 'coord': {'lon': 14.39698, 'lat': 50.001339} + }, + { + 'id': 3064531, + 'name': 'Svépravice', + 'country': 'CZ', + 'coord': {'lon': 14.6131, 'lat': 50.100712} + }, + { + 'id': 6547426, + 'name': 'Wardenburg', + 'country': 'DE', + 'coord': {'lon': 8.19785, 'lat': 53.062222} + }, + { + 'id': 6553084, + 'name': 'Wachtberg', + 'country': 'DE', + 'coord': {'lon': 7.1259, 'lat': 50.6213} + }, + { + 'id': 2835344, + 'name': 'Schwalmtal', + 'country': 'DE', + 'coord': {'lon': 6.26667, 'lat': 51.216671} + }, + { + 'id': 7602475, + 'name': 'Pfaffenhofen an der Ilm', + 'country': 'DE', + 'coord': {'lon': 11.502, 'lat': 48.528431} + }, + { + 'id': 6553078, + 'name': 'Odenthal', + 'country': 'DE', + 'coord': {'lon': 7.1182, 'lat': 51.034801} + }, + { + 'id': 6553081, + 'name': 'Much', + 'country': 'DE', + 'coord': {'lon': 7.3537, 'lat': 50.874699} + }, + { + 'id': 2915013, + 'name': 'Großstädteln', + 'country': 'DE', + 'coord': {'lon': 12.38333, 'lat': 51.26667} + }, + { + 'id': 6553073, + 'name': 'Lindlar', + 'country': 'DE', + 'coord': {'lon': 7.3665, 'lat': 51.033199} + }, + { + 'id': 6553056, + 'name': 'Kreuzau', + 'country': 'DE', + 'coord': {'lon': 6.4771, 'lat': 50.729401} + }, + { + 'id': 6557629, + 'name': 'Höxter, Stadt', + 'country': 'DE', + 'coord': {'lon': 9.39737, 'lat': 51.796371} + }, + { + 'id': 2820086, + 'name': 'Kreis Unna', + 'country': 'DE', + 'coord': {'lon': 7.7175, 'lat': 51.568611} + }, + { + 'id': 6553128, + 'name': 'Hille', + 'country': 'DE', + 'coord': {'lon': 8.7722, 'lat': 52.330898} + }, + { + 'id': 6556314, + 'name': 'Haar', + 'country': 'DE', + 'coord': {'lon': 11.7333, 'lat': 48.099998} + }, + { + 'id': 2916630, + 'name': 'Grossenhain', + 'country': 'DE', + 'coord': {'lon': 13.55, 'lat': 51.283329} + }, + { + 'id': 6553174, + 'name': 'Ginsheim-Gustavsburg', + 'country': 'DE', + 'coord': {'lon': 8.3425, 'lat': 49.985802} + }, + { + 'id': 6553072, + 'name': 'Engelskirchen', + 'country': 'DE', + 'coord': {'lon': 7.4, 'lat': 50.983299} + }, + { + 'id': 6555618, + 'name': 'Eggenstein-Leopoldshafen', + 'country': 'DE', + 'coord': {'lon': 8.39056, 'lat': 49.095299} + }, + { + 'id': 6553040, + 'name': 'Brüggen', + 'country': 'DE', + 'coord': {'lon': 6.1886, 'lat': 51.2379} + }, + { + 'id': 2957818, + 'name': 'Bönen', + 'country': 'DE', + 'coord': {'lon': 7.76667, 'lat': 51.583328} + }, + { + 'id': 3221125, + 'name': 'Kreisfreie Stadt Bielefeld', + 'country': 'DE', + 'coord': {'lon': 8.55861, 'lat': 52.017502} + }, + { + 'id': 2949188, + 'name': 'Bielefeld', + 'country': 'DE', + 'coord': {'lon': 8.5, 'lat': 52} + }, + { + 'id': 6555717, + 'name': 'Baiersbronn', + 'country': 'DE', + 'coord': {'lon': 8.3495, 'lat': 48.515499} + }, + { + 'id': 6552854, + 'name': 'Bad Zwischenahn', + 'country': 'DE', + 'coord': {'lon': 8.04142, 'lat': 53.1717} + }, + { + 'id': 6557561, + 'name': 'Bad Honnef, Stadt', + 'country': 'DE', + 'coord': {'lon': 7.26114, 'lat': 50.647579} + }, + { + 'id': 6553094, + 'name': 'Ascheberg', + 'country': 'DE', + 'coord': {'lon': 7.61667, 'lat': 51.783298} + }, + { + 'id': 2856307, + 'name': 'Ostfildern', + 'country': 'DE', + 'coord': {'lon': 9.25143, 'lat': 48.7267} + }, + { + 'id': 7602483, + 'name': 'Spremberg, Stadt', + 'country': 'DE', + 'coord': {'lon': 14.37355, 'lat': 51.56971} + }, + { + 'id': 6543938, + 'name': 'Høje-Taastrup Kommune', + 'country': 'DK', + 'coord': {'lon': 12.24854, 'lat': 55.656429} + }, + { + 'id': 2616011, + 'name': 'Nyborg Kommune', + 'country': 'DK', + 'coord': {'lon': 10.75, 'lat': 55.333328} + }, + { + 'id': 2618525, + 'name': 'Kolding Kommune', + 'country': 'DK', + 'coord': {'lon': 9.46667, 'lat': 55.533329} + }, + { + 'id': 3495858, + 'name': 'Neiba', + 'country': 'DO', + 'coord': {'lon': -71.416672, 'lat': 18.5} + }, + { + 'id': 3496332, + 'name': 'Moca', + 'country': 'DO', + 'coord': {'lon': -70.5, 'lat': 19.5} + }, + { + 'id': 2476412, + 'name': 'el hed', + 'country': 'DZ', + 'coord': {'lon': 4.77361, 'lat': 36.650002} + }, + { + 'id': 2479183, + 'name': 'Souma', + 'country': 'DZ', + 'coord': {'lon': 2.90528, 'lat': 36.51833} + }, + { + 'id': 2482939, + 'name': 'Rouached', + 'country': 'DZ', + 'coord': {'lon': 6.04267, 'lat': 36.457741} + }, + { + 'id': 2483761, + 'name': 'Reggane', + 'country': 'DZ', + 'coord': {'lon': 0.1714, 'lat': 26.715759} + }, + { + 'id': 2487620, + 'name': 'Metlili Chaamba', + 'country': 'DZ', + 'coord': {'lon': 3.63333, 'lat': 32.26667} + }, + { + 'id': 2498775, + 'name': 'El Abiodh Sidi Cheikh', + 'country': 'DZ', + 'coord': {'lon': 0.54839, 'lat': 32.893002} + }, + { + 'id': 6361023, + 'name': 'Osuna', + 'country': 'ES', + 'coord': {'lon': -5.11371, 'lat': 37.22229} + }, + { + 'id': 6361010, + 'name': 'Lora del Río', + 'country': 'ES', + 'coord': {'lon': -5.48845, 'lat': 37.660149} + }, + { + 'id': 6359459, + 'name': 'Fuengirola', + 'country': 'ES', + 'coord': {'lon': -4.61206, 'lat': 36.551491} + }, + { + 'id': 6358465, + 'name': 'Bailén', + 'country': 'ES', + 'coord': {'lon': -3.78418, 'lat': 38.080231} + }, + { + 'id': 6362958, + 'name': 'Utebo', + 'country': 'ES', + 'coord': {'lon': -1.00454, 'lat': 41.715591} + }, + { + 'id': 6356273, + 'name': 'Barberà del Vallès', + 'country': 'ES', + 'coord': {'lon': 2.13201, 'lat': 41.517361} + }, + { + 'id': 6359334, + 'name': 'Pinto', + 'country': 'ES', + 'coord': {'lon': -3.68321, 'lat': 40.258942} + }, + { + 'id': 6533993, + 'name': 'Pineda de Mar', + 'country': 'ES', + 'coord': {'lon': 2.66524, 'lat': 41.636478} + }, + { + 'id': 6534092, + 'name': 'Palamós', + 'country': 'ES', + 'coord': {'lon': 3.14432, 'lat': 41.860611} + }, + { + 'id': 6359320, + 'name': 'Navalcarnero', + 'country': 'ES', + 'coord': {'lon': -3.99743, 'lat': 40.282101} + }, + { + 'id': 6359308, + 'name': 'Mejorada del Campo', + 'country': 'ES', + 'coord': {'lon': -3.47564, 'lat': 40.402061} + }, + { + 'id': 6356141, + 'name': 'Manlleu', + 'country': 'ES', + 'coord': {'lon': 2.28035, 'lat': 41.999298} + }, + { + 'id': 6359300, + 'name': 'Leganés', + 'country': 'ES', + 'coord': {'lon': -3.77931, 'lat': 40.327358} + }, + { + 'id': 6362203, + 'name': 'Laguna de Duero', + 'country': 'ES', + 'coord': {'lon': -4.72002, 'lat': 41.56963} + }, + { + 'id': 6357300, + 'name': 'Coruña (A)', + 'country': 'ES', + 'coord': {'lon': -8.4188, 'lat': 43.371262} + }, + { + 'id': 6361741, + 'name': 'Illescas', + 'country': 'ES', + 'coord': {'lon': -3.85713, 'lat': 40.135811} + }, + { + 'id': 6356206, + 'name': 'la Roca del Vallès', + 'country': 'ES', + 'coord': {'lon': 2.32741, 'lat': 41.601181} + }, + { + 'id': 6362379, + 'name': 'Ermua', + 'country': 'ES', + 'coord': {'lon': -2.50305, 'lat': 43.18774} + }, + { + 'id': 6358120, + 'name': 'Eibar', + 'country': 'ES', + 'coord': {'lon': -2.46165, 'lat': 43.19978} + }, + { + 'id': 6362372, + 'name': 'Durango', + 'country': 'ES', + 'coord': {'lon': -2.6498, 'lat': 43.16481} + }, + { + 'id': 6359273, + 'name': 'Collado Villalba', + 'country': 'ES', + 'coord': {'lon': -3.99052, 'lat': 40.642971} + }, + { + 'id': 6359266, + 'name': 'Ciempozuelos', + 'country': 'ES', + 'coord': {'lon': -3.6001, 'lat': 40.153599} + }, + { + 'id': 6356068, + 'name': 'Caldes de Montbui', + 'country': 'ES', + 'coord': {'lon': 2.14934, 'lat': 41.65057} + }, + { + 'id': 6359026, + 'name': 'Calahorra', + 'country': 'ES', + 'coord': {'lon': -1.95262, 'lat': 42.307869} + }, + { + 'id': 6356985, + 'name': 'Benicasim/Benicàssim', + 'country': 'ES', + 'coord': {'lon': 0.06334, 'lat': 40.052799} + }, + { + 'id': 6360635, + 'name': 'Realejos (Los)', + 'country': 'ES', + 'coord': {'lon': -16.59104, 'lat': 28.381981} + }, + { + 'id': 3128528, + 'name': 'Basauri', + 'country': 'ES', + 'coord': {'lon': -2.88271, 'lat': 43.234821} + }, + { + 'id': 6357735, + 'name': 'Lobras', + 'country': 'ES', + 'coord': {'lon': -3.20859, 'lat': 36.90868} + }, + { + 'id': 329586, + 'name': 'Robit', + 'country': 'ET', + 'coord': {'lon': 39.633331, 'lat': 12.01667} + }, + { + 'id': 331180, + 'name': 'Mekele', + 'country': 'ET', + 'coord': {'lon': 39.475281, 'lat': 13.49667} + }, + { + 'id': 332880, + 'name': 'Kolito', + 'country': 'ET', + 'coord': {'lon': 38.083328, 'lat': 7.31667} + }, + { + 'id': 2204582, + 'name': 'Lambasa', + 'country': 'FJ', + 'coord': {'lon': 179.383331, 'lat': -16.41667} + }, + { + 'id': 7626930, + 'name': 'Sokehs Municipality', + 'country': 'FM', + 'coord': {'lon': 158.1427, 'lat': 6.93273} + }, + { + 'id': 6441676, + 'name': 'Wittenheim', + 'country': 'FR', + 'coord': {'lon': 7.33333, 'lat': 47.816669} + }, + { + 'id': 6438569, + 'name': 'Wattrelos', + 'country': 'FR', + 'coord': {'lon': 3.21667, 'lat': 50.700001} + }, + { + 'id': 6454050, + 'name': 'Vitré', + 'country': 'FR', + 'coord': {'lon': -1.2, 'lat': 48.133331} + }, + { + 'id': 6446231, + 'name': 'Viry-Châtillon', + 'country': 'FR', + 'coord': {'lon': 2.38333, 'lat': 48.666672} + }, + { + 'id': 6452039, + 'name': 'Villeneuve-le-Roi', + 'country': 'FR', + 'coord': {'lon': 2.41667, 'lat': 48.73333} + }, + { + 'id': 6453748, + 'name': 'Vierzon', + 'country': 'FR', + 'coord': {'lon': 2.08333, 'lat': 47.216671} + }, + { + 'id': 6446218, + 'name': 'Verrières-le-Buisson', + 'country': 'FR', + 'coord': {'lon': 2.26667, 'lat': 48.75} + }, + { + 'id': 6457368, + 'name': 'Arrondissement d\'Antony', + 'country': 'FR', + 'coord': {'lon': 2.3006, 'lat': 48.7617} + }, + { + 'id': 6425695, + 'name': 'Vallauris', + 'country': 'FR', + 'coord': {'lon': 7.05, 'lat': 43.583328} + }, + { + 'id': 6438526, + 'name': 'Tourcoing', + 'country': 'FR', + 'coord': {'lon': 3.15, 'lat': 50.716671} + }, + { + 'id': 6446342, + 'name': 'Taverny', + 'country': 'FR', + 'coord': {'lon': 2.21667, 'lat': 49.033329} + }, + { + 'id': 6446340, + 'name': 'Soisy-sous-Montmorency', + 'country': 'FR', + 'coord': {'lon': 2.3, 'lat': 48.98333} + }, + { + 'id': 6438498, + 'name': 'Sin-le-Noble', + 'country': 'FR', + 'coord': {'lon': 3.11667, 'lat': 50.366669} + }, + { + 'id': 6451981, + 'name': 'Sèvres', + 'country': 'FR', + 'coord': {'lon': 2.2, 'lat': 48.816669} + }, + { + 'id': 6427088, + 'name': 'Salon-de-Provence', + 'country': 'FR', + 'coord': {'lon': 5.1, 'lat': 43.633331} + }, + { + 'id': 6455342, + 'name': 'Saint-Ouen', + 'country': 'FR', + 'coord': {'lon': 2.33333, 'lat': 48.900002} + }, + { + 'id': 6441760, + 'name': 'Saint-Fons', + 'country': 'FR', + 'coord': {'lon': 4.86667, 'lat': 45.700001} + }, + { + 'id': 6454369, + 'name': 'Saint-Avold', + 'country': 'FR', + 'coord': {'lon': 6.7, 'lat': 49.099998} + }, + { + 'id': 6454153, + 'name': 'Rezé', + 'country': 'FR', + 'coord': {'lon': -1.56667, 'lat': 47.200001} + }, + { + 'id': 6454341, + 'name': 'Pontivy', + 'country': 'FR', + 'coord': {'lon': -2.98333, 'lat': 48.066669} + }, + { + 'id': 6454014, + 'name': 'Pessac', + 'country': 'FR', + 'coord': {'lon': -0.61667, 'lat': 44.799999} + }, + { + 'id': 6446184, + 'name': 'Palaiseau', + 'country': 'FR', + 'coord': {'lon': 2.25, 'lat': 48.716671} + }, + { + 'id': 6443784, + 'name': 'Ozoir-la-Ferrière', + 'country': 'FR', + 'coord': {'lon': 2.66667, 'lat': 48.76667} + }, + { + 'id': 6441724, + 'name': 'Oullins', + 'country': 'FR', + 'coord': {'lon': 4.8, 'lat': 45.716671} + }, + { + 'id': 6446721, + 'name': 'Mougins', + 'country': 'FR', + 'coord': {'lon': 7, 'lat': 43.599998} + }, + { + 'id': 6446177, + 'name': 'Morsang-sur-Orge', + 'country': 'FR', + 'coord': {'lon': 2.35, 'lat': 48.666672} + }, + { + 'id': 6430140, + 'name': 'Montélimar', + 'country': 'FR', + 'coord': {'lon': 4.75, 'lat': 44.566669} + }, + { + 'id': 6453858, + 'name': 'Montbéliard', + 'country': 'FR', + 'coord': {'lon': 6.8, 'lat': 47.51667} + }, + { + 'id': 6452024, + 'name': 'Maisons-Alfort', + 'country': 'FR', + 'coord': {'lon': 2.43333, 'lat': 48.799999} + }, + { + 'id': 6430468, + 'name': 'Louviers', + 'country': 'FR', + 'coord': {'lon': 1.16667, 'lat': 49.216671} + }, + { + 'id': 6452023, + 'name': 'Limeil-Brévannes', + 'country': 'FR', + 'coord': {'lon': 2.4893, 'lat': 48.7467} + }, + { + 'id': 6457185, + 'name': 'Les Pavillons-sous-Bois', + 'country': 'FR', + 'coord': {'lon': 2.51667, 'lat': 48.900002} + }, + { + 'id': 6432528, + 'name': 'Lattes', + 'country': 'FR', + 'coord': {'lon': 3.9, 'lat': 43.566669} + }, + { + 'id': 6446146, + 'name': 'Grigny', + 'country': 'FR', + 'coord': {'lon': 2.39382, 'lat': 48.653931} + }, + { + 'id': 6446274, + 'name': 'Goussainville', + 'country': 'FR', + 'coord': {'lon': 2.474, 'lat': 49.032001} + }, + { + 'id': 6454157, + 'name': 'Gien', + 'country': 'FR', + 'coord': {'lon': 2.6297, 'lat': 47.689201} + }, + { + 'id': 6451993, + 'name': 'Gagny', + 'country': 'FR', + 'coord': {'lon': 2.53333, 'lat': 48.883331} + }, + { + 'id': 6455107, + 'name': 'Firminy', + 'country': 'FR', + 'coord': {'lon': 4.3, 'lat': 45.383331} + }, + { + 'id': 6433192, + 'name': 'Échirolles', + 'country': 'FR', + 'coord': {'lon': 5.71667, 'lat': 45.133331} + }, + { + 'id': 6441821, + 'name': 'Décines-Charpieu', + 'country': 'FR', + 'coord': {'lon': 4.9598, 'lat': 45.7686} + }, + { + 'id': 6455404, + 'name': 'Dammarie-les-Lys', + 'country': 'FR', + 'coord': {'lon': 2.65, 'lat': 48.51667} + }, + { + 'id': 6455339, + 'name': 'Colombes', + 'country': 'FR', + 'coord': {'lon': 2.25, 'lat': 48.916672} + }, + { + 'id': 6453697, + 'name': 'Cognac', + 'country': 'FR', + 'coord': {'lon': -0.33333, 'lat': 45.700001} + }, + { + 'id': 6428545, + 'name': 'Chenôve', + 'country': 'FR', + 'coord': {'lon': 5, 'lat': 47.283329} + }, + { + 'id': 6443604, + 'name': 'Chelles', + 'country': 'FR', + 'coord': {'lon': 2.6, 'lat': 48.883331} + }, + { + 'id': 6618272, + 'name': 'Cesson-Sévigné', + 'country': 'FR', + 'coord': {'lon': -1.603, 'lat': 48.121201} + }, + { + 'id': 3028097, + 'name': 'Cayenne', + 'country': 'FR', + 'coord': {'lon': 1.62803, 'lat': 49.558578} + }, + { + 'id': 6439436, + 'name': 'Carvin', + 'country': 'FR', + 'coord': {'lon': 2.96667, 'lat': 50.48333} + }, + { + 'id': 6452010, + 'name': 'Bonneuil-sur-Marne', + 'country': 'FR', + 'coord': {'lon': 2.48333, 'lat': 48.76667} + }, + { + 'id': 6455331, + 'name': 'Belfort', + 'country': 'FR', + 'coord': {'lon': 6.86667, 'lat': 47.633331} + }, + { + 'id': 6447202, + 'name': 'Bayeux', + 'country': 'FR', + 'coord': {'lon': -0.703, 'lat': 49.278599} + }, + { + 'id': 6613166, + 'name': 'Bagnolet', + 'country': 'FR', + 'coord': {'lon': 2.41667, 'lat': 48.866669} + }, + { + 'id': 6450845, + 'name': 'Autun', + 'country': 'FR', + 'coord': {'lon': 4.3, 'lat': 46.950001} + }, + { + 'id': 6448311, + 'name': 'Auch', + 'country': 'FR', + 'coord': {'lon': 0.58333, 'lat': 43.650002} + }, + { + 'id': 6451006, + 'name': 'Annecy-le-Vieux', + 'country': 'FR', + 'coord': {'lon': 6.15, 'lat': 45.916672} + }, + { + 'id': 6452610, + 'name': 'Alfortville', + 'country': 'FR', + 'coord': {'lon': 2.41667, 'lat': 48.799999} + }, + { + 'id': 6455394, + 'name': 'Les Ulis', + 'country': 'FR', + 'coord': {'lon': 2.16932, 'lat': 48.68174} + }, + { + 'id': 7300065, + 'name': 'Yate', + 'country': 'GB', + 'coord': {'lon': -2.40944, 'lat': 51.54805} + }, + { + 'id': 7292818, + 'name': 'Caia Park', + 'country': 'GB', + 'coord': {'lon': -2.97767, 'lat': 53.045219} + }, + { + 'id': 7290657, + 'name': 'Worcester District', + 'country': 'GB', + 'coord': {'lon': -2.20886, 'lat': 52.196121} + }, + { + 'id': 3333222, + 'name': 'Borough of Wolverhampton', + 'country': 'GB', + 'coord': {'lon': -2.11667, 'lat': 52.583328} + }, + { + 'id': 7299965, + 'name': 'Winsford', + 'country': 'GB', + 'coord': {'lon': -2.52331, 'lat': 53.19191} + }, + { + 'id': 2634551, + 'name': 'Welwyn Hatfield', + 'country': 'GB', + 'coord': {'lon': -0.21667, 'lat': 51.75} + }, + { + 'id': 3333211, + 'name': 'Borough of Trafford', + 'country': 'GB', + 'coord': {'lon': -2.33333, 'lat': 53.416672} + }, + { + 'id': 7290632, + 'name': 'Tamworth District', + 'country': 'GB', + 'coord': {'lon': -1.6829, 'lat': 52.62273} + }, + { + 'id': 7291961, + 'name': 'Wroughton', + 'country': 'GB', + 'coord': {'lon': -1.8056, 'lat': 51.517849} + }, + { + 'id': 7290571, + 'name': 'Dartford District', + 'country': 'GB', + 'coord': {'lon': 0.24851, 'lat': 51.43388} + }, + { + 'id': 7290673, + 'name': 'South Derbyshire District', + 'country': 'GB', + 'coord': {'lon': -1.53296, 'lat': 52.821999} + }, + { + 'id': 3333208, + 'name': 'Borough of Tameside', + 'country': 'GB', + 'coord': {'lon': -2.08333, 'lat': 53.5} + }, + { + 'id': 7291795, + 'name': 'Mossley', + 'country': 'GB', + 'coord': {'lon': -2.02418, 'lat': 53.516338} + }, + { + 'id': 7294483, + 'name': 'Seaham', + 'country': 'GB', + 'coord': {'lon': -1.34838, 'lat': 54.8391} + }, + { + 'id': 7295275, + 'name': 'Sandown', + 'country': 'GB', + 'coord': {'lon': -1.14195, 'lat': 50.661251} + }, + { + 'id': 7297739, + 'name': 'Ryton', + 'country': 'GB', + 'coord': {'lon': -2.35315, 'lat': 52.624569} + }, + { + 'id': 7290656, + 'name': 'Redditch District', + 'country': 'GB', + 'coord': {'lon': -1.94565, 'lat': 52.279331} + }, + { + 'id': 7294048, + 'name': 'Prestatyn', + 'country': 'GB', + 'coord': {'lon': -3.40514, 'lat': 53.334641} + }, + { + 'id': 7294693, + 'name': 'Peterlee', + 'country': 'GB', + 'coord': {'lon': -1.32905, 'lat': 54.758461} + }, + { + 'id': 7301708, + 'name': 'Penarth', + 'country': 'GB', + 'coord': {'lon': -3.18138, 'lat': 51.43095} + }, + { + 'id': 7292284, + 'name': 'Oswestry', + 'country': 'GB', + 'coord': {'lon': -3.05832, 'lat': 52.857101} + }, + { + 'id': 7294581, + 'name': 'Northwich', + 'country': 'GB', + 'coord': {'lon': -2.51575, 'lat': 53.255798} + }, + { + 'id': 2657122, + 'name': 'Ards District', + 'country': 'GB', + 'coord': {'lon': -5.58333, 'lat': 54.5} + }, + { + 'id': 2641519, + 'name': 'Newtownards', + 'country': 'GB', + 'coord': {'lon': -5.69092, 'lat': 54.592361} + }, + { + 'id': 7300025, + 'name': 'Newquay', + 'country': 'GB', + 'coord': {'lon': -5.07426, 'lat': 50.424091} + }, + { + 'id': 7298888, + 'name': 'Nailsea', + 'country': 'GB', + 'coord': {'lon': -2.77756, 'lat': 51.424} + }, + { + 'id': 7293862, + 'name': 'Morley', + 'country': 'GB', + 'coord': {'lon': -1.6034, 'lat': 53.742901} + }, + { + 'id': 7293814, + 'name': 'Mirfield', + 'country': 'GB', + 'coord': {'lon': -1.69404, 'lat': 53.673901} + }, + { + 'id': 7291605, + 'name': 'Maesteg', + 'country': 'GB', + 'coord': {'lon': -3.64713, 'lat': 51.61528} + }, + { + 'id': 7296039, + 'name': 'Sutton', + 'country': 'GB', + 'coord': {'lon': -2.0931, 'lat': 53.227161} + }, + { + 'id': 3333218, + 'name': 'City of Westminster', + 'country': 'GB', + 'coord': {'lon': -0.16667, 'lat': 51.5} + }, + { + 'id': 7295996, + 'name': 'Sefton', + 'country': 'GB', + 'coord': {'lon': -2.97287, 'lat': 53.50441} + }, + { + 'id': 3333227, + 'name': 'East Dunbartonshire', + 'country': 'GB', + 'coord': {'lon': -4.2, 'lat': 55.933331} + }, + { + 'id': 3333226, + 'name': 'East Ayrshire', + 'country': 'GB', + 'coord': {'lon': -4.25, 'lat': 55.5} + }, + { + 'id': 7296076, + 'name': 'Keynsham', + 'country': 'GB', + 'coord': {'lon': -2.49775, 'lat': 51.41251} + }, + { + 'id': 7301693, + 'name': 'Kempston', + 'country': 'GB', + 'coord': {'lon': -0.49955, 'lat': 52.116791} + }, + { + 'id': 7299757, + 'name': 'Horwich', + 'country': 'GB', + 'coord': {'lon': -2.52379, 'lat': 53.603069} + }, + { + 'id': 7290564, + 'name': 'Dacorum District', + 'country': 'GB', + 'coord': {'lon': -0.57377, 'lat': 51.768509} + }, + { + 'id': 7290687, + 'name': 'Hastings District', + 'country': 'GB', + 'coord': {'lon': 0.58145, 'lat': 50.867279} + }, + { + 'id': 7291323, + 'name': 'Guisborough', + 'country': 'GB', + 'coord': {'lon': -1.07738, 'lat': 54.535629} + }, + { + 'id': 7290595, + 'name': 'Great Yarmouth District', + 'country': 'GB', + 'coord': {'lon': 1.6469, 'lat': 52.633961} + }, + { + 'id': 7290630, + 'name': 'South Staffordshire District', + 'country': 'GB', + 'coord': {'lon': -2.15319, 'lat': 52.604481} + }, + { + 'id': 7296623, + 'name': 'Goole', + 'country': 'GB', + 'coord': {'lon': -0.87588, 'lat': 53.70216} + }, + { + 'id': 7290556, + 'name': 'Fareham District', + 'country': 'GB', + 'coord': {'lon': -1.21114, 'lat': 50.8535} + }, + { + 'id': 7290639, + 'name': 'Epsom and Ewell District', + 'country': 'GB', + 'coord': {'lon': -0.26017, 'lat': 51.335732} + }, + { + 'id': 7290641, + 'name': 'Runnymede District', + 'country': 'GB', + 'coord': {'lon': -0.53722, 'lat': 51.394421} + }, + { + 'id': 7300545, + 'name': 'Ebbw Vale', + 'country': 'GB', + 'coord': {'lon': -3.20482, 'lat': 51.77298} + }, + { + 'id': 7290615, + 'name': 'Broxtowe District', + 'country': 'GB', + 'coord': {'lon': -1.25781, 'lat': 52.973049} + }, + { + 'id': 7296192, + 'name': 'Dunstable', + 'country': 'GB', + 'coord': {'lon': -0.5173, 'lat': 51.884651} + }, + { + 'id': 3333142, + 'name': 'City of Derby', + 'country': 'GB', + 'coord': {'lon': -1.47217, 'lat': 52.9207} + }, + { + 'id': 7300542, + 'name': 'Eccleshill', + 'country': 'GB', + 'coord': {'lon': -2.4517, 'lat': 53.706779} + }, + { + 'id': 7291971, + 'name': 'Cwmbran Central', + 'country': 'GB', + 'coord': {'lon': -3.02699, 'lat': 51.641171} + }, + { + 'id': 7300082, + 'name': 'Healeyfield', + 'country': 'GB', + 'coord': {'lon': -1.8608, 'lat': 54.830681} + }, + { + 'id': 7290582, + 'name': 'Ribble Valley District', + 'country': 'GB', + 'coord': {'lon': -2.41624, 'lat': 53.902439} + }, + { + 'id': 7299112, + 'name': 'Sodbury', + 'country': 'GB', + 'coord': {'lon': -2.35653, 'lat': 51.541489} + }, + { + 'id': 7296198, + 'name': 'Brymbo', + 'country': 'GB', + 'coord': {'lon': -3.08351, 'lat': 53.074551} + }, + { + 'id': 7296060, + 'name': 'Brixham', + 'country': 'GB', + 'coord': {'lon': -3.51133, 'lat': 50.390831} + }, + { + 'id': 7296000, + 'name': 'Bracknell', + 'country': 'GB', + 'coord': {'lon': -0.75918, 'lat': 51.406029} + }, + { + 'id': 7291483, + 'name': 'Blyth', + 'country': 'GB', + 'coord': {'lon': -1.53835, 'lat': 55.117748} + }, + { + 'id': 7299866, + 'name': 'Biggleswade', + 'country': 'GB', + 'coord': {'lon': -0.24536, 'lat': 52.078602} + }, + { + 'id': 7298694, + 'name': 'Berkhamsted', + 'country': 'GB', + 'coord': {'lon': -0.5578, 'lat': 51.755138} + }, + { + 'id': 7296167, + 'name': 'Bathampton', + 'country': 'GB', + 'coord': {'lon': -2.32627, 'lat': 51.3923} + }, + { + 'id': 2641376, + 'name': 'North Down District', + 'country': 'GB', + 'coord': {'lon': -5.66667, 'lat': 54.666672} + }, + { + 'id': 7298620, + 'name': 'Bangor', + 'country': 'GB', + 'coord': {'lon': -4.13579, 'lat': 53.222301} + }, + { + 'id': 2656408, + 'name': 'Banbridge District', + 'country': 'GB', + 'coord': {'lon': -6.16667, 'lat': 54.333328} + }, + { + 'id': 7292321, + 'name': 'Aberystwyth', + 'country': 'GB', + 'coord': {'lon': -4.07708, 'lat': 52.41227} + }, + { + 'id': 6690583, + 'name': 'Chalk Farm', + 'country': 'GB', + 'coord': {'lon': -0.14987, 'lat': 51.543129} + }, + { + 'id': 7290681, + 'name': 'East Dorset District', + 'country': 'GB', + 'coord': {'lon': -1.976, 'lat': 50.866901} + }, + { + 'id': 612366, + 'name': 'Poti', + 'country': 'GE', + 'coord': {'lon': 41.67197, 'lat': 42.14616} + }, + { + 'id': 2294938, + 'name': 'Tafo', + 'country': 'GH', + 'coord': {'lon': -1.61275, 'lat': 6.73453} + }, + { + 'id': 2295385, + 'name': 'Shama Junction', + 'country': 'GH', + 'coord': {'lon': -1.63011, 'lat': 5.00872} + }, + { + 'id': 2295672, + 'name': 'Saltpond', + 'country': 'GH', + 'coord': {'lon': -1.06058, 'lat': 5.20913} + }, + { + 'id': 2301400, + 'name': 'Dunkwa', + 'country': 'GH', + 'coord': {'lon': -1.77995, 'lat': 5.96562} + }, + { + 'id': 2416443, + 'name': 'Pita', + 'country': 'GN', + 'coord': {'lon': -12.4, 'lat': 11.08333} + }, + { + 'id': 6690393, + 'name': 'Sainte-Anne', + 'country': 'GP', + 'coord': {'lon': -61.366669, 'lat': 16.23333} + }, + { + 'id': 6690399, + 'name': 'Pointe-à-Pitre', + 'country': 'GP', + 'coord': {'lon': -61.51667, 'lat': 16.23333} + }, + { + 'id': 6690387, + 'name': 'Les Abymes', + 'country': 'GP', + 'coord': {'lon': -61.5, 'lat': 16.26667} + }, + { + 'id': 6690413, + 'name': 'Le Moule', + 'country': 'GP', + 'coord': {'lon': -61.333328, 'lat': 16.33333} + }, + { + 'id': 6690408, + 'name': 'Capesterre-Belle-Eau', + 'country': 'GP', + 'coord': {'lon': -61.549999, 'lat': 16.049999} + }, + { + 'id': 8133766, + 'name': 'Dimos Salamis', + 'country': 'GR', + 'coord': {'lon': 23.47966, 'lat': 37.938259} + }, + { + 'id': 8133808, + 'name': 'Dimos Fyli', + 'country': 'GR', + 'coord': {'lon': 23.668631, 'lat': 38.12466} + }, + { + 'id': 3426466, + 'name': 'Grytviken', + 'country': 'GS', + 'coord': {'lon': -36.509201, 'lat': -54.281109} + }, + { + 'id': 3589799, + 'name': 'Municipio de San Marcos', + 'country': 'GT', + 'coord': {'lon': -91.800003, 'lat': 14.96667} + }, + { + 'id': 3595722, + 'name': 'Municipio de Flores', + 'country': 'GT', + 'coord': {'lon': -89.897087, 'lat': 16.923809} + }, + { + 'id': 3600456, + 'name': 'Departamento de Valle', + 'country': 'HN', + 'coord': {'lon': -87.583328, 'lat': 13.58333} + }, + { + 'id': 3716661, + 'name': 'Thor', + 'country': 'HT', + 'coord': {'lon': -72.401382, 'lat': 18.536461} + }, + { + 'id': 3740016, + 'name': 'Ti Port-de-Paix', + 'country': 'HT', + 'coord': {'lon': -72.833328, 'lat': 19.933331} + }, + { + 'id': 3053876, + 'name': 'Csukásitanyák', + 'country': 'HU', + 'coord': {'lon': 19.316669, 'lat': 47.5} + }, + { + 'id': 1213547, + 'name': 'Tanjungbalai', + 'country': 'ID', + 'coord': {'lon': 99.800003, 'lat': 2.96667} + }, + { + 'id': 1214055, + 'name': 'Reuleuet', + 'country': 'ID', + 'coord': {'lon': 96.283333, 'lat': 5.21667} + }, + { + 'id': 294622, + 'name': 'Judieda Makr', + 'country': 'IL', + 'coord': {'lon': 35.154999, 'lat': 32.92556} + }, + { + 'id': 1252738, + 'name': 'Yeola', + 'country': 'IN', + 'coord': {'lon': 74.48333, 'lat': 20.033331} + }, + { + 'id': 1252744, + 'name': 'Yellapur', + 'country': 'IN', + 'coord': {'lon': 74.716667, 'lat': 14.96667} + }, + { + 'id': 1252773, + 'name': 'Yaval', + 'country': 'IN', + 'coord': {'lon': 75.699997, 'lat': 21.16667} + }, + { + 'id': 6540553, + 'name': 'Ventimiglia', + 'country': 'IT', + 'coord': {'lon': 7.60264, 'lat': 43.793522} + }, + { + 'id': 6542009, + 'name': 'Savona', + 'country': 'IT', + 'coord': {'lon': 8.47375, 'lat': 44.30814} + }, + { + 'id': 6537557, + 'name': 'Ruvo di Puglia', + 'country': 'IT', + 'coord': {'lon': 16.48778, 'lat': 41.113628} + }, + { + 'id': 6539485, + 'name': 'Pioltello', + 'country': 'IT', + 'coord': {'lon': 9.32435, 'lat': 45.497971} + }, + { + 'id': 6536957, + 'name': 'Palestrina', + 'country': 'IT', + 'coord': {'lon': 12.88899, 'lat': 41.835522} + }, + { + 'id': 6537567, + 'name': 'Palagiano', + 'country': 'IT', + 'coord': {'lon': 17.037399, 'lat': 40.57822} + }, + { + 'id': 6538821, + 'name': 'Pagani', + 'country': 'IT', + 'coord': {'lon': 14.61334, 'lat': 40.751511} + }, + { + 'id': 6541936, + 'name': 'Orta Nova', + 'country': 'IT', + 'coord': {'lon': 15.71066, 'lat': 41.329929} + }, + { + 'id': 6540026, + 'name': 'Oria', + 'country': 'IT', + 'coord': {'lon': 17.64131, 'lat': 40.49733} + }, + { + 'id': 6537554, + 'name': 'Noicattaro', + 'country': 'IT', + 'coord': {'lon': 16.98959, 'lat': 41.033829} + }, + { + 'id': 6542044, + 'name': 'Nettuno', + 'country': 'IT', + 'coord': {'lon': 12.67899, 'lat': 41.482609} + }, + { + 'id': 6541509, + 'name': 'Negrar', + 'country': 'IT', + 'coord': {'lon': 10.93798, 'lat': 45.52879} + }, + { + 'id': 6540220, + 'name': 'Mira', + 'country': 'IT', + 'coord': {'lon': 12.13481, 'lat': 45.435799} + }, + { + 'id': 6540584, + 'name': 'Lissone', + 'country': 'IT', + 'coord': {'lon': 9.24655, 'lat': 45.615582} + }, + { + 'id': 6538560, + 'name': 'Lastra a Signa', + 'country': 'IT', + 'coord': {'lon': 11.10282, 'lat': 43.771351} + }, + { + 'id': 6541484, + 'name': 'Imperia', + 'country': 'IT', + 'coord': {'lon': 8.02225, 'lat': 43.88332} + }, + { + 'id': 6541474, + 'name': 'Jesi', + 'country': 'IT', + 'coord': {'lon': 13.24017, 'lat': 43.528759} + }, + { + 'id': 6541164, + 'name': 'Giugliano in Campania', + 'country': 'IT', + 'coord': {'lon': 14.19103, 'lat': 40.92741} + }, + { + 'id': 6537588, + 'name': 'Galatone', + 'country': 'IT', + 'coord': {'lon': 18.070419, 'lat': 40.142921} + }, + { + 'id': 6542094, + 'name': 'Gaeta', + 'country': 'IT', + 'coord': {'lon': 13.56281, 'lat': 41.218311} + }, + { + 'id': 6541853, + 'name': 'Frosinone', + 'country': 'IT', + 'coord': {'lon': 13.3401, 'lat': 41.640018} + }, + { + 'id': 6538453, + 'name': 'Formigine', + 'country': 'IT', + 'coord': {'lon': 10.847, 'lat': 44.57296} + }, + { + 'id': 6541136, + 'name': 'Fondi', + 'country': 'IT', + 'coord': {'lon': 13.43131, 'lat': 41.354111} + }, + { + 'id': 6540408, + 'name': 'Fidenza', + 'country': 'IT', + 'coord': {'lon': 10.06668, 'lat': 44.86396} + }, + { + 'id': 6536870, + 'name': 'Corciano', + 'country': 'IT', + 'coord': {'lon': 12.28736, 'lat': 43.12904} + }, + { + 'id': 6540023, + 'name': 'Conversano', + 'country': 'IT', + 'coord': {'lon': 17.11479, 'lat': 40.966228} + }, + { + 'id': 6539925, + 'name': 'Cittadella', + 'country': 'IT', + 'coord': {'lon': 11.7842, 'lat': 45.650002} + }, + { + 'id': 6538144, + 'name': 'Bra', + 'country': 'IT', + 'coord': {'lon': 7.85563, 'lat': 44.703041} + }, + { + 'id': 6542123, + 'name': 'Benevento', + 'country': 'IT', + 'coord': {'lon': 14.78614, 'lat': 41.12952} + }, + { + 'id': 6542012, + 'name': 'Bareggio', + 'country': 'IT', + 'coord': {'lon': 8.99994, 'lat': 45.487671} + }, + { + 'id': 6541492, + 'name': 'Arese', + 'country': 'IT', + 'coord': {'lon': 9.07654, 'lat': 45.552269} + }, + { + 'id': 6541135, + 'name': 'Aprilia', + 'country': 'IT', + 'coord': {'lon': 12.65009, 'lat': 41.589512} + }, + { + 'id': 6540534, + 'name': 'Anagni', + 'country': 'IT', + 'coord': {'lon': 13.15269, 'lat': 41.74472} + }, + { + 'id': 6536221, + 'name': 'Spinea', + 'country': 'IT', + 'coord': {'lon': 12.16251, 'lat': 45.488701} + }, + { + 'id': 6542340, + 'name': 'Volla', + 'country': 'IT', + 'coord': {'lon': 14.34293, 'lat': 40.87841} + }, + { + 'id': 3489227, + 'name': 'Old Harbour', + 'country': 'JM', + 'coord': {'lon': -77.108978, 'lat': 17.941441} + }, + { + 'id': 3489297, + 'name': 'New Kingston', + 'country': 'JM', + 'coord': {'lon': -76.783188, 'lat': 18.007469} + }, + { + 'id': 1859472, + 'name': 'Kimiidera', + 'country': 'JP', + 'coord': {'lon': 135.199997, 'lat': 34.183331} + }, + { + 'id': 1037370, + 'name': 'Mocimboa', + 'country': 'MZ', + 'coord': {'lon': 40.349998, 'lat': -11.31667} + }, + { + 'id': 2749810, + 'name': 'Gemeente Noordwijkerhout', + 'country': 'NL', + 'coord': {'lon': 4.48333, 'lat': 52.25} + }, + { + 'id': 2751688, + 'name': 'Gemeente Leusden', + 'country': 'NL', + 'coord': {'lon': 5.41667, 'lat': 52.133331} + }, + { + 'id': 2753467, + 'name': 'Gemeente Huizen', + 'country': 'NL', + 'coord': {'lon': 5.23333, 'lat': 52.283329} + }, + { + 'id': 2753718, + 'name': 'Gemeente Hoogeveen', + 'country': 'NL', + 'coord': {'lon': 6.58333, 'lat': 52.683331} + }, + { + 'id': 2754696, + 'name': 'Gemeente Heemskerk', + 'country': 'NL', + 'coord': {'lon': 4.65386, 'lat': 52.509449} + }, + { + 'id': 2759874, + 'name': 'Gemeente Alphen aan den Rijn', + 'country': 'NL', + 'coord': {'lon': 4.65, 'lat': 52.133331} + }, + { + 'id': 3160606, + 'name': 'Horten', + 'country': 'NO', + 'coord': {'lon': 10.48527, 'lat': 59.41547} + }, + { + 'id': 6453374, + 'name': 'Haugesund', + 'country': 'NO', + 'coord': {'lon': 5.27551, 'lat': 59.410149} + }, + { + 'id': 6453355, + 'name': 'Gjøvik', + 'country': 'NO', + 'coord': {'lon': 10.69287, 'lat': 60.79472} + }, + { + 'id': 6453341, + 'name': 'Ålesund', + 'country': 'NO', + 'coord': {'lon': 6.15424, 'lat': 62.471241} + }, + { + 'id': 1282635, + 'name': 'Tulsipur', + 'country': 'NP', + 'coord': {'lon': 82.297256, 'lat': 28.130989} + }, + { + 'id': 6240770, + 'name': 'Cambridge', + 'country': 'NZ', + 'coord': {'lon': 175.440201, 'lat': -37.87822} + }, + { + 'id': 288721, + 'name': 'Bidbid', + 'country': 'OM', + 'coord': {'lon': 58.1283, 'lat': 23.40786} + }, + { + 'id': 288764, + 'name': 'Bawshar', + 'country': 'OM', + 'coord': {'lon': 58.398899, 'lat': 23.55563} + }, + { + 'id': 288902, + 'name': 'Badiyah', + 'country': 'OM', + 'coord': {'lon': 58.799999, 'lat': 22.450001} + }, + { + 'id': 288955, + 'name': 'As Suwayq', + 'country': 'OM', + 'coord': {'lon': 57.43861, 'lat': 23.84944} + }, + { + 'id': 3691094, + 'name': 'Uchiza', + 'country': 'PE', + 'coord': {'lon': -76.463333, 'lat': -8.45917} + }, + { + 'id': 7530966, + 'name': 'Włocławek', + 'country': 'PL', + 'coord': {'lon': 19.060829, 'lat': 52.665379} + }, + { + 'id': 7531696, + 'name': 'Świdwin', + 'country': 'PL', + 'coord': {'lon': 15.7973, 'lat': 53.7742} + }, + { + 'id': 7530961, + 'name': 'Jastrzębie-Zdrój', + 'country': 'PL', + 'coord': {'lon': 18.600531, 'lat': 49.960629} + }, + { + 'id': 7532652, + 'name': 'Bełchatów', + 'country': 'PL', + 'coord': {'lon': 19.3626, 'lat': 51.3545} + }, + { + 'id': 4562506, + 'name': 'Aguadilla', + 'country': 'PR', + 'coord': {'lon': -67.154068, 'lat': 18.42745} + }, + { + 'id': 8014434, + 'name': 'Vila Franca de Xira', + 'country': 'PT', + 'coord': {'lon': -8.96442, 'lat': 38.912411} + }, + { + 'id': 8012598, + 'name': 'Ramada', + 'country': 'PT', + 'coord': {'lon': -9.19464, 'lat': 38.806961} + }, + { + 'id': 8013113, + 'name': 'Almada', + 'country': 'PT', + 'coord': {'lon': -9.16249, 'lat': 38.678871} + }, + { + 'id': 8012746, + 'name': 'Gueifães', + 'country': 'PT', + 'coord': {'lon': -8.6052, 'lat': 41.215248} + }, + { + 'id': 499452, + 'name': 'Safonovo', + 'country': 'RU', + 'coord': {'lon': 33.216671, 'lat': 55.150002} + }, + { + 'id': 2695079, + 'name': 'Lillsjönäs', + 'country': 'SE', + 'coord': {'lon': 17.950001, 'lat': 59.333328} + }, + { + 'id': 2407660, + 'name': 'Koidu', + 'country': 'SL', + 'coord': {'lon': -10.83333, 'lat': 8.41667} + }, + { + 'id': 1607257, + 'name': 'Prakhon Chai', + 'country': 'TH', + 'coord': {'lon': 103.120811, 'lat': 14.60592} + }, + { + 'id': 1609031, + 'name': 'Changwat Lop Buri', + 'country': 'TH', + 'coord': {'lon': 100.75, 'lat': 14.93333} + }, + { + 'id': 742902, + 'name': 'Kocaali', + 'country': 'TR', + 'coord': {'lon': 30.852779, 'lat': 41.05336} + }, + { + 'id': 148942, + 'name': 'Vwawa', + 'country': 'TZ', + 'coord': {'lon': 32.933331, 'lat': -9.11667} + }, + { + 'id': 4056099, + 'name': 'Coffee County', + 'country': 'US', + 'coord': {'lon': -86.000221, 'lat': 31.41683} + }, + { + 'id': 4151245, + 'name': 'Clay County', + 'country': 'US', + 'coord': {'lon': -81.833153, 'lat': 29.99968} + }, + { + 'id': 4155535, + 'name': 'Flagler County', + 'country': 'US', + 'coord': {'lon': -81.291451, 'lat': 29.45859} + }, + { + 'id': 4158449, + 'name': 'Hernando County', + 'country': 'US', + 'coord': {'lon': -82.458153, 'lat': 28.541941} + }, + { + 'id': 4174301, + 'name': 'Sumter County', + 'country': 'US', + 'coord': {'lon': -82.083138, 'lat': 28.708599} + }, + { + 'id': 4196508, + 'name': 'Fulton County', + 'country': 'US', + 'coord': {'lon': -84.449928, 'lat': 33.766769} + }, + { + 'id': 4191014, + 'name': 'DeKalb County', + 'country': 'US', + 'coord': {'lon': -84.233253, 'lat': 33.750381} + }, + { + 'id': 4255818, + 'name': 'Clark County', + 'country': 'US', + 'coord': {'lon': -85.761353, 'lat': 38.483398} + }, + { + 'id': 4310411, + 'name': 'Sylvania', + 'country': 'US', + 'coord': {'lon': -85.87413, 'lat': 38.157009} + }, + { + 'id': 4287837, + 'name': 'Clark County', + 'country': 'US', + 'coord': {'lon': -84.266602, 'lat': 37.98341} + }, + { + 'id': 4347820, + 'name': 'City of Baltimore', + 'country': 'US', + 'coord': {'lon': -76.61219, 'lat': 39.290379} + }, + { + 'id': 7198188, + 'name': 'Cashell Estates', + 'country': 'US', + 'coord': {'lon': -77.138702, 'lat': 39.137199} + }, + { + 'id': 4372589, + 'name': 'Wakely Terrace', + 'country': 'US', + 'coord': {'lon': -76.334961, 'lat': 39.525661} + }, + { + 'id': 4406835, + 'name': 'Saint Charles County', + 'country': 'US', + 'coord': {'lon': -90.733459, 'lat': 38.76672} + }, + { + 'id': 4407084, + 'name': 'City of Saint Louis', + 'country': 'US', + 'coord': {'lon': -90.197891, 'lat': 38.62727} + }, + { + 'id': 4422178, + 'name': 'Coahoma County', + 'country': 'US', + 'coord': {'lon': -90.567879, 'lat': 34.217892} + }, + { + 'id': 4431425, + 'name': 'Jackson County', + 'country': 'US', + 'coord': {'lon': -88.6278, 'lat': 30.42325} + }, + { + 'id': 4481511, + 'name': 'Nash County', + 'country': 'US', + 'coord': {'lon': -77.96637, 'lat': 35.96682} + }, + { + 'id': 4475520, + 'name': 'Lee County', + 'country': 'US', + 'coord': {'lon': -79.183083, 'lat': 35.46682} + }, + { + 'id': 4527624, + 'name': 'Warren County', + 'country': 'US', + 'coord': {'lon': -84.166603, 'lat': 39.433392} + }, + { + 'id': 4534444, + 'name': 'Creek County', + 'country': 'US', + 'coord': {'lon': -96.400291, 'lat': 35.900082} + }, + { + 'id': 4592843, + 'name': 'Richland County', + 'country': 'US', + 'coord': {'lon': -80.916481, 'lat': 34.016819} + }, + { + 'id': 4735729, + 'name': 'Taylor County', + 'country': 'US', + 'coord': {'lon': -99.833702, 'lat': 32.300129} + }, + { + 'id': 4697444, + 'name': 'Hidalgo County', + 'country': 'US', + 'coord': {'lon': -98.200287, 'lat': 26.333679} + }, + { + 'id': 4740157, + 'name': 'Washington County', + 'country': 'US', + 'coord': {'lon': -96.400238, 'lat': 30.233549} + }, + { + 'id': 4739690, + 'name': 'Walker County', + 'country': 'US', + 'coord': {'lon': -95.566887, 'lat': 30.73353} + }, + { + 'id': 4703071, + 'name': 'Kerr County', + 'country': 'US', + 'coord': {'lon': -99.300323, 'lat': 30.050211} + }, + { + 'id': 4744106, + 'name': 'City of Alexandria', + 'country': 'US', + 'coord': {'lon': -77.046921, 'lat': 38.80484} + }, + { + 'id': 4749005, + 'name': 'City of Bristol', + 'country': 'US', + 'coord': {'lon': -82.188469, 'lat': 36.596489} + }, + { + 'id': 4752046, + 'name': 'City of Charlottesville', + 'country': 'US', + 'coord': {'lon': -78.476677, 'lat': 38.029308} + }, + { + 'id': 4752215, + 'name': 'City of Chesapeake', + 'country': 'US', + 'coord': {'lon': -76.312157, 'lat': 36.687649} + }, + { + 'id': 4753684, + 'name': 'City of Colonial Heights', + 'country': 'US', + 'coord': {'lon': -77.410263, 'lat': 37.244041} + }, + { + 'id': 4755298, + 'name': 'City of Danville', + 'country': 'US', + 'coord': {'lon': -79.39502, 'lat': 36.585972} + }, + { + 'id': 4758109, + 'name': 'City of Fairfax', + 'country': 'US', + 'coord': {'lon': -77.306374, 'lat': 38.846218} + }, + { + 'id': 4760084, + 'name': 'City of Fredericksburg', + 'country': 'US', + 'coord': {'lon': -77.460541, 'lat': 38.303181} + }, + { + 'id': 4763237, + 'name': 'City of Harrisonburg', + 'country': 'US', + 'coord': {'lon': -78.868919, 'lat': 38.44957} + }, + { + 'id': 4764849, + 'name': 'City of Hopewell', + 'country': 'US', + 'coord': {'lon': -77.287201, 'lat': 37.304321} + }, + { + 'id': 4771099, + 'name': 'City of Lynchburg', + 'country': 'US', + 'coord': {'lon': -79.14225, 'lat': 37.41375} + }, + { + 'id': 4771426, + 'name': 'City of Manassas', + 'country': 'US', + 'coord': {'lon': -77.475273, 'lat': 38.75095} + }, + { + 'id': 4776037, + 'name': 'City of Newport News', + 'country': 'US', + 'coord': {'lon': -76.508011, 'lat': 37.062649} + }, + { + 'id': 4776242, + 'name': 'City of Norfolk', + 'country': 'US', + 'coord': {'lon': -76.261879, 'lat': 36.891258} + }, + { + 'id': 4778642, + 'name': 'City of Petersburg', + 'country': 'US', + 'coord': {'lon': -77.401932, 'lat': 37.227928} + }, + { + 'id': 4780019, + 'name': 'City of Portsmouth', + 'country': 'US', + 'coord': {'lon': -76.354668, 'lat': 36.85487} + }, + { + 'id': 4780851, + 'name': 'City of Radford', + 'country': 'US', + 'coord': {'lon': -80.576447, 'lat': 37.13179} + }, + { + 'id': 4781756, + 'name': 'City of Richmond', + 'country': 'US', + 'coord': {'lon': -77.460258, 'lat': 37.553761} + }, + { + 'id': 4782241, + 'name': 'City of Roanoke', + 'country': 'US', + 'coord': {'lon': -79.941429, 'lat': 37.270969} + }, + { + 'id': 4784205, + 'name': 'City of Salem', + 'country': 'US', + 'coord': {'lon': -80.054764, 'lat': 37.293468} + }, + { + 'id': 4788160, + 'name': 'City of Suffolk', + 'country': 'US', + 'coord': {'lon': -76.608009, 'lat': 36.708481} + }, + { + 'id': 4787467, + 'name': 'City of Staunton', + 'country': 'US', + 'coord': {'lon': -79.071701, 'lat': 38.149578} + }, + { + 'id': 4792534, + 'name': 'City of Waynesboro', + 'country': 'US', + 'coord': {'lon': -78.889473, 'lat': 38.06847} + }, + { + 'id': 4794134, + 'name': 'City of Winchester', + 'country': 'US', + 'coord': {'lon': -78.16333, 'lat': 39.185661} + }, + { + 'id': 5151606, + 'name': 'Cuyahoga County', + 'country': 'US', + 'coord': {'lon': -81.666519, 'lat': 41.433392} + }, + { + 'id': 4899519, + 'name': 'Lee County', + 'country': 'US', + 'coord': {'lon': -89.283432, 'lat': 41.750591} + }, + { + 'id': 4898722, + 'name': 'Knox County', + 'country': 'US', + 'coord': {'lon': -90.200119, 'lat': 40.933369} + }, + { + 'id': 5004681, + 'name': 'Ottawa County', + 'country': 'US', + 'coord': {'lon': -86.000603, 'lat': 42.95002} + }, + { + 'id': 4985190, + 'name': 'Bay County', + 'country': 'US', + 'coord': {'lon': -84.016647, 'lat': 43.73336} + }, + { + 'id': 5000477, + 'name': 'Macomb County', + 'country': 'US', + 'coord': {'lon': -82.949928, 'lat': 42.700031} + }, + { + 'id': 4997130, + 'name': 'Ingham County', + 'country': 'US', + 'coord': {'lon': -84.383301, 'lat': 42.60004} + }, + { + 'id': 5009706, + 'name': 'Shiawassee County', + 'country': 'US', + 'coord': {'lon': -84.149971, 'lat': 42.950031} + }, + { + 'id': 5128316, + 'name': 'Nassau County', + 'country': 'US', + 'coord': {'lon': -73.582901, 'lat': 40.75066} + }, + { + 'id': 6941775, + 'name': 'Kings County', + 'country': 'US', + 'coord': {'lon': -73.949577, 'lat': 40.650101} + }, + { + 'id': 5113792, + 'name': 'Cortland County', + 'country': 'US', + 'coord': {'lon': -76.082977, 'lat': 42.600071} + }, + { + 'id': 5112738, + 'name': 'City Line', + 'country': 'US', + 'coord': {'lon': -73.887077, 'lat': 40.676208} + }, + { + 'id': 5118116, + 'name': 'Fulton County', + 'country': 'US', + 'coord': {'lon': -74.449577, 'lat': 43.116741} + }, + { + 'id': 5122534, + 'name': 'Jamestown', + 'country': 'US', + 'coord': {'lon': -79.235329, 'lat': 42.097} + }, + { + 'id': 6332485, + 'name': 'Queensbridge Houses', + 'country': 'US', + 'coord': {'lon': -73.945, 'lat': 40.75528} + }, + { + 'id': 7250946, + 'name': 'Carnegie Hill', + 'country': 'US', + 'coord': {'lon': -73.95472, 'lat': 40.783329} + }, + { + 'id': 5133668, + 'name': 'Rensselaer County', + 'country': 'US', + 'coord': {'lon': -73.482887, 'lat': 42.716751} + }, + { + 'id': 5161640, + 'name': 'Mahoning County', + 'country': 'US', + 'coord': {'lon': -80.766472, 'lat': 41.03339} + }, + { + 'id': 5151896, + 'name': 'Delaware County', + 'country': 'US', + 'coord': {'lon': -83.000183, 'lat': 40.266731} + }, + { + 'id': 5145576, + 'name': 'Allen County', + 'country': 'US', + 'coord': {'lon': -84.083282, 'lat': 40.76672} + }, + { + 'id': 5153362, + 'name': 'Erie County', + 'country': 'US', + 'coord': {'lon': -82.599899, 'lat': 41.350052} + }, + { + 'id': 5221078, + 'name': 'Bristol County', + 'country': 'US', + 'coord': {'lon': -71.271721, 'lat': 41.71677} + }, + { + 'id': 5393068, + 'name': 'Santa Cruz County', + 'country': 'US', + 'coord': {'lon': -122.051071, 'lat': 37.066608} + }, + { + 'id': 5391997, + 'name': 'San Francisco County', + 'country': 'US', + 'coord': {'lon': -122.45108, 'lat': 37.766602} + }, + { + 'id': 5423573, + 'name': 'Grand Junction', + 'country': 'US', + 'coord': {'lon': -108.550652, 'lat': 39.063869} + }, + { + 'id': 5525886, + 'name': 'Maverick County', + 'country': 'US', + 'coord': {'lon': -100.350349, 'lat': 28.76692} + }, + { + 'id': 5522430, + 'name': 'Gray County', + 'country': 'US', + 'coord': {'lon': -100.802002, 'lat': 35.416698} + }, + { + 'id': 1512838, + 'name': 'Shofirkon', + 'country': 'UZ', + 'coord': {'lon': 64.501389, 'lat': 40.119999} + }, + { + 'id': 1512978, + 'name': 'Qushkupir', + 'country': 'UZ', + 'coord': {'lon': 60.345558, 'lat': 41.535} + }, + { + 'id': 1513017, + 'name': 'Parkent', + 'country': 'UZ', + 'coord': {'lon': 69.676392, 'lat': 41.294441} + }, + { + 'id': 1513023, + 'name': 'Pop', + 'country': 'UZ', + 'coord': {'lon': 71.108887, 'lat': 40.873611} + }, + { + 'id': 1513038, + 'name': 'Paxtakor', + 'country': 'UZ', + 'coord': {'lon': 67.954437, 'lat': 40.315281} + }, + { + 'id': 1513092, + 'name': 'Novyy Turtkul', + 'country': 'UZ', + 'coord': {'lon': 61.01667, 'lat': 41.549999} + }, + { + 'id': 1513245, + 'name': 'Manghit', + 'country': 'UZ', + 'coord': {'lon': 60.059719, 'lat': 42.115559} + }, + { + 'id': 1513655, + 'name': 'Haqqulobod', + 'country': 'UZ', + 'coord': {'lon': 72.116669, 'lat': 40.916672} + }, + { + 'id': 1513900, + 'name': 'Iskandar', + 'country': 'UZ', + 'coord': {'lon': 69.700829, 'lat': 41.55389} + }, + { + 'id': 1513957, + 'name': 'Hazorasp', + 'country': 'UZ', + 'coord': {'lon': 61.074169, 'lat': 41.319439} + }, + { + 'id': 1514215, + 'name': 'Chinoz', + 'country': 'UZ', + 'coord': {'lon': 68.769722, 'lat': 40.93639} + }, + { + 'id': 1514330, + 'name': 'Buka', + 'country': 'UZ', + 'coord': {'lon': 69.198608, 'lat': 40.810829} + }, + { + 'id': 1514387, + 'name': 'Beruniy', + 'country': 'UZ', + 'coord': {'lon': 60.752499, 'lat': 41.691109} + }, + { + 'id': 1514396, + 'name': 'Bektemir', + 'country': 'UZ', + 'coord': {'lon': 69.334167, 'lat': 41.209721} + }, + { + 'id': 1526979, + 'name': 'Quva', + 'country': 'UZ', + 'coord': {'lon': 72.072922, 'lat': 40.522041} + }, + { + 'id': 3748724, + 'name': 'Redemption', + 'country': 'VC', + 'coord': {'lon': -61.229439, 'lat': 13.16444} + }, + { + 'id': 3649281, + 'name': 'Municipio Anaco', + 'country': 'VE', + 'coord': {'lon': -64.466667, 'lat': 9.33333} + }, + { + 'id': 3486270, + 'name': 'Anaco', + 'country': 'VE', + 'coord': {'lon': -64.472778, 'lat': 9.43889} + }, + { + 'id': 3625123, + 'name': 'Municipio Zamora', + 'country': 'VE', + 'coord': {'lon': -67.5, 'lat': 10.06667} + }, + { + 'id': 3625547, + 'name': 'Municipio Valencia', + 'country': 'VE', + 'coord': {'lon': -68.083328, 'lat': 10.08333} + }, + { + 'id': 8129205, + 'name': 'Municipio Santiago Mariño', + 'country': 'VE', + 'coord': {'lon': -67.472878, 'lat': 10.22388} + }, + { + 'id': 3628416, + 'name': 'Municipio San Felipe', + 'country': 'VE', + 'coord': {'lon': -68.633331, 'lat': 10.5} + }, + { + 'id': 3645361, + 'name': 'Municipio Colón', + 'country': 'VE', + 'coord': {'lon': -72.083328, 'lat': 9} + }, + { + 'id': 3628494, + 'name': 'Municipio San Carlos', + 'country': 'VE', + 'coord': {'lon': -68.583328, 'lat': 9.58333} + }, + { + 'id': 8129204, + 'name': 'Municipio Los Salias', + 'country': 'VE', + 'coord': {'lon': -66.95179, 'lat': 10.38854} + }, + { + 'id': 8129175, + 'name': 'Municipio Sucre', + 'country': 'VE', + 'coord': {'lon': -66.801552, 'lat': 10.47226} + }, + { + 'id': 8129237, + 'name': 'Municipio Libertador', + 'country': 'VE', + 'coord': {'lon': -67.541939, 'lat': 10.17389} + }, + { + 'id': 3630932, + 'name': 'Palo Negro', + 'country': 'VE', + 'coord': {'lon': -67.541939, 'lat': 10.17389} + }, + { + 'id': 3631506, + 'name': 'Municipio Nirgua', + 'country': 'VE', + 'coord': {'lon': -68.666672, 'lat': 10.08333} + }, +]; diff --git a/example/lib/common.dart b/example/lib/common.dart new file mode 100644 index 0000000..8c78d49 --- /dev/null +++ b/example/lib/common.dart @@ -0,0 +1,25 @@ +import 'dart:developer'; + +import 'package:http_interceptor/http_interceptor.dart'; + +class LoggerInterceptor extends InterceptorContract { + @override + Future interceptRequest({ + required BaseRequest request, + }) async { + log('----- Request -----'); + log(request.toString()); + log(request.headers.toString()); + return request; + } + + @override + Future interceptResponse({ + required BaseResponse response, + }) async { + log('----- Response -----'); + log('Code: ${response.statusCode}'); + log(response.toString()); + return response; + } +} diff --git a/example/lib/credentials.dart b/example/lib/credentials.dart index df63344..bd4799a 100644 --- a/example/lib/credentials.dart +++ b/example/lib/credentials.dart @@ -1,3 +1,4 @@ // Replace this if you are going to run the example. You can get your own at https://openweathermap.org/ -const String OPEN_WEATHER_EXPIRED_API_KEY = "b04a4a7c5a71de47d7cdb0s5687c5d14"; -const String OPEN_WEATHER_API_KEY = "b04a4a7c5a71de47d7cdb0c7607c5d14"; +const String kOpenWeatherExpiredApiKey = 'b04a4a7c5a71de47d7cdb0s5687c5d14'; +const String kOpenWeatherApiKey = 'b04a4a7c5a71de47d7cdb0c7607c5d14'; +const String kRemoveBgApiKey = 'JQTfvLJiunzmZ4gkxwP8CH95'; diff --git a/example/lib/main.dart b/example/lib/main.dart index 2a91f21..d7e8b40 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,377 +1,47 @@ -import 'dart:convert'; -import 'dart:developer'; -import 'dart:io'; - import 'package:flutter/material.dart'; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http_interceptor_example/multipart_app.dart'; + +import 'weather_app.dart'; -import 'cities.dart'; // This is just a List of Maps that contains the suggested cities. -import 'credentials.dart'; // If you are going to run this example you need to replace the key. +void main() => runApp(const ExamplesApp()); -void main() => runApp(MyApp()); +class ExamplesApp extends StatelessWidget { + const ExamplesApp({Key? key}) : super(key: key); -class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - home: HomeScreen(), + return const MaterialApp( + home: ExamplesMenuScreen(), ); } } -class HomeScreen extends StatefulWidget { - @override - _HomeScreenState createState() => _HomeScreenState(); -} - -class _HomeScreenState extends State { - WeatherRepository repository = WeatherRepository( - InterceptedClient.build( - interceptors: [ - WeatherApiInterceptor(), - LoggerInterceptor(), - ], - retryPolicy: ExpiredTokenRetryPolicy(), - ), - ); - - @override - void initState() { - super.initState(); - - clearStorageForDemoPurposes(); - } - - Future clearStorageForDemoPurposes() async { - final cache = await SharedPreferences.getInstance(); - - cache.setString(kOWApiToken, OPEN_WEATHER_EXPIRED_API_KEY); - } - - @override - void dispose() { - repository.client.close(); - super.dispose(); - } +class ExamplesMenuScreen extends StatelessWidget { + const ExamplesMenuScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - centerTitle: true, - title: const Text('Weather App'), - actions: [ - IconButton( - icon: Icon(Icons.search), - onPressed: () { - showSearch( - context: context, - delegate: WeatherSearch(repository), - ); - }, - ) - ], - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.wb_sunny, - size: 64, - color: Colors.grey, - ), - Container( - height: 16, - ), - Text( - "Search for a city", - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.w300, - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - ); - } -} - -class WeatherSearch extends SearchDelegate { - int selected = -1; - WeatherRepository repo; - - WeatherSearch(this.repo); - - @override - List buildActions(BuildContext context) { - return [ - IconButton( - icon: Icon(Icons.clear), - onPressed: () { - selected = -1; - query = ""; - }, - ) - ]; - } - - @override - Widget buildLeading(BuildContext context) { - return IconButton( - icon: AnimatedIcon( - icon: AnimatedIcons.menu_arrow, - progress: transitionAnimation, + title: const Text('Examples'), ), - onPressed: () { - close(context, null); - }, - ); - } - - @override - Widget buildResults(BuildContext context) { - final city = selected == -1 ? null : cities[selected]; - - return city != null ? buildWeatherCard(city) : buildEmptyCard(); - } - - @override - Widget buildSuggestions(BuildContext context) { - final suggestionList = query.isEmpty - ? cities - : cities.where((p) => p["name"].toString().startsWith(query)).toList(); - return ListView.builder( - itemCount: suggestionList.length, - itemBuilder: (context, index) { - return ListTile( - onTap: () { - selected = index; - query = cities[selected]["name"] as String; - showResults(context); - }, - title: Text(suggestionList[index]['name'] as String), - subtitle: Text(suggestionList[index]['country'] as String), - ); - }, - ); - } - - Widget buildWeatherCard(final city) { - return FutureBuilder>( - future: repo.fetchCityWeather(city["id"]), - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center( - child: Text(snapshot.error?.toString() ?? 'Error'), - ); - } - - if (!snapshot.hasData) { - return Center( - child: CircularProgressIndicator(), - ); - } - final weather = snapshot.data; - final iconWeather = weather!["weather"][0]["icon"]; - final main = weather["main"]; - final wind = weather["wind"]; - return Card( - margin: EdgeInsets.all(16.0), - child: Container( - width: Size.infinite.width, - padding: EdgeInsets.all(16.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - leading: Tooltip( - child: Image.network( - "https://openweathermap.org/img/w/$iconWeather.png"), - message: weather["weather"][0]["main"], - ), - title: Text(city["name"]), - subtitle: Text(city["country"]), - ), - ListTile( - title: Text("${main["temp"]} °C"), - subtitle: Text("Temperature"), - ), - ListTile( - title: Text("${main["temp_min"]} °C"), - subtitle: Text("Min Temperature"), - ), - ListTile( - title: Text("${main["temp_max"]} °C"), - subtitle: Text("Max Temperature"), - ), - ListTile( - title: Text("${main["humidity"]} %"), - subtitle: Text("Humidity"), - ), - ListTile( - title: Text("${main["pressure"]} hpa"), - subtitle: Text("Pressure"), - ), - ListTile( - title: Text("${wind["speed"]} m/s"), - subtitle: Text("Wind Speed"), - ), - ], - ), + body: ListView( + shrinkWrap: true, + children: [ + ListTile( + leading: const Icon(Icons.cloud), + title: const Text('Weather Example'), + subtitle: const Text('Simple HTTP Intercepting'), + onTap: () => Navigator.push(context, WeatherApp.route()), ), - ); - }, - ); - } - - Widget buildEmptyCard() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.wb_sunny, - size: 64, - color: Colors.grey, - ), - Container( - height: 16, - ), - Text( - "Search for a city", - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.w300, - ), - textAlign: TextAlign.center, + ListTile( + leading: const Icon(Icons.photo), + title: const Text('Remove Img Background Example'), + subtitle: const Text('Multipart Intercepting'), + onTap: () => Navigator.push(context, MultipartApp.route()), ), ], ), ); } } - -const baseUrl = "https://api.openweathermap.org/data/2.5"; - -class WeatherRepository { - InterceptedClient client; - - WeatherRepository(this.client); - - // Alternatively you can forget about using the Client and just doing the HTTP request with - // the InterceptedHttp.build() call. - // Future> fetchCityWeather(int id) async { - // var parsedWeather; - // try { - // var response = await InterceptedHttp.build( - // interceptors: [WeatherApiInterceptor()]) - // .get("$baseUrl/weather", params: {'id': "$id"}); - // if (response.statusCode == 200) { - // parsedWeather = json.decode(response.body); - // } else { - // throw Exception("Error while fetching. \n ${response.body}"); - // } - // } catch (e) { - // log(e); - // } - // return parsedWeather; - // } - - Future> fetchCityWeather(int? id) async { - var parsedWeather; - try { - final response = - await client.get("$baseUrl/weather".toUri(), params: {'id': "$id"}); - if (response.statusCode == 200) { - parsedWeather = json.decode(response.body); - } else { - return Future.error( - "Error while fetching.", - StackTrace.fromString("${response.body}"), - ); - } - } on SocketException { - return Future.error('No Internet connection 😑'); - } on FormatException { - return Future.error('Bad response format 👎'); - } on Exception catch (error) { - log(error.toString()); - return Future.error('Unexpected error 😢'); - } - - return parsedWeather; - } -} - -class LoggerInterceptor implements InterceptorContract { - @override - Future interceptRequest({required BaseRequest request}) async { - log("----- Request -----"); - log(request.toString()); - return request; - } - - @override - Future interceptResponse( - {required BaseResponse response}) async { - log("----- Response -----"); - log('Err. Code: ${response.statusCode}'); - log(response.toString()); - return response; - } -} - -const String kOWApiToken = "TOKEN"; - -class WeatherApiInterceptor implements InterceptorContract { - @override - Future interceptRequest({required BaseRequest request}) async { - final cache = await SharedPreferences.getInstance(); - - final Map? headers = Map.from(request.headers); - headers?[HttpHeaders.contentTypeHeader] = "application/json"; - - return request.copyWith( - url: request.url.addParameters({ - 'appid': cache.getString(kOWApiToken) ?? '', - 'units': 'metric', - }), - headers: headers, - ); - } - - @override - Future interceptResponse( - {required BaseResponse response}) async => - response; -} - -class ExpiredTokenRetryPolicy extends RetryPolicy { - @override - int get maxRetryAttempts => 2; - - @override - bool shouldAttemptRetryOnException(Exception reason, BaseRequest request) { - log(reason.toString()); - - return false; - } - - @override - Future shouldAttemptRetryOnResponse(BaseResponse response) async { - if (response.statusCode == 401) { - log("Retrying request..."); - final cache = await SharedPreferences.getInstance(); - - cache.setString(kOWApiToken, OPEN_WEATHER_API_KEY); - - return true; - } - - return false; - } -} diff --git a/example/lib/multipart_app.dart b/example/lib/multipart_app.dart new file mode 100644 index 0000000..f7cd553 --- /dev/null +++ b/example/lib/multipart_app.dart @@ -0,0 +1,178 @@ +import 'dart:developer'; +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:http_interceptor_example/common.dart'; +import 'package:http_interceptor_example/credentials.dart'; +import 'package:image_picker/image_picker.dart'; + +class MultipartApp extends StatefulWidget { + const MultipartApp({Key? key}) : super(key: key); + + static Route route() { + return MaterialPageRoute(builder: (ctx) => const MultipartApp()); + } + + @override + State createState() => _MultipartAppState(); +} + +class _MultipartAppState extends State { + RemoveBgRepository repository = RemoveBgRepository( + InterceptedClient.build( + interceptors: [ + RemoveBgApiInterceptor(), + LoggerInterceptor(), + ], + ), + ); + + final ImagePicker _picker = ImagePicker(); + XFile? pickedImage; + ui.Image? noBgImage; + + Future _onUpload() async { + if (pickedImage == null) return; + + setState(() { + noBgImage = null; + }); + + final data = + await repository.removeImageBackground(pickedImage!, 'image_file'); + + setState(() { + noBgImage = data; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Remove BG App'), + ), + floatingActionButton: FloatingActionButton.extended( + onPressed: pickedImage == null ? null : _onUpload, + icon: const Icon(Icons.upload), + label: const Text('Upload'), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + body: SafeArea( + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 16), + children: [ + ListTile( + leading: const Icon(Icons.camera), + title: const Text('Take Picture'), + onTap: () async { + final image = + await _picker.pickImage(source: ImageSource.camera); + setState(() { + pickedImage = image; + noBgImage = null; + }); + }, + ), + ListTile( + leading: const Icon(Icons.album), + title: const Text('Choose from Gallery'), + onTap: () async { + final image = + await _picker.pickImage(source: ImageSource.gallery); + setState(() { + pickedImage = image; + noBgImage = null; + }); + }, + ), + if (pickedImage != null) ...[ + const Text('Before'), + Image.file(File(pickedImage!.path)), + ], + if (noBgImage != null) ...[ + const Text('After'), + RawImage( + image: noBgImage!, // this is a dart:ui Image object + scale: 1.0, + ), + ], + ], + ), + ), + ); + } +} + +// const baseUrl = 'http://api.resmush.it/ws.php'; +const baseUrl = 'https://api.remove.bg/v1.0/removebg'; + +class RemoveBgRepository { + InterceptedClient client; + + RemoveBgRepository(this.client); + + Future removeImageBackground( + XFile imgFile, + String fieldName, + ) async { + ui.Image parsedResponse; + try { + final req = MultipartRequest( + HttpMethod.POST.asString, + Uri.parse(baseUrl), + )..files.add( + await MultipartFile.fromPath( + fieldName, + imgFile.path, + ), + ); + + final response = await client.send(req); + if (response.statusCode == 200) { + final respBytes = await response.stream.first; + final image = await decodeImageFromList(Uint8List.fromList(respBytes)); + + parsedResponse = image; + } else { + return Future.error( + 'Error while fetching.', + StackTrace.fromString(''), + ); + } + } on SocketException { + return Future.error('No Internet connection 😑'); + } on FormatException { + return Future.error('Bad response format 👎'); + } on Exception catch (error) { + log(error.toString()); + return Future.error('Unexpected error 😢'); + } + + return parsedResponse; + } +} + +class RemoveBgApiInterceptor extends InterceptorContract { + @override + Future interceptRequest({ + required BaseRequest request, + }) async { + final Map headers = Map.from(request.headers); + headers[HttpHeaders.contentTypeHeader] = 'application/json'; + headers['X-Api-Key'] = kRemoveBgApiKey; + + return request.copyWith( + headers: headers, + ); + } + + @override + Future interceptResponse({ + required BaseResponse response, + }) async => + response; +} diff --git a/example/lib/weather_app.dart b/example/lib/weather_app.dart new file mode 100644 index 0000000..e37eeab --- /dev/null +++ b/example/lib/weather_app.dart @@ -0,0 +1,357 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:http_interceptor_example/common.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +/// This is just a List of Maps that contains the suggested cities. +/// If you are going to run this example you need to replace the key. +import 'cities.dart'; +import 'credentials.dart'; + +class WeatherApp extends StatefulWidget { + const WeatherApp({Key? key}) : super(key: key); + + static Route route() { + return MaterialPageRoute(builder: (ctx) => const WeatherApp()); + } + + @override + WeatherAppState createState() => WeatherAppState(); +} + +class WeatherAppState extends State { + WeatherRepository repository = WeatherRepository( + InterceptedClient.build( + interceptors: [ + WeatherApiInterceptor(), + LoggerInterceptor(), + ], + retryPolicy: ExpiredTokenRetryPolicy(), + ), + ); + + @override + void initState() { + super.initState(); + + clearStorageForDemoPurposes(); + } + + Future clearStorageForDemoPurposes() async { + final cache = await SharedPreferences.getInstance(); + + cache.setString(kOWApiToken, kOpenWeatherExpiredApiKey); + } + + @override + void dispose() { + repository.client.close(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: const Text('Weather App'), + actions: [ + IconButton( + icon: const Icon(Icons.search), + onPressed: () { + showSearch( + context: context, + delegate: WeatherSearch(repository), + ); + }, + ) + ], + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.wb_sunny, + size: 64, + color: Colors.grey, + ), + Container( + height: 16, + ), + const Text( + 'Search for a city', + style: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.w300, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } +} + +class WeatherSearch extends SearchDelegate { + int selected = -1; + WeatherRepository repo; + + WeatherSearch(this.repo); + + @override + List buildActions(BuildContext context) { + return [ + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + selected = -1; + query = ''; + }, + ) + ]; + } + + @override + Widget buildLeading(BuildContext context) { + return IconButton( + icon: AnimatedIcon( + icon: AnimatedIcons.menu_arrow, + progress: transitionAnimation, + ), + onPressed: () { + close(context, null); + }, + ); + } + + @override + Widget buildResults(BuildContext context) { + final city = selected == -1 ? null : cities[selected]; + + return city != null ? buildWeatherCard(city) : buildEmptyCard(); + } + + @override + Widget buildSuggestions(BuildContext context) { + final suggestionList = query.isEmpty + ? cities + : cities.where((p) => p['name'].toString().startsWith(query)).toList(); + return ListView.builder( + itemCount: suggestionList.length, + itemBuilder: (context, index) { + return ListTile( + onTap: () { + selected = index; + query = cities[selected]['name'] as String; + showResults(context); + }, + title: Text(suggestionList[index]['name'] as String), + subtitle: Text(suggestionList[index]['country'] as String), + ); + }, + ); + } + + Widget buildWeatherCard(final city) { + return FutureBuilder>( + future: repo.fetchCityWeather(city['id']), + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center( + child: Text(snapshot.error?.toString() ?? 'Error'), + ); + } + + if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator(), + ); + } + final weather = snapshot.data; + final iconWeather = weather!['weather'][0]['icon']; + final main = weather['main']; + final wind = weather['wind']; + return Card( + margin: const EdgeInsets.all(16.0), + child: Container( + width: Size.infinite.width, + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: Tooltip( + message: weather['weather'][0]['main'], + child: Image.network( + 'https://openweathermap.org/img/w/$iconWeather.png'), + ), + title: Text(city['name']), + subtitle: Text(city['country']), + ), + ListTile( + title: Text("${main["temp"]} °C"), + subtitle: const Text('Temperature'), + ), + ListTile( + title: Text("${main["temp_min"]} °C"), + subtitle: const Text('Min Temperature'), + ), + ListTile( + title: Text("${main["temp_max"]} °C"), + subtitle: const Text('Max Temperature'), + ), + ListTile( + title: Text("${main["humidity"]} %"), + subtitle: const Text('Humidity'), + ), + ListTile( + title: Text("${main["pressure"]} hpa"), + subtitle: const Text('Pressure'), + ), + ListTile( + title: Text("${wind["speed"]} m/s"), + subtitle: const Text('Wind Speed'), + ), + ], + ), + ), + ); + }, + ); + } + + Widget buildEmptyCard() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.wb_sunny, + size: 64, + color: Colors.grey, + ), + Container( + height: 16, + ), + const Text( + 'Search for a city', + style: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.w300, + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + } +} + +const baseUrl = 'https://api.openweathermap.org/data/2.5'; + +class WeatherRepository { + InterceptedClient client; + + WeatherRepository(this.client); + + // Alternatively you can forget about using the Client and just doing the HTTP request with + // the InterceptedHttp.build() call. + // Future> fetchCityWeather(int id) async { + // var parsedWeather; + // try { + // var response = await InterceptedHttp.build( + // interceptors: [WeatherApiInterceptor()]) + // .get("$baseUrl/weather", params: {'id': "$id"}); + // if (response.statusCode == 200) { + // parsedWeather = json.decode(response.body); + // } else { + // throw Exception("Error while fetching. \n ${response.body}"); + // } + // } catch (e) { + // log(e); + // } + // return parsedWeather; + // } + + Future> fetchCityWeather(int? id) async { + Map parsedWeather; + try { + final response = + await client.get('$baseUrl/weather'.toUri(), params: {'id': '$id'}); + if (response.statusCode == 200) { + parsedWeather = jsonDecode(response.body); + } else { + return Future.error( + 'Error while fetching.', + StackTrace.fromString(response.body), + ); + } + } on SocketException { + return Future.error('No Internet connection 😑'); + } on FormatException { + return Future.error('Bad response format 👎'); + } on Exception catch (error) { + log(error.toString()); + return Future.error('Unexpected error 😢'); + } + + return parsedWeather; + } +} + +const String kOWApiToken = 'TOKEN'; + +class WeatherApiInterceptor extends InterceptorContract { + @override + Future interceptRequest({required BaseRequest request}) async { + final cache = await SharedPreferences.getInstance(); + + final Map headers = Map.from(request.headers); + headers[HttpHeaders.contentTypeHeader] = 'application/json'; + + return request.copyWith( + url: request.url.addParameters({ + 'appid': cache.getString(kOWApiToken) ?? '', + 'units': 'metric', + }), + headers: headers, + ); + } + + @override + Future interceptResponse( + {required BaseResponse response}) async => + response; +} + +class ExpiredTokenRetryPolicy extends RetryPolicy { + @override + int get maxRetryAttempts => 2; + + @override + bool shouldAttemptRetryOnException(Exception reason, BaseRequest request) { + log(reason.toString()); + + return false; + } + + @override + Future shouldAttemptRetryOnResponse(BaseResponse response) async { + if (response.statusCode == 401) { + log('Retrying request...'); + final cache = await SharedPreferences.getInstance(); + + cache.setString(kOWApiToken, kOpenWeatherApiKey); + + return true; + } + + return false; + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5da13dd..77bbb8e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,19 +1,22 @@ name: http_interceptor_example description: Demonstrates how to use the http_interceptor plugin. version: 0.0.1+1 -publish_to: "none" +publish_to: 'none' environment: - sdk: ">=2.12.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter http_interceptor: path: ../ + http_parser: ^4.0.1 + image_picker: ^0.8.5+3 shared_preferences: ^2.0.6 dev_dependencies: + flutter_lints: ^2.0.1 flutter_test: sdk: flutter diff --git a/lib/extensions/base_request.dart b/lib/extensions/base_request.dart index 761bfa7..4c77ea2 100644 --- a/lib/extensions/base_request.dart +++ b/lib/extensions/base_request.dart @@ -1,9 +1,12 @@ import 'dart:convert'; import 'package:http/http.dart'; -import 'package:http_interceptor/extensions/extensions.dart'; import 'package:http_interceptor/http/http_methods.dart'; +import './multipart_request.dart'; +import './request.dart'; +import './streamed_request.dart'; + /// Extends [BaseRequest] to provide copied instances. extension BaseRequestCopyWith on BaseRequest { /// Creates a new instance of [BaseRequest] based of on `this`. It copies @@ -66,6 +69,6 @@ extension BaseRequestCopyWith on BaseRequest { } throw UnsupportedError( - 'Cannot copy unsupported type of request ${this.runtimeType}'); + 'Cannot copy unsupported type of request $runtimeType'); } } diff --git a/lib/extensions/base_response_io.dart b/lib/extensions/base_response_io.dart index dc7fcf6..ec46047 100644 --- a/lib/extensions/base_response_io.dart +++ b/lib/extensions/base_response_io.dart @@ -2,9 +2,11 @@ import 'dart:io'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; -import 'package:http_interceptor/extensions/extensions.dart'; import 'package:http_interceptor/extensions/io_streamed_response.dart'; +import './response.dart'; +import './streamed_response.dart'; + // Extends [BaseRequest] to provide copied instances. extension BaseResponseCopyWith on BaseResponse { /// Creates a new instance of [BaseResponse] based of on `this`. It copies @@ -67,6 +69,6 @@ extension BaseResponseCopyWith on BaseResponse { } throw UnsupportedError( - 'Cannot copy unsupported type of response ${this.runtimeType}'); + 'Cannot copy unsupported type of response $runtimeType'); } } diff --git a/lib/extensions/base_response_none.dart b/lib/extensions/base_response_none.dart index 1a1cd39..a2e72f3 100644 --- a/lib/extensions/base_response_none.dart +++ b/lib/extensions/base_response_none.dart @@ -1,5 +1,7 @@ import 'package:http/http.dart'; -import 'package:http_interceptor/extensions/extensions.dart'; + +import './response.dart'; +import './streamed_response.dart'; // Extends [BaseRequest] to provide copied instances. extension BaseResponseCopyWith on BaseResponse { @@ -47,6 +49,6 @@ extension BaseResponseCopyWith on BaseResponse { } throw UnsupportedError( - 'Cannot copy unsupported type of response ${this.runtimeType}'); + 'Cannot copy unsupported type of response $runtimeType'); } } diff --git a/lib/extensions/extensions.dart b/lib/extensions/extensions.dart deleted file mode 100644 index deaad51..0000000 --- a/lib/extensions/extensions.dart +++ /dev/null @@ -1,10 +0,0 @@ -export 'base_request.dart'; -export 'base_response_none.dart' if (dart.library.io) 'base_response_io.dart'; -export 'multipart_request.dart'; -export 'request.dart'; -export 'request.dart'; -export 'response.dart'; -export 'streamed_request.dart'; -export 'streamed_response.dart'; -export 'string.dart'; -export 'uri.dart'; diff --git a/lib/extensions/streamed_request.dart b/lib/extensions/streamed_request.dart index b90286c..47112e9 100644 --- a/lib/extensions/streamed_request.dart +++ b/lib/extensions/streamed_request.dart @@ -28,7 +28,7 @@ extension StreamedRequestCopyWith on StreamedRequest { stream.listen((data) { req.sink.add(data); }); - this.finalize().listen((data) { + finalize().listen((data) { req.sink.add(data); }); } diff --git a/lib/extensions/uri.dart b/lib/extensions/uri.dart index 4f2e7b2..f0613f4 100644 --- a/lib/extensions/uri.dart +++ b/lib/extensions/uri.dart @@ -1,4 +1,4 @@ -import 'package:http_interceptor/extensions/extensions.dart'; +import 'package:http_interceptor/extensions/string.dart'; import 'package:http_interceptor/utils/utils.dart'; /// Extends `Uri` to allow adding parameters to already created intstances diff --git a/lib/http/http.dart b/lib/http/http.dart index f70463f..c9e04dd 100644 --- a/lib/http/http.dart +++ b/lib/http/http.dart @@ -1,4 +1,4 @@ +export '../models/interceptor_contract.dart'; export 'http_methods.dart'; export 'intercepted_client.dart'; export 'intercepted_http.dart'; -export 'interceptor_contract.dart'; diff --git a/lib/http/http_methods.dart b/lib/http/http_methods.dart index 6ba6daf..c53aa9b 100644 --- a/lib/http/http_methods.dart +++ b/lib/http/http_methods.dart @@ -1,3 +1,4 @@ +// ignore_for_file: constant_identifier_names /// Enum representation of all available HTTP methods. enum HttpMethod { HEAD, diff --git a/lib/http/intercepted_client.dart b/lib/http/intercepted_client.dart index 5318273..6193ed1 100644 --- a/lib/http/intercepted_client.dart +++ b/lib/http/intercepted_client.dart @@ -3,11 +3,12 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:http/http.dart'; -import 'package:http_interceptor/extensions/extensions.dart'; -import 'package:http_interceptor/models/models.dart'; +import 'package:http_interceptor/extensions/base_request.dart'; +import 'package:http_interceptor/extensions/uri.dart'; +import '../models/interceptor_contract.dart'; +import '../models/retry_policy.dart'; import 'http_methods.dart'; -import 'interceptor_contract.dart'; typedef TimeoutCallback = FutureOr Function(); @@ -107,6 +108,7 @@ class InterceptedClient extends BaseClient { headers: headers, )) as Response; + @override Future get( Uri url, { Map? headers, @@ -230,7 +232,7 @@ class InterceptedClient extends BaseClient { }) async { url = url.addParameters(params); - Request request = new Request(method.asString, url); + Request request = Request(method.asString, url); if (headers != null) request.headers.addAll(headers); if (encoding != null) request.encoding = encoding; if (body != null) { @@ -241,7 +243,7 @@ class InterceptedClient extends BaseClient { } else if (body is Map) { request.bodyFields = body.cast(); } else { - throw new ArgumentError('Invalid request body "$body".'); + throw ArgumentError('Invalid request body "$body".'); } } @@ -259,7 +261,7 @@ class InterceptedClient extends BaseClient { if (response.reasonPhrase != null) { message = "$message: ${response.reasonPhrase}"; } - throw new ClientException("$message.", url); + throw ClientException("$message.", url); } /// Attempts to perform the request and intercept the data @@ -304,9 +306,11 @@ class InterceptedClient extends BaseClient { Future _interceptRequest(BaseRequest request) async { BaseRequest interceptedRequest = request.copyWith(); for (InterceptorContract interceptor in interceptors) { - interceptedRequest = await interceptor.interceptRequest( - request: interceptedRequest, - ); + if (await interceptor.shouldInterceptRequest()) { + interceptedRequest = await interceptor.interceptRequest( + request: interceptedRequest, + ); + } } return interceptedRequest; @@ -316,14 +320,17 @@ class InterceptedClient extends BaseClient { Future _interceptResponse(BaseResponse response) async { BaseResponse interceptedResponse = response; for (InterceptorContract interceptor in interceptors) { - interceptedResponse = await interceptor.interceptResponse( - response: interceptedResponse, - ); + if (await interceptor.shouldInterceptResponse()) { + interceptedResponse = await interceptor.interceptResponse( + response: interceptedResponse, + ); + } } return interceptedResponse; } + @override void close() { _inner.close(); } diff --git a/lib/http/intercepted_http.dart b/lib/http/intercepted_http.dart index cd16c9b..8fd82d3 100644 --- a/lib/http/intercepted_http.dart +++ b/lib/http/intercepted_http.dart @@ -223,7 +223,7 @@ class InterceptedHttp { /// Internal convenience utility to create a new [Client] instance for each /// request. It closes the client after using it for the request. Future _withClient( - Future fn(InterceptedClient client), + Future Function(InterceptedClient client) fn, ) async { final client = InterceptedClient.build( interceptors: interceptors, diff --git a/lib/http_interceptor.dart b/lib/http_interceptor.dart index b37b28e..9f2f8ef 100644 --- a/lib/http_interceptor.dart +++ b/lib/http_interceptor.dart @@ -1,6 +1,21 @@ library http_interceptor; export 'package:http/http.dart'; -export 'package:http_interceptor/extensions/extensions.dart'; -export 'package:http_interceptor/http/http.dart'; -export 'package:http_interceptor/models/models.dart'; + +export './extensions/base_request.dart'; +export './extensions/base_response_none.dart' + if (dart.library.io) './extensions/base_response_io.dart'; +export './extensions/multipart_request.dart'; +export './extensions/request.dart'; +export './extensions/request.dart'; +export './extensions/response.dart'; +export './extensions/streamed_request.dart'; +export './extensions/streamed_response.dart'; +export './extensions/string.dart'; +export './extensions/uri.dart'; +export './http/http_methods.dart'; +export './http/intercepted_client.dart'; +export './http/intercepted_http.dart'; +export './models/http_interceptor_exception.dart'; +export './models/interceptor_contract.dart'; +export './models/retry_policy.dart'; diff --git a/lib/models/http_interceptor_exception.dart b/lib/models/http_interceptor_exception.dart index 1122d67..0c9d5b7 100644 --- a/lib/models/http_interceptor_exception.dart +++ b/lib/models/http_interceptor_exception.dart @@ -1,8 +1,9 @@ class HttpInterceptorException implements Exception { - final message; + final dynamic message; HttpInterceptorException([this.message]); + @override String toString() { if (message == null) return "Exception"; return "Exception: $message"; diff --git a/lib/http/interceptor_contract.dart b/lib/models/interceptor_contract.dart similarity index 89% rename from lib/http/interceptor_contract.dart rename to lib/models/interceptor_contract.dart index f3805be..a3dae81 100644 --- a/lib/http/interceptor_contract.dart +++ b/lib/models/interceptor_contract.dart @@ -26,7 +26,11 @@ import 'package:http/http.dart'; ///} ///``` abstract class InterceptorContract { + Future shouldInterceptRequest() async => true; + Future interceptRequest({required BaseRequest request}); + Future shouldInterceptResponse() async => true; + Future interceptResponse({required BaseResponse response}); } diff --git a/lib/models/models.dart b/lib/models/models.dart deleted file mode 100644 index b237781..0000000 --- a/lib/models/models.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'http_interceptor_exception.dart'; -export 'retry_policy.dart'; diff --git a/lib/utils/query_parameters.dart b/lib/utils/query_parameters.dart index 922faa2..2dc6ac4 100644 --- a/lib/utils/query_parameters.dart +++ b/lib/utils/query_parameters.dart @@ -6,7 +6,7 @@ String buildUrlString(String url, Map? parameters) { if (parameters == null) return url; // Check if there are parameters to add. - if (parameters.length > 0) { + if (parameters.isNotEmpty) { // Checks if the string url already has parameters. if (url.contains("?")) { url += "&"; diff --git a/pubspec.yaml b/pubspec.yaml index bac0ce8..fdb69d6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,8 @@ name: http_interceptor -description: A lightweight, simple plugin that allows you to intercept request and response objects and modify them if desired. -version: 2.0.0-beta.5 +description: + A lightweight, simple plugin that allows you to intercept request and response + objects and modify them if desired. +version: 2.0.0-beta.6 homepage: https://github.com/CodingAleCR/http_interceptor issue_tracker: https://github.com/CodingAleCR/http_interceptor/issues repository: https://github.com/CodingAleCR/http_interceptor @@ -12,5 +14,5 @@ dependencies: http: ^0.13.4 dev_dependencies: + flutter_lints: ^2.0.1 test: ^1.17.5 - effective_dart: ^1.3.0 diff --git a/test/extensions/request_test.dart b/test/extensions/request_test.dart index 8173f1a..28b5b59 100644 --- a/test/extensions/request_test.dart +++ b/test/extensions/request_test.dart @@ -82,7 +82,7 @@ main() { }); test('Request is copied with different method', () { // Arrange - final newMethod = HttpMethod.POST; + const newMethod = HttpMethod.POST; // Act Request copied = request.copyWith( @@ -239,7 +239,7 @@ main() { }); test('Request is copied with different followRedirects', () { // Arrange - final newFollowRedirects = false; + const newFollowRedirects = false; // Act Request copied = request.copyWith( @@ -263,7 +263,7 @@ main() { }); test('Request is copied with different maxRedirects', () { // Arrange - final newMaxRedirects = 2; + const newMaxRedirects = 2; // Act Request copied = request.copyWith( @@ -288,7 +288,7 @@ main() { test('Request is copied with different persistentConnection', () { // Arrange - final newPersistentConnection = false; + const newPersistentConnection = false; // Act Request copied = request.copyWith( From 604293e205dc57f73226a21a507224f01ad9c3b7 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Tue, 2 Aug 2022 23:35:03 -0600 Subject: [PATCH 2/8] docs: update v2 migration guide --- guides/migration_guide_2.0.0.md | 4 ++-- lib/http/http.dart | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 lib/http/http.dart diff --git a/guides/migration_guide_2.0.0.md b/guides/migration_guide_2.0.0.md index d05b113..16c241a 100644 --- a/guides/migration_guide_2.0.0.md +++ b/guides/migration_guide_2.0.0.md @@ -17,7 +17,7 @@ For interceptors you need to change the signature of the methods along with the v1.0.2 or lower ```dart -class WeatherApiInterceptor implements InterceptorContract { +class WeatherApiInterceptor extends InterceptorContract { @override Future interceptRequest({required RequestData data}) async { final cache = await SharedPreferences.getInstance(); @@ -37,7 +37,7 @@ class WeatherApiInterceptor implements InterceptorContract { v2.0.0 and up ```dart -class WeatherApiInterceptor implements InterceptorContract { +class WeatherApiInterceptor extends InterceptorContract { @override Future interceptRequest({required BaseRequest request}) async { final cache = await SharedPreferences.getInstance(); diff --git a/lib/http/http.dart b/lib/http/http.dart deleted file mode 100644 index c9e04dd..0000000 --- a/lib/http/http.dart +++ /dev/null @@ -1,4 +0,0 @@ -export '../models/interceptor_contract.dart'; -export 'http_methods.dart'; -export 'intercepted_client.dart'; -export 'intercepted_http.dart'; From a435988d77b838221873d62f5a4ea3c5ff7597a2 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Thu, 4 Aug 2022 08:23:59 -0600 Subject: [PATCH 3/8] feat: adds bodyBytes to Request.copyWith --- lib/extensions/request.dart | 37 ++++++++++++++++++++----------- test/extensions/request_test.dart | 31 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/lib/extensions/request.dart b/lib/extensions/request.dart index 24e7f95..4bcae8c 100644 --- a/lib/extensions/request.dart +++ b/lib/extensions/request.dart @@ -11,21 +11,32 @@ extension RequestCopyWith on Request { HttpMethod? method, Uri? url, Map? headers, - dynamic body, + String? body, + List? bodyBytes, Encoding? encoding, bool? followRedirects, int? maxRedirects, bool? persistentConnection, - }) => - Request( - method?.asString ?? this.method, - url ?? this.url, - ) - ..body = body ?? this.body - ..headers.addAll(headers ?? this.headers) - ..encoding = encoding ?? this.encoding - ..followRedirects = followRedirects ?? this.followRedirects - ..maxRedirects = maxRedirects ?? this.maxRedirects - ..persistentConnection = - persistentConnection ?? this.persistentConnection; + }) { + final copied = Request( + method?.asString ?? this.method, + url ?? this.url, + )..body = this.body; + + if (body != null) { + copied.body = body; + } + + if (bodyBytes != null) { + copied.bodyBytes = bodyBytes; + } + + return copied + ..headers.addAll(headers ?? this.headers) + ..encoding = encoding ?? this.encoding + ..followRedirects = followRedirects ?? this.followRedirects + ..maxRedirects = maxRedirects ?? this.maxRedirects + ..persistentConnection = + persistentConnection ?? this.persistentConnection; + } } diff --git a/test/extensions/request_test.dart b/test/extensions/request_test.dart index 28b5b59..1e8744b 100644 --- a/test/extensions/request_test.dart +++ b/test/extensions/request_test.dart @@ -206,6 +206,37 @@ main() { expect(copied.persistentConnection, equals(request.persistentConnection)); }); + test('Request is copied with GZip encoded body', () { + // Arrange + final gzip = GZipCodec(); + final newBody = + jsonDecode(request.body.isNotEmpty ? request.body : '{}') as Map; + newBody['hello'] = 'world'; + + // Act + final utfBytes = utf8.encode(jsonEncode(newBody)); + final gzipBytes = gzip.encode(utfBytes); + Request copied = request.copyWith( + body: base64.encode(gzipBytes), + ); + + // Assert + final decodedBody = utf8.decode(gzip.decode(base64.decode(copied.body))); + expect(copied.url, equals(request.url)); + expect(copied.method, equals(request.method)); + expect(copied.headers, equals(request.headers)); + expect( + decodedBody, + allOf([ + equals(jsonEncode(newBody)), + isNot(equals(request.body)), + ])); + expect(copied.encoding, equals(request.encoding)); + expect(copied.followRedirects, equals(request.followRedirects)); + expect(copied.maxRedirects, equals(request.maxRedirects)); + expect(copied.persistentConnection, equals(request.persistentConnection)); + }); + test('Request is copied with different encoding', () { // Arrange final newEncoding = Encoding.getByName('latin1'); From e3206849113cddb86e1d92274209fcfde6954c04 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Thu, 4 Aug 2022 08:24:26 -0600 Subject: [PATCH 4/8] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9aa44f..89b3125 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.0.0-beta.6 - ✨  Added: `Future shouldInterceptRequest()` and `Future shouldInterceptResponse()`. This enables individual interceptor checks and conditional intercepting configurations. +- ✨  Added: `bodyBytes` to `Request.copyWith`. This adds support to set and modify the body as a stream of bytes. - 📖  Changed: **example** project to showcase updated Flutter 3.0, new library APIs and `MultipartRequest` handling. ## 2.0.0-beta.5 From 065d522f8a9f499ef76c13587b5b9468f1be4dc2 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Wed, 10 Aug 2022 08:43:13 -0600 Subject: [PATCH 5/8] feat: refactored shouldAttemptRetryOnException to be async --- CHANGELOG.md | 1 + example/lib/weather_app.dart | 5 ++++- lib/http/intercepted_client.dart | 2 +- lib/models/retry_policy.dart | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89b3125..b0b12aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - ✨  Added: `Future shouldInterceptRequest()` and `Future shouldInterceptResponse()`. This enables individual interceptor checks and conditional intercepting configurations. - ✨  Added: `bodyBytes` to `Request.copyWith`. This adds support to set and modify the body as a stream of bytes. +- ❗️🛠  Changed: `RetryPolicy` to be `Future` instead of `bool` so that you can support different exception retrying scenarios (See #115). - 📖  Changed: **example** project to showcase updated Flutter 3.0, new library APIs and `MultipartRequest` handling. ## 2.0.0-beta.5 diff --git a/example/lib/weather_app.dart b/example/lib/weather_app.dart index e37eeab..41a20f5 100644 --- a/example/lib/weather_app.dart +++ b/example/lib/weather_app.dart @@ -335,7 +335,10 @@ class ExpiredTokenRetryPolicy extends RetryPolicy { int get maxRetryAttempts => 2; @override - bool shouldAttemptRetryOnException(Exception reason, BaseRequest request) { + Future shouldAttemptRetryOnException( + Exception reason, + BaseRequest request, + ) async { log(reason.toString()); return false; diff --git a/lib/http/intercepted_client.dart b/lib/http/intercepted_client.dart index 6193ed1..d021b63 100644 --- a/lib/http/intercepted_client.dart +++ b/lib/http/intercepted_client.dart @@ -290,7 +290,7 @@ class InterceptedClient extends BaseClient { } on Exception catch (error) { if (retryPolicy != null && retryPolicy!.maxRetryAttempts > _retryCount && - retryPolicy!.shouldAttemptRetryOnException(error, request)) { + await retryPolicy!.shouldAttemptRetryOnException(error, request)) { _retryCount += 1; return _attemptRequest(request); } else { diff --git a/lib/models/retry_policy.dart b/lib/models/retry_policy.dart index 250d6e2..ef1783c 100644 --- a/lib/models/retry_policy.dart +++ b/lib/models/retry_policy.dart @@ -36,7 +36,8 @@ import 'package:http/http.dart'; abstract class RetryPolicy { /// Defines whether the request should be retried when an Exception occurs /// while making said request to the server. - bool shouldAttemptRetryOnException(Exception reason, BaseRequest request) => + Future shouldAttemptRetryOnException( + Exception reason, BaseRequest request) async => false; /// Defines whether the request should be retried after the request has From 6ff22b75f4934be87d62e2b524e0955548947142 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Wed, 10 Aug 2022 09:56:55 -0600 Subject: [PATCH 6/8] fix: multipart app example --- example/lib/multipart_app.dart | 32 ++++++++++++++++---------------- example/pubspec.yaml | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/example/lib/multipart_app.dart b/example/lib/multipart_app.dart index f7cd553..9bbc575 100644 --- a/example/lib/multipart_app.dart +++ b/example/lib/multipart_app.dart @@ -1,7 +1,6 @@ import 'dart:developer'; import 'dart:io'; import 'dart:typed_data'; -import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:http_interceptor/http_interceptor.dart'; @@ -32,7 +31,7 @@ class _MultipartAppState extends State { final ImagePicker _picker = ImagePicker(); XFile? pickedImage; - ui.Image? noBgImage; + Uint8List? noBgImage; Future _onUpload() async { if (pickedImage == null) return; @@ -91,14 +90,15 @@ class _MultipartAppState extends State { ), if (pickedImage != null) ...[ const Text('Before'), - Image.file(File(pickedImage!.path)), + Image.file( + File(pickedImage!.path), + ), ], if (noBgImage != null) ...[ const Text('After'), - RawImage( - image: noBgImage!, // this is a dart:ui Image object - scale: 1.0, - ), + Image.memory( + noBgImage!, + ) ], ], ), @@ -115,11 +115,11 @@ class RemoveBgRepository { RemoveBgRepository(this.client); - Future removeImageBackground( + Future removeImageBackground( XFile imgFile, String fieldName, ) async { - ui.Image parsedResponse; + Uint8List parsedResponse; try { final req = MultipartRequest( HttpMethod.POST.asString, @@ -131,21 +131,21 @@ class RemoveBgRepository { ), ); - final response = await client.send(req); - if (response.statusCode == 200) { - final respBytes = await response.stream.first; - final image = await decodeImageFromList(Uint8List.fromList(respBytes)); + final streamResponse = await client.send(req); + final response = await Response.fromStream(streamResponse); - parsedResponse = image; + if (response.statusCode == 200) { + parsedResponse = response.bodyBytes; } else { return Future.error( 'Error while fetching.', - StackTrace.fromString(''), + StackTrace.fromString('Response was not 200.'), ); } } on SocketException { return Future.error('No Internet connection 😑'); - } on FormatException { + } on FormatException catch (error) { + log(error.toString()); return Future.error('Bad response format 👎'); } on Exception catch (error) { log(error.toString()); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 77bbb8e..03f5902 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,6 @@ dependencies: sdk: flutter http_interceptor: path: ../ - http_parser: ^4.0.1 image_picker: ^0.8.5+3 shared_preferences: ^2.0.6 From e0a4b4a7c398085ca61a5e905f4cfc4d2222a0ab Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Wed, 10 Aug 2022 10:11:38 -0600 Subject: [PATCH 7/8] test: fix retry policy tests --- test/models/retry_policy_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/models/retry_policy_test.dart b/test/models/retry_policy_test.dart index 80b4c7a..a9647bc 100644 --- a/test/models/retry_policy_test.dart +++ b/test/models/retry_policy_test.dart @@ -15,9 +15,9 @@ main() { }); group("shouldAttemptRetryOnException", () { - test("returns false by default", () { + test("returns false by default", () async { expect( - testObject.shouldAttemptRetryOnException( + await testObject.shouldAttemptRetryOnException( Exception("Test Exception."), Request( 'GET', From 29795aa511cc506abd5e233c13bc0d3d4a0acc75 Mon Sep 17 00:00:00 2001 From: Alejandro Ulate Date: Wed, 10 Aug 2022 10:11:50 -0600 Subject: [PATCH 8/8] docs: update migration docs --- guides/migration_guide_2.0.0.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/guides/migration_guide_2.0.0.md b/guides/migration_guide_2.0.0.md index 16c241a..99a1b62 100644 --- a/guides/migration_guide_2.0.0.md +++ b/guides/migration_guide_2.0.0.md @@ -106,3 +106,17 @@ class ExpiredTokenRetryPolicy extends RetryPolicy { } } ``` + +If you are using `shouldAttemptRetryOnException` then you will also have to convert the signature to be async like the following: + +```dart +@override +Future shouldAttemptRetryOnException( + Exception reason, + BaseRequest request, +) async { + log(reason.toString()); + + return false; +} +```