geocoder 1.1.8 → 1.1.9

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.

Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +4 -0
  3. data/CHANGELOG.md +13 -1
  4. data/README.md +100 -30
  5. data/Rakefile +1 -1
  6. data/examples/autoexpire_cache_dalli.rb +2 -2
  7. data/examples/cache_bypass.rb +48 -0
  8. data/lib/geocoder/calculations.rb +38 -0
  9. data/lib/geocoder/cli.rb +8 -1
  10. data/lib/geocoder/lookup.rb +3 -0
  11. data/lib/geocoder/lookups/baidu.rb +54 -0
  12. data/lib/geocoder/lookups/base.rb +26 -11
  13. data/lib/geocoder/lookups/dstk.rb +20 -0
  14. data/lib/geocoder/lookups/freegeoip.rb +2 -6
  15. data/lib/geocoder/lookups/geocoder_us.rb +39 -0
  16. data/lib/geocoder/lookups/google.rb +5 -0
  17. data/lib/geocoder/lookups/mapquest.rb +21 -5
  18. data/lib/geocoder/lookups/maxmind.rb +1 -1
  19. data/lib/geocoder/lookups/nominatim.rb +0 -1
  20. data/lib/geocoder/lookups/ovi.rb +14 -4
  21. data/lib/geocoder/query.rb +5 -1
  22. data/lib/geocoder/results/baidu.rb +79 -0
  23. data/lib/geocoder/results/dstk.rb +6 -0
  24. data/lib/geocoder/results/geocoder_us.rb +39 -0
  25. data/lib/geocoder/results/yandex.rb +1 -1
  26. data/lib/geocoder/stores/active_record.rb +12 -6
  27. data/lib/geocoder/stores/mongo_base.rb +5 -2
  28. data/lib/geocoder/version.rb +1 -1
  29. data/lib/tasks/geocoder.rake +2 -0
  30. data/test/cache_test.rb +16 -0
  31. data/test/calculations_test.rb +31 -21
  32. data/test/fixtures/baidu_invalid_key +1 -0
  33. data/test/fixtures/baidu_no_results +1 -0
  34. data/test/fixtures/baidu_reverse +1 -0
  35. data/test/fixtures/baidu_shanghai_pearl_tower +12 -0
  36. data/test/fixtures/geocoder_us_madison_square_garden +1 -0
  37. data/test/fixtures/geocoder_us_no_results +1 -0
  38. data/test/fixtures/google_over_limit +4 -0
  39. data/test/fixtures/mapquest_error +16 -0
  40. data/test/fixtures/mapquest_invalid_api_key +16 -0
  41. data/test/fixtures/mapquest_invalid_request +16 -0
  42. data/test/fixtures/mapquest_no_results +10 -1
  43. data/test/mongoid_test.rb +7 -0
  44. data/test/near_test.rb +18 -0
  45. data/test/proxy_test.rb +13 -0
  46. data/test/query_test.rb +5 -0
  47. data/test/services_test.rb +75 -2
  48. data/test/test_helper.rb +16 -6
  49. metadata +24 -9
@@ -12,7 +12,7 @@ module Geocoder::Result
12
12
  end
13
13
 
14
14
  def city
15
- if state.empty?
15
+ if state.empty? and address_details.has_key? 'Locality'
16
16
  address_details['Locality']['LocalityName']
17
17
  elsif sub_state.empty?
18
18
  address_details['AdministrativeArea']['Locality']['LocalityName']
@@ -32,7 +32,7 @@ module Geocoder::Store
32
32
  # Find all objects within a radius of the given location.
33
33
  # Location may be either a string to geocode or an array of
34
34
  # coordinates (<tt>[lat,lon]</tt>). Also takes an options hash
35
- # (see Geocoder::Orm::ActiveRecord::ClassMethods.near_scope_options
35
+ # (see Geocoder::Store::ActiveRecord::ClassMethods.near_scope_options
36
36
  # for details).
37
37
  #
38
38
  scope :near, lambda{ |location, *args|
@@ -105,6 +105,8 @@ module Geocoder::Store
105
105
  # * +:order+ - column(s) for ORDER BY SQL clause; default is distance;
106
106
  # set to false or nil to omit the ORDER BY clause
107
107
  # * +:exclude+ - an object to exclude (used by the +nearbys+ method)
108
+ # * +:distance_column+ - used to set the column name of the calculated distance.
109
+ # * +:bearing_column+ - used to set the column name of the calculated bearing.
108
110
  #
109
111
  def near_scope_options(latitude, longitude, radius = 20, options = {})
110
112
  if options[:units]
@@ -116,6 +118,8 @@ module Geocoder::Store
116
118
  select_bearing = options.fetch(:select_bearing, true)
117
119
  bearing = bearing_sql(latitude, longitude, options)
118
120
  distance = distance_sql(latitude, longitude, options)
121
+ distance_column = options.fetch(:distance_column, 'distance')
122
+ bearing_column = options.fetch(:bearing_column, 'bearing')
119
123
 
120
124
  b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
121
125
  args = b + [
@@ -132,9 +136,11 @@ module Geocoder::Store
132
136
  {
133
137
  :select => select_clause(options[:select],
134
138
  select_distance ? distance : nil,
135
- select_bearing ? bearing : nil),
139
+ select_bearing ? bearing : nil,
140
+ distance_column,
141
+ bearing_column),
136
142
  :conditions => add_exclude_condition(conditions, options[:exclude]),
137
- :order => options.include?(:order) ? options[:order] : "distance ASC"
143
+ :order => options.include?(:order) ? options[:order] : "#{distance_column} ASC"
138
144
  }
139
145
  end
140
146
 
@@ -176,7 +182,7 @@ module Geocoder::Store
176
182
  ##
177
183
  # Generate the SELECT clause.
178
184
  #
179
- def select_clause(columns, distance = nil, bearing = nil)
185
+ def select_clause(columns, distance = nil, bearing = nil, distance_column = 'distance', bearing_column = 'bearing')
180
186
  if columns == :id_only
181
187
  return full_column_name(primary_key)
182
188
  elsif columns == :geo_only
@@ -186,11 +192,11 @@ module Geocoder::Store
186
192
  end
187
193
  if distance
188
194
  clause += ", " unless clause.empty?
189
- clause += "#{distance} AS distance"
195
+ clause += "#{distance} AS #{distance_column}"
190
196
  end
191
197
  if bearing
192
198
  clause += ", " unless clause.empty?
193
- clause += "#{bearing} AS bearing"
199
+ clause += "#{bearing} AS #{bearing_column}"
194
200
  end
195
201
  clause
196
202
  end
@@ -31,8 +31,11 @@ module Geocoder::Store
31
31
  field = geocoder_options[:coordinates]
32
32
  conds[field] = empty.clone
33
33
  conds[field]["$nearSphere"] = coords.reverse
34
- conds[field]["$maxDistance"] = \
35
- Geocoder::Calculations.distance_to_radians(radius, options[:units])
34
+
35
+ if radius
36
+ conds[field]["$maxDistance"] = \
37
+ Geocoder::Calculations.distance_to_radians(radius, options[:units])
38
+ end
36
39
 
37
40
  if obj = options[:exclude]
38
41
  conds[:_id.ne] = obj.id
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.1.8"
2
+ VERSION = "1.1.9"
3
3
  end
@@ -2,11 +2,13 @@ namespace :geocode do
2
2
  desc "Geocode all objects without coordinates."
3
3
  task :all => :environment do
4
4
  class_name = ENV['CLASS'] || ENV['class']
5
+ sleep_timer = ENV['SLEEP'] || ENV['sleep']
5
6
  raise "Please specify a CLASS (model)" unless class_name
6
7
  klass = class_from_string(class_name)
7
8
 
8
9
  klass.not_geocoded.each do |obj|
9
10
  obj.geocode; obj.save
11
+ sleep(sleep_timer.to_f) unless sleep_timer.nil?
10
12
  end
11
13
  end
12
14
  end
data/test/cache_test.rb CHANGED
@@ -16,4 +16,20 @@ class CacheTest < Test::Unit::TestCase
16
16
  "Lookup #{l} did not return cached result."
17
17
  end
18
18
  end
19
+
20
+ def test_google_over_query_limit_does_not_hit_cache
21
+ Geocoder.configure(:cache => {})
22
+ Geocoder.configure(:lookup => :google)
23
+ set_api_key!(:google)
24
+ Geocoder.configure(:always_raise => :all)
25
+ assert_raises Geocoder::OverQueryLimitError do
26
+ Geocoder.search("over limit")
27
+ end
28
+ lookup = Geocoder::Lookup.get(:google)
29
+ assert_equal false, lookup.instance_variable_get(:@cache_hit)
30
+ assert_raises Geocoder::OverQueryLimitError do
31
+ Geocoder.search("over limit")
32
+ end
33
+ assert_equal false, lookup.instance_variable_get(:@cache_hit)
34
+ end
19
35
  end
@@ -100,6 +100,17 @@ class CalculationsTest < Test::Unit::TestCase
100
100
  end
101
101
  end
102
102
 
103
+ # --- random point ---
104
+
105
+ def test_random_point_within_radius
106
+ 20.times do
107
+ center = [51, 7] # Cologne, DE
108
+ radius = 10 # miles
109
+ random_point = Geocoder::Calculations.random_point_near(center, radius)
110
+ distance = Geocoder::Calculations.distance_between(center, random_point)
111
+ assert distance <= radius
112
+ end
113
+ end
103
114
 
104
115
  # --- bearing ---
105
116
 
@@ -157,32 +168,28 @@ class CalculationsTest < Test::Unit::TestCase
157
168
  end
158
169
 
159
170
  def test_extract_coordinates
160
- result = Geocoder::Calculations.extract_coordinates([ nil, nil ])
161
- assert is_nan_coordinates?(result)
171
+ coords = [-23,47]
172
+ l = Landmark.new("Madagascar", coords[0], coords[1])
173
+ assert_equal coords, Geocoder::Calculations.extract_coordinates(l)
174
+ assert_equal coords, Geocoder::Calculations.extract_coordinates(coords)
175
+ end
162
176
 
163
- result = Geocoder::Calculations.extract_coordinates([ 1.0 / 3, 2.0 / 3 ])
164
- assert_in_delta 1.0 / 3, result.first, 1E-5
165
- assert_in_delta 2.0 / 3, result.last, 1E-5
177
+ def test_extract_nan_coordinates
178
+ result = Geocoder::Calculations.extract_coordinates([ nil, nil ])
179
+ assert_nan_coordinates?(result)
166
180
 
167
181
  result = Geocoder::Calculations.extract_coordinates(nil)
168
- assert is_nan_coordinates?(result)
182
+ assert_nan_coordinates?(result)
169
183
 
170
184
  result = Geocoder::Calculations.extract_coordinates('')
171
- assert is_nan_coordinates?(result)
185
+ assert_nan_coordinates?(result)
172
186
 
173
187
  result = Geocoder::Calculations.extract_coordinates([ 'nix' ])
174
- assert is_nan_coordinates?(result)
188
+ assert_nan_coordinates?(result)
175
189
 
176
190
  o = Object.new
177
191
  result = Geocoder::Calculations.extract_coordinates(o)
178
- assert is_nan_coordinates?(result)
179
-
180
- def o.to_coordinates
181
- [ 1.0 / 3, 2.0 / 3 ]
182
- end
183
- result = Geocoder::Calculations.extract_coordinates(o)
184
- assert_in_delta 1.0 / 3, result.first, 1E-5
185
- assert_in_delta 2.0 / 3, result.last, 1E-5
192
+ assert_nan_coordinates?(result)
186
193
  end
187
194
 
188
195
  def test_coordinates_present
@@ -192,10 +199,13 @@ class CalculationsTest < Test::Unit::TestCase
192
199
  assert !Geocoder::Calculations.coordinates_present?(3.23, nil)
193
200
  end
194
201
 
195
- def test_extract_coordinates
196
- coords = [-23,47]
197
- l = Landmark.new("Madagascar", coords[0], coords[1])
198
- assert_equal coords, Geocoder::Calculations.extract_coordinates(l)
199
- assert_equal coords, Geocoder::Calculations.extract_coordinates(coords)
202
+ private # ------------------------------------------------------------------
203
+
204
+ def assert_nan_coordinates?(value)
205
+ assert value.is_a?(Array) &&
206
+ value.size == 2 &&
207
+ value[0].nan? &&
208
+ value[1].nan?,
209
+ "Expected value to be [NaN, NaN] but was #{value}"
200
210
  end
201
211
  end
@@ -0,0 +1 @@
1
+ {"results":[],"status":5,"msg":"AK Illegal or Not Exist:"}
@@ -0,0 +1 @@
1
+ {"status":0,"result":[]}
@@ -0,0 +1 @@
1
+ {"status":0,"result":{"location":{"lng":121.48789948569,"lat":31.249161555654},"formatted_address":"上海市闸北区天潼路619号","business":"七浦路,海宁路,北京东路","addressComponent":{"city":"上海市","district":"闸北区","province":"上海市","street":"天潼路","street_number":"619号"},"cityCode":289}}
@@ -0,0 +1,12 @@
1
+ {
2
+ "status":0,
3
+ "result":{
4
+ "location":{
5
+ "lng":116.30814954222,
6
+ "lat":40.056885091681
7
+ },
8
+ "precise":1,
9
+ "confidence":80,
10
+ "level":"\u5546\u52a1\u5927\u53a6"
11
+ }
12
+ }
@@ -0,0 +1 @@
1
+ 40.678107, -73.897460, 4 Pennsylvania Ave, New York, NY, 11207
@@ -0,0 +1 @@
1
+ 2: couldn't find this address! sorry
@@ -0,0 +1,4 @@
1
+ {
2
+ "status": "OVER_QUERY_LIMIT",
3
+ "results": [ ]
4
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "results": [
3
+ {
4
+ "locations": []
5
+ }
6
+ ],
7
+ "info": {
8
+ "copyright": {
9
+ "text": "© 2012 MapQuest, Inc.",
10
+ "imageUrl": "http://api.mqcdn.com/res/mqlogo.gif",
11
+ "imageAltText": "© 2012 MapQuest, Inc."
12
+ },
13
+ "statuscode": 500,
14
+ "messages": ["Error processing request: ..."]
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "results": [
3
+ {
4
+ "locations": []
5
+ }
6
+ ],
7
+ "info": {
8
+ "copyright": {
9
+ "text": "© 2012 MapQuest, Inc.",
10
+ "imageUrl": "http://api.mqcdn.com/res/mqlogo.gif",
11
+ "imageAltText": "© 2012 MapQuest, Inc."
12
+ },
13
+ "statuscode": 403,
14
+ "messages": ["..."]
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "results": [
3
+ {
4
+ "locations": []
5
+ }
6
+ ],
7
+ "info": {
8
+ "copyright": {
9
+ "text": "© 2012 MapQuest, Inc.",
10
+ "imageUrl": "http://api.mqcdn.com/res/mqlogo.gif",
11
+ "imageAltText": "© 2012 MapQuest, Inc."
12
+ },
13
+ "statuscode": 400,
14
+ "messages": ["Illegal argument from request: ..."]
15
+ }
16
+ }
@@ -3,5 +3,14 @@
3
3
  {
4
4
  "locations": []
5
5
  }
6
- ]
6
+ ],
7
+ "info": {
8
+ "copyright": {
9
+ "text": "© 2012 MapQuest, Inc.",
10
+ "imageUrl": "http://api.mqcdn.com/res/mqlogo.gif",
11
+ "imageAltText": "© 2012 MapQuest, Inc."
12
+ },
13
+ "statuscode": 0,
14
+ "messages": []
15
+ }
7
16
  }
data/test/mongoid_test.rb CHANGED
@@ -36,4 +36,11 @@ class MongoidTest < Test::Unit::TestCase
36
36
  result = PlaceWithoutIndex.index_options.keys.flatten[0] == :coordinates
37
37
  assert !result
38
38
  end
39
+
40
+ def test_nil_radius_omits_max_distance
41
+ location = [40.750354, -73.993371]
42
+ p = Place.near(location, nil)
43
+ key = Mongoid::VERSION >= "3" ? "location" : :location
44
+ assert_equal nil, p.selector[key]['$maxDistance']
45
+ end
39
46
  end
data/test/near_test.rb CHANGED
@@ -35,6 +35,24 @@ class NearTest < Test::Unit::TestCase
35
35
  assert_no_consecutive_comma(result[:select])
36
36
  end
37
37
 
38
+ def test_near_scope_options_with_custom_distance_column
39
+ result = Event.send(:near_scope_options, 1.0, 2.0, 5, :distance_column => 'calculated_distance')
40
+
41
+ assert_no_match /AS distance/, result[:select]
42
+ assert_match /AS calculated_distance/, result[:select]
43
+ assert_no_match /\bdistance\b/, result[:order]
44
+ assert_match /calculated_distance/, result[:order]
45
+ assert_no_consecutive_comma(result[:select])
46
+ end
47
+
48
+ def test_near_scope_options_with_custom_bearing_column
49
+ result = Event.send(:near_scope_options, 1.0, 2.0, 5, :bearing_column => 'calculated_bearing')
50
+
51
+ assert_no_match /AS bearing/, result[:select]
52
+ assert_match /AS calculated_bearing/, result[:select]
53
+ assert_no_consecutive_comma(result[:select])
54
+ end
55
+
38
56
  private
39
57
 
40
58
  def assert_no_consecutive_comma(string)
data/test/proxy_test.rb CHANGED
@@ -20,4 +20,17 @@ class ProxyTest < Test::Unit::TestCase
20
20
  Geocoder::Lookup::Google.new.send(:http_client)
21
21
  end
22
22
  end
23
+
24
+ def test_accepts_proxy_with_http_protocol
25
+ Geocoder.configure(:http_proxy => 'http://localhost')
26
+ lookup = Geocoder::Lookup::Google.new
27
+ assert lookup.send(:http_client).proxy_class?
28
+ end
29
+
30
+ def test_accepts_proxy_with_https_protocol
31
+ Geocoder.configure(:https_proxy => 'https://localhost')
32
+ Geocoder.configure(:use_https => true)
33
+ lookup = Geocoder::Lookup::Google.new
34
+ assert lookup.send(:http_client).proxy_class?
35
+ end
23
36
  end
data/test/query_test.rb CHANGED
@@ -44,4 +44,9 @@ class QueryTest < Test::Unit::TestCase
44
44
  assert !Geocoder::Query.new("127 Main St.").loopback_ip_address?
45
45
  assert !Geocoder::Query.new("John Doe\n127 Main St.\nAnywhere, USA").loopback_ip_address?
46
46
  end
47
+
48
+ def test_sanitized_text_with_array
49
+ q = Geocoder::Query.new([43.1313,11.3131])
50
+ assert_equal "43.1313,11.3131", q.sanitized_text
51
+ end
47
52
  end
@@ -98,6 +98,26 @@ class ServicesTest < Test::Unit::TestCase
98
98
  Geocoder::Lookup::GooglePremier.new.query_url(Geocoder::Query.new("Madison Square Garden, New York, NY"))
99
99
  end
100
100
 
101
+ # --- DSTK (Data Science Toolkit) ---
102
+
103
+ def test_dstk_result_components
104
+ Geocoder.configure(:lookup => :dstk, :dstk => { :host => 'NOT_AN_ACTUAL_HOST' })
105
+ result = Geocoder.search("Madison Square Garden, New York, NY").first
106
+ assert_equal "Manhattan",
107
+ result.address_components_of_type(:sublocality).first['long_name']
108
+ end
109
+
110
+ def test_dstk_query_url
111
+ Geocoder.configure(:lookup => :dstk, :dstk => { :host => 'NOT_AN_ACTUAL_HOST' })
112
+ assert_equal "http://NOT_AN_ACTUAL_HOST/maps/api/geocode/json?address=Madison+Square+Garden%2C+New+York%2C+NY&language=en&sensor=false",
113
+ Geocoder::Lookup::Dstk.new.query_url(Geocoder::Query.new("Madison Square Garden, New York, NY"))
114
+ end
115
+
116
+ def test_dstk_default_query_url
117
+ Geocoder.configure(:lookup => :dstk)
118
+ assert_equal "http://www.datasciencetoolkit.org/maps/api/geocode/json?address=Madison+Square+Garden%2C+New+York%2C+NY&language=en&sensor=false",
119
+ Geocoder::Lookup::Dstk.new.query_url(Geocoder::Query.new("Madison Square Garden, New York, NY"))
120
+ end
101
121
 
102
122
  # --- Yahoo ---
103
123
 
@@ -206,6 +226,18 @@ class ServicesTest < Test::Unit::TestCase
206
226
  end
207
227
  end
208
228
 
229
+ def test_maxmind_works_when_loopback_address_on_omni
230
+ Geocoder.configure(:ip_lookup => :maxmind, :maxmind => { :service => :omni })
231
+ result = Geocoder.search("127.0.0.1").first
232
+ assert_equal "", result.country_code
233
+ end
234
+
235
+ def test_maxmind_works_when_loopback_address_on_country
236
+ Geocoder.configure(:ip_lookup => :maxmind, :maxmind => { :service => :country })
237
+ result = Geocoder.search("127.0.0.1").first
238
+ assert_equal "", result.country_code
239
+ end
240
+
209
241
 
210
242
  # --- Bing ---
211
243
 
@@ -256,7 +288,16 @@ class ServicesTest < Test::Unit::TestCase
256
288
  lookup = Geocoder::Lookup::Mapquest.new
257
289
  query = Geocoder::Query.new("Bluffton, SC")
258
290
  res = lookup.query_url(query)
259
- assert_equal "http://www.mapquestapi.com/geocoding/v1/address?key=abc123&location=Bluffton%2C+SC",
291
+ assert_equal "http://open.mapquestapi.com/geocoding/v1/address?key=abc123&location=Bluffton%2C+SC",
292
+ res
293
+ end
294
+
295
+ def test_api_route_licensed
296
+ Geocoder.configure(:lookup => :mapquest, :api_key => "abc123", :mapquest => {:licensed => true, :version => 2})
297
+ lookup = Geocoder::Lookup::Mapquest.new
298
+ query = Geocoder::Query.new("Bluffton, SC")
299
+ res = lookup.query_url(query)
300
+ assert_equal "http://www.mapquestapi.com/geocoding/v2/address?key=abc123&location=Bluffton%2C+SC",
260
301
  res
261
302
  end
262
303
 
@@ -275,6 +316,38 @@ class ServicesTest < Test::Unit::TestCase
275
316
  result.address
276
317
  end
277
318
 
319
+ def test_mapquest_no_results
320
+ Geocoder.configure(:lookup => :mapquest)
321
+ set_api_key!(:mapquest)
322
+ assert_equal [], Geocoder.search("no results")
323
+ end
324
+
325
+ def test_mapquest_raises_exception_when_invalid_request
326
+ Geocoder.configure(:always_raise => [Geocoder::InvalidRequest])
327
+ l = Geocoder::Lookup.get(:mapquest)
328
+ assert_raises Geocoder::InvalidRequest do
329
+ l.send(:results, Geocoder::Query.new("invalid request"))
330
+ end
331
+ end
332
+
333
+ def test_mapquest_raises_exception_when_invalid_api_key
334
+ Geocoder.configure(:always_raise => [Geocoder::InvalidApiKey])
335
+ l = Geocoder::Lookup.get(:mapquest)
336
+ assert_raises Geocoder::InvalidApiKey do
337
+ l.send(:results, Geocoder::Query.new("invalid api key"))
338
+ end
339
+ end
340
+
341
+ def test_mapquest_raises_exception_when_error
342
+ Geocoder.configure(:always_raise => [Geocoder::Error])
343
+ l = Geocoder::Lookup.get(:mapquest)
344
+ assert_raises Geocoder::Error do
345
+ l.send(:results, Geocoder::Query.new("error"))
346
+ end
347
+ end
348
+
349
+
350
+
278
351
  # --- Esri ---
279
352
 
280
353
  def test_esri_query_for_geocode
@@ -304,7 +377,7 @@ class ServicesTest < Test::Unit::TestCase
304
377
  assert_equal 40.75004981300049, result.coordinates[0]
305
378
  assert_equal -73.99423889799965, result.coordinates[1]
306
379
  end
307
-
380
+
308
381
  def test_esri_results_component_when_reverse_geocoding
309
382
  Geocoder.configure(:lookup => :esri)
310
383
  result = Geocoder.search([45.423733, -75.676333]).first