geocoder 1.2.5 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +83 -8
- data/lib/geocoder/ip_address.rb +11 -2
- data/lib/geocoder/lookup.rb +4 -0
- data/lib/geocoder/lookups/geoip2.rb +40 -0
- data/lib/geocoder/lookups/google_places_details.rb +50 -0
- data/lib/geocoder/lookups/maxmind_local.rb +1 -1
- data/lib/geocoder/lookups/okf.rb +43 -0
- data/lib/geocoder/lookups/postcode_anywhere_uk.rb +51 -0
- data/lib/geocoder/lookups/smarty_streets.rb +1 -1
- data/lib/geocoder/results/geoip2.rb +64 -0
- data/lib/geocoder/results/google_places_details.rb +35 -0
- data/lib/geocoder/results/okf.rb +106 -0
- data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
- data/lib/geocoder/results/test.rb +1 -1
- data/lib/geocoder/stores/active_record.rb +22 -11
- data/lib/geocoder/version.rb +1 -1
- data/test/fixtures/google_places_details_invalid_request +4 -0
- data/test/fixtures/google_places_details_madison_square_garden +120 -0
- data/test/fixtures/google_places_details_no_results +4 -0
- data/test/fixtures/google_places_details_no_reviews +60 -0
- data/test/fixtures/google_places_details_no_types +66 -0
- data/test/fixtures/okf_kirstinmaki +67 -0
- data/test/fixtures/okf_no_results +4 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +1 -0
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +1 -0
- data/test/test_helper.rb +44 -0
- data/test/unit/cache_test.rb +1 -1
- data/test/unit/error_handling_test.rb +3 -3
- data/test/unit/ip_address_test.rb +3 -0
- data/test/unit/lookup_test.rb +1 -1
- data/test/unit/lookups/geoip2_test.rb +27 -0
- data/test/unit/lookups/google_places_details_test.rb +122 -0
- data/test/unit/lookups/okf_test.rb +38 -0
- data/test/unit/lookups/postcode_anywhere_uk_test.rb +70 -0
- data/test/unit/query_test.rb +1 -0
- data/test/unit/test_mode_test.rb +1 -1
- metadata +28 -2
@@ -0,0 +1,35 @@
|
|
1
|
+
require "geocoder/results/google"
|
2
|
+
|
3
|
+
module Geocoder
|
4
|
+
module Result
|
5
|
+
class GooglePlacesDetails < Google
|
6
|
+
def place_id
|
7
|
+
@data["place_id"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def types
|
11
|
+
@data["types"] || []
|
12
|
+
end
|
13
|
+
|
14
|
+
def reviews
|
15
|
+
@data["reviews"] || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def rating
|
19
|
+
@data["rating"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def rating_count
|
23
|
+
@data["user_ratings_total"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def phone_number
|
27
|
+
@data["international_phone_number"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def website
|
31
|
+
@data["website"]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class Okf < Base
|
5
|
+
|
6
|
+
def coordinates
|
7
|
+
['lat', 'lng'].map{ |i| geometry['location'][i] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def address(format = :full)
|
11
|
+
formatted_address
|
12
|
+
end
|
13
|
+
|
14
|
+
def city
|
15
|
+
fields = [:locality, :sublocality,
|
16
|
+
:administrative_area_level_3,
|
17
|
+
:administrative_area_level_2]
|
18
|
+
fields.each do |f|
|
19
|
+
if entity = address_components_of_type(f).first
|
20
|
+
return entity['long_name']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
return nil # no appropriate components found
|
24
|
+
end
|
25
|
+
|
26
|
+
def state
|
27
|
+
""
|
28
|
+
end
|
29
|
+
|
30
|
+
def sub_state
|
31
|
+
""
|
32
|
+
end
|
33
|
+
|
34
|
+
def state_code
|
35
|
+
""
|
36
|
+
end
|
37
|
+
|
38
|
+
def country
|
39
|
+
if country = address_components_of_type(:country).first
|
40
|
+
country['long_name']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def country_code
|
45
|
+
if country = address_components_of_type(:country).first
|
46
|
+
country['short_name']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def postal_code
|
51
|
+
if postal = address_components_of_type(:postal_code).first
|
52
|
+
postal['long_name']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def route
|
57
|
+
if route = address_components_of_type(:route).first
|
58
|
+
route['long_name']
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def street_number
|
63
|
+
if street_number = address_components_of_type(:street_number).first
|
64
|
+
street_number['long_name']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def street_address
|
69
|
+
[route, street_number].compact.join(' ')
|
70
|
+
end
|
71
|
+
|
72
|
+
def types
|
73
|
+
@data['types']
|
74
|
+
end
|
75
|
+
|
76
|
+
def formatted_address
|
77
|
+
@data['formatted_address']
|
78
|
+
end
|
79
|
+
|
80
|
+
def address_components
|
81
|
+
@data['address_components']
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Get address components of a given type. Valid types are defined in
|
86
|
+
# Google's Geocoding API documentation and include (among others):
|
87
|
+
#
|
88
|
+
# :street_number
|
89
|
+
# :locality
|
90
|
+
# :neighborhood
|
91
|
+
# :route
|
92
|
+
# :postal_code
|
93
|
+
#
|
94
|
+
def address_components_of_type(type)
|
95
|
+
address_components.select{ |c| c['types'].include?(type.to_s) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def geometry
|
99
|
+
@data['geometry']
|
100
|
+
end
|
101
|
+
|
102
|
+
def precision
|
103
|
+
geometry['location_type'] if geometry
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class PostcodeAnywhereUk < Base
|
5
|
+
|
6
|
+
def coordinates
|
7
|
+
[@data['Latitude'].to_f, @data['Longitude'].to_f]
|
8
|
+
end
|
9
|
+
|
10
|
+
def blank_result
|
11
|
+
''
|
12
|
+
end
|
13
|
+
alias_method :state, :blank_result
|
14
|
+
alias_method :state_code, :blank_result
|
15
|
+
alias_method :postal_code, :blank_result
|
16
|
+
|
17
|
+
def address
|
18
|
+
@data['Location']
|
19
|
+
end
|
20
|
+
|
21
|
+
def city
|
22
|
+
# is this too big a jump to assume that the API always
|
23
|
+
# returns a City, County as the last elements?
|
24
|
+
city = @data['Location'].split(',')[-2] || blank_result
|
25
|
+
city.strip
|
26
|
+
end
|
27
|
+
|
28
|
+
def os_grid
|
29
|
+
@data['OsGrid']
|
30
|
+
end
|
31
|
+
|
32
|
+
# This is a UK only API; all results are UK specific and
|
33
|
+
# so ommitted from API response.
|
34
|
+
def country
|
35
|
+
'United Kingdom'
|
36
|
+
end
|
37
|
+
|
38
|
+
def country_code
|
39
|
+
'UK'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -18,14 +18,14 @@ module Geocoder::Store
|
|
18
18
|
|
19
19
|
# scope: geocoded objects
|
20
20
|
scope :geocoded, lambda {
|
21
|
-
where("#{geocoder_options[:latitude]} IS NOT NULL " +
|
22
|
-
"AND #{geocoder_options[:longitude]} IS NOT NULL")
|
21
|
+
where("#{table_name}.#{geocoder_options[:latitude]} IS NOT NULL " +
|
22
|
+
"AND #{table_name}.#{geocoder_options[:longitude]} IS NOT NULL")
|
23
23
|
}
|
24
24
|
|
25
25
|
# scope: not-geocoded objects
|
26
26
|
scope :not_geocoded, lambda {
|
27
|
-
where("#{geocoder_options[:latitude]} IS NULL " +
|
28
|
-
"OR #{geocoder_options[:longitude]} IS NULL")
|
27
|
+
where("#{table_name}.#{geocoder_options[:latitude]} IS NULL " +
|
28
|
+
"OR #{table_name}.#{geocoder_options[:longitude]} IS NULL")
|
29
29
|
}
|
30
30
|
|
31
31
|
##
|
@@ -45,7 +45,7 @@ module Geocoder::Store
|
|
45
45
|
# If no lat/lon given we don't want any results, but we still
|
46
46
|
# need distance and bearing columns so you can add, for example:
|
47
47
|
# .order("distance")
|
48
|
-
select(select_clause(nil,
|
48
|
+
select(select_clause(nil, null_value, null_value)).where(false_condition)
|
49
49
|
end
|
50
50
|
}
|
51
51
|
|
@@ -64,7 +64,7 @@ module Geocoder::Store
|
|
64
64
|
full_column_name(geocoder_options[:longitude])
|
65
65
|
))
|
66
66
|
else
|
67
|
-
select(select_clause(nil,
|
67
|
+
select(select_clause(nil, null_value, null_value)).where(false_condition)
|
68
68
|
end
|
69
69
|
}
|
70
70
|
end
|
@@ -107,7 +107,7 @@ module Geocoder::Store
|
|
107
107
|
# * +:exclude+ - an object to exclude (used by the +nearbys+ method)
|
108
108
|
# * +:distance_column+ - used to set the column name of the calculated distance.
|
109
109
|
# * +:bearing_column+ - used to set the column name of the calculated bearing.
|
110
|
-
# * +:min_radius+ - the value to use as the minimum radius.
|
110
|
+
# * +:min_radius+ - the value to use as the minimum radius.
|
111
111
|
# ignored if database is sqlite.
|
112
112
|
# default is 0.0
|
113
113
|
#
|
@@ -118,13 +118,13 @@ module Geocoder::Store
|
|
118
118
|
latitude_attribute = options[:latitude] || geocoder_options[:latitude]
|
119
119
|
longitude_attribute = options[:longitude] || geocoder_options[:longitude]
|
120
120
|
options[:units] ||= (geocoder_options[:units] || Geocoder.config.units)
|
121
|
-
select_distance = options.fetch(:select_distance
|
121
|
+
select_distance = options.fetch(:select_distance) { true }
|
122
122
|
options[:order] = "" if !select_distance && !options.include?(:order)
|
123
|
-
select_bearing = options.fetch(:select_bearing
|
123
|
+
select_bearing = options.fetch(:select_bearing) { true }
|
124
124
|
bearing = bearing_sql(latitude, longitude, options)
|
125
125
|
distance = distance_sql(latitude, longitude, options)
|
126
|
-
distance_column = options.fetch(:distance_column
|
127
|
-
bearing_column = options.fetch(:bearing_column
|
126
|
+
distance_column = options.fetch(:distance_column) { 'distance' }
|
127
|
+
bearing_column = options.fetch(:bearing_column) { 'bearing' }
|
128
128
|
|
129
129
|
b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
|
130
130
|
args = b + [
|
@@ -224,6 +224,17 @@ module Geocoder::Store
|
|
224
224
|
connection.adapter_name.match(/sqlite/i)
|
225
225
|
end
|
226
226
|
|
227
|
+
def using_postgres?
|
228
|
+
connection.adapter_name.match(/postgres/i)
|
229
|
+
end
|
230
|
+
|
231
|
+
##
|
232
|
+
# Use OID type when running in PosgreSQL
|
233
|
+
#
|
234
|
+
def null_value
|
235
|
+
using_postgres? ? 'NULL::text' : 'NULL'
|
236
|
+
end
|
237
|
+
|
227
238
|
##
|
228
239
|
# Value which can be passed to where() to produce no results.
|
229
240
|
#
|
data/lib/geocoder/version.rb
CHANGED
@@ -0,0 +1,120 @@
|
|
1
|
+
{
|
2
|
+
"html_attributions" : [],
|
3
|
+
"result" : {
|
4
|
+
"address_components" : [
|
5
|
+
{
|
6
|
+
"long_name" : "4",
|
7
|
+
"short_name" : "4",
|
8
|
+
"types" : [ "street_number" ]
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"long_name" : "Pennsylvania Plaza",
|
12
|
+
"short_name" : "Pennsylvania Plaza",
|
13
|
+
"types" : [ "route" ]
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"long_name" : "Chelsea",
|
17
|
+
"short_name" : "Chelsea",
|
18
|
+
"types" : [ "neighborhood", "political" ]
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"long_name" : "Manhattan",
|
22
|
+
"short_name" : "Manhattan",
|
23
|
+
"types" : [ "sublocality_level_1", "sublocality", "political" ]
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"long_name" : "New York",
|
27
|
+
"short_name" : "New York",
|
28
|
+
"types" : [ "locality", "political" ]
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"long_name" : "New York County",
|
32
|
+
"short_name" : "New York County",
|
33
|
+
"types" : [ "administrative_area_level_2", "political" ]
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"long_name" : "NY",
|
37
|
+
"short_name" : "NY",
|
38
|
+
"types" : [ "administrative_area_level_1", "political" ]
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"long_name" : "United States",
|
42
|
+
"short_name" : "US",
|
43
|
+
"types" : [ "country", "political" ]
|
44
|
+
},
|
45
|
+
{
|
46
|
+
"long_name" : "10001",
|
47
|
+
"short_name" : "10001",
|
48
|
+
"types" : [ "postal_code" ]
|
49
|
+
}
|
50
|
+
],
|
51
|
+
"adr_address" : "\u003cspan class=\"street-address\"\u003e4 Pennsylvania Plaza\u003c/span\u003e, \u003cspan class=\"locality\"\u003eNew York\u003c/span\u003e, \u003cspan class=\"region\"\u003eNY\u003c/span\u003e \u003cspan class=\"postal-code\"\u003e10001\u003c/span\u003e, \u003cspan class=\"country-name\"\u003eUnited States\u003c/span\u003e",
|
52
|
+
"formatted_address" : "4 Pennsylvania Plaza, New York, NY, United States",
|
53
|
+
"formatted_phone_number" : "(212) 465-6741",
|
54
|
+
"geometry" : {
|
55
|
+
"location" : {
|
56
|
+
"lat" : 40.750504,
|
57
|
+
"lng" : -73.993439
|
58
|
+
}
|
59
|
+
},
|
60
|
+
"icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/stadium-71.png",
|
61
|
+
"id" : "55e3174d410b31da010030a7dfc0c9819027445a",
|
62
|
+
"international_phone_number" : "+1 212-465-6741",
|
63
|
+
"name" : "Madison Square Garden",
|
64
|
+
"photos" : [
|
65
|
+
{
|
66
|
+
"height" : 267,
|
67
|
+
"html_attributions" : [ "Someone" ],
|
68
|
+
"photo_reference" : "CnRoAAAAB1lz_vOkA1Ffaf7vJ1xcjzVsII-873Z_f8_v3EyW4XbEvlR3VkW_HvNfwF6AwDA0U-ont7fIUqEMyDcovCTWN8RSYN3ibEhqgJPvXxBjeYVi0cc-t-3KfkB_LpV7chPAqhOsdMG56kyzTKIo4lISHxIQqru7QXV6xU11jLaLpi4FNRoUhutg9aq027NghW1d-o9GGE8N3yM",
|
69
|
+
"width" : 400
|
70
|
+
},
|
71
|
+
{
|
72
|
+
"height" : 732,
|
73
|
+
"html_attributions" : [ "Someone else" ],
|
74
|
+
"photo_reference" : "CoQBfwAAADbYj554hM1BgVbBOs6rDjO9UtQ63ecU1P8tI3PfaHame3MB4ipgcNRlv9N2iUa-tXoMq9iXAaDStWgCJ3f48WIuIRbz-Xv-HzSJ0hMCrFiZMRs7kLgaBO7eDJwioTySWcoyAwojretq4mZKF_AcRSUhkqOokBhOstmshWWpSAyyEhAdpL2yp42xDNq2YRiFrx4DGhRZIdt7mochSwZcgSdjESea27Qy9Q",
|
75
|
+
"width" : 929
|
76
|
+
}
|
77
|
+
],
|
78
|
+
"place_id" : "ChIJhRwB-yFawokR5Phil-QQ3zM",
|
79
|
+
"rating" : 4.4,
|
80
|
+
"reference" : "CnRuAAAArSB-mFxXRjm0ERZIC4c_1gbXwxqmyxUrxws_PQUrz9Y3xZstEwm7_8dLw7zM8hV3vWkPF4RkkZQQ_X01ikDALx2VgV60YwiSX7k3TXxkWnzyFcX0fnHCQLerlYttk_usL7UALQQgMeuf25_eFx3SnhIQxN95Ek3bQVuLVM16yb99ehoU7djcL3cjllohLZ6oJ6X3Tzb9MJQ",
|
81
|
+
"reviews" : [
|
82
|
+
{
|
83
|
+
"aspects" : [
|
84
|
+
{
|
85
|
+
"rating" : 5,
|
86
|
+
"type" : "overall"
|
87
|
+
}
|
88
|
+
],
|
89
|
+
"author_name" : "John Smith",
|
90
|
+
"author_url" : "https://plus.google.com/john.smith",
|
91
|
+
"language" : "en",
|
92
|
+
"rating" : 5,
|
93
|
+
"text" : "It's nice.",
|
94
|
+
"time" : 1407266916
|
95
|
+
},
|
96
|
+
{
|
97
|
+
"aspects" : [
|
98
|
+
{
|
99
|
+
"rating" : 2,
|
100
|
+
"type" : "overall"
|
101
|
+
}
|
102
|
+
],
|
103
|
+
"author_name" : "Jane Smith",
|
104
|
+
"author_url" : "https://plus.google.com/jane.smith",
|
105
|
+
"language" : "en",
|
106
|
+
"rating" : 2,
|
107
|
+
"text" : "Not so nice.",
|
108
|
+
"time" : 1398779079
|
109
|
+
}
|
110
|
+
],
|
111
|
+
"scope" : "GOOGLE",
|
112
|
+
"types" : [ "stadium", "establishment" ],
|
113
|
+
"url" : "https://plus.google.com/112180896421099179463/about?hl=en-US",
|
114
|
+
"user_ratings_total" : 382,
|
115
|
+
"utc_offset" : -240,
|
116
|
+
"vicinity" : "4 Pennsylvania Plaza, New York",
|
117
|
+
"website" : "http://www.thegarden.com/"
|
118
|
+
},
|
119
|
+
"status" : "OK"
|
120
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
{
|
2
|
+
"html_attributions" : [],
|
3
|
+
"result" : {
|
4
|
+
"address_components" : [
|
5
|
+
{
|
6
|
+
"long_name" : "25",
|
7
|
+
"short_name" : "25",
|
8
|
+
"types" : [ "street_number" ]
|
9
|
+
},
|
10
|
+
{
|
11
|
+
"long_name" : "Oranienstraße",
|
12
|
+
"short_name" : "Oranienstraße",
|
13
|
+
"types" : [ "route" ]
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"long_name" : "Friedrichshain-Kreuzberg",
|
17
|
+
"short_name" : "Friedrichshain-Kreuzberg",
|
18
|
+
"types" : [ "sublocality_level_1", "sublocality", "political" ]
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"long_name" : "Berlin",
|
22
|
+
"short_name" : "Berlin",
|
23
|
+
"types" : [ "locality", "political" ]
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"long_name" : "Berlin",
|
27
|
+
"short_name" : "Berlin",
|
28
|
+
"types" : [ "administrative_area_level_1", "political" ]
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"long_name" : "Germany",
|
32
|
+
"short_name" : "DE",
|
33
|
+
"types" : [ "country", "political" ]
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"long_name" : "10999",
|
37
|
+
"short_name" : "10999",
|
38
|
+
"types" : [ "postal_code" ]
|
39
|
+
}
|
40
|
+
],
|
41
|
+
"adr_address" : "\u003cspan class=\"street-address\"\u003eOranienstraße 25\u003c/span\u003e, \u003cspan class=\"postal-code\"\u003e10999\u003c/span\u003e \u003cspan class=\"locality\"\u003eBerlin\u003c/span\u003e, \u003cspan class=\"country-name\"\u003eGermany\u003c/span\u003e",
|
42
|
+
"formatted_address" : "Oranienstraße 25, 10999 Berlin, Germany",
|
43
|
+
"geometry" : {
|
44
|
+
"location" : {
|
45
|
+
"lat" : 52.5010652,
|
46
|
+
"lng" : 13.4206563
|
47
|
+
}
|
48
|
+
},
|
49
|
+
"icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png",
|
50
|
+
"id" : "b49e917abd41c247425645a6ac3e5a6756ad80f8",
|
51
|
+
"name" : "Oranienstraße 25",
|
52
|
+
"place_id" : "ChIJQ8-HeTROqEcRGdCTErYy5D0",
|
53
|
+
"reference" : "CpQBjAAAAKrbnaAglhQLI6KPs3EbRp1lVh5UkB4xLEyzOmvvGmtpmwD2EAnlokKcx1VU5PvvB7moRGw6lHTlMTScpGL3GTCC_WM2pzDxgeaAtoB-SR4YQ7PRhHkT2eqxACbaP_70Z9Wyb2J31tG66xBrYASAuBzXgEXYaFpo8dhRBY4xMTfexvMziw6rHs01SxLhCFh-uBIQBQcGVz70_HtaG_g6ZZ5omhoUdIDDSVApRiVoIh61NiCzStYa-x0",
|
54
|
+
"scope" : "GOOGLE",
|
55
|
+
"types" : [ "street_address" ],
|
56
|
+
"url" : "https://maps.google.com/maps/place?q=Oranienstra%C3%9Fe+25,+10999+Berlin,+Germany&ftid=0x47a84e347987cf43:0x3de432b61293d019",
|
57
|
+
"vicinity" : "Friedrichshain-Kreuzberg"
|
58
|
+
},
|
59
|
+
"status" : "OK"
|
60
|
+
}
|