rgeo 0.3.13 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. data/History.rdoc +8 -0
  2. data/README.rdoc +4 -4
  3. data/Version +1 -1
  4. data/ext/geos_c_impl/extconf.rb +1 -0
  5. data/ext/geos_c_impl/factory.c +118 -5
  6. data/ext/geos_c_impl/factory.h +24 -1
  7. data/ext/geos_c_impl/geometry.c +42 -53
  8. data/ext/geos_c_impl/geometry_collection.c +137 -54
  9. data/ext/geos_c_impl/geometry_collection.h +9 -0
  10. data/ext/geos_c_impl/line_string.c +88 -45
  11. data/ext/geos_c_impl/point.c +31 -17
  12. data/ext/geos_c_impl/polygon.c +50 -22
  13. data/ext/geos_c_impl/polygon.h +9 -0
  14. data/ext/geos_c_impl/preface.h +10 -0
  15. data/lib/rgeo/cartesian/factory.rb +9 -1
  16. data/lib/rgeo/coord_sys/cs/entities.rb +10 -1
  17. data/lib/rgeo/coord_sys/proj4.rb +1 -1
  18. data/lib/rgeo/feature/types.rb +29 -5
  19. data/lib/rgeo/geographic/factory.rb +5 -0
  20. data/lib/rgeo/geographic/projected_feature_classes.rb +3 -47
  21. data/lib/rgeo/geographic/projected_feature_methods.rb +69 -0
  22. data/lib/rgeo/geographic/spherical_feature_classes.rb +1 -74
  23. data/lib/rgeo/geographic/spherical_feature_methods.rb +84 -0
  24. data/lib/rgeo/geographic/spherical_math.rb +3 -3
  25. data/lib/rgeo/geos.rb +17 -9
  26. data/lib/rgeo/geos/{factory.rb → capi_factory.rb} +36 -15
  27. data/lib/rgeo/geos/{impl_additions.rb → capi_feature_classes.rb} +127 -16
  28. data/lib/rgeo/geos/ffi_factory.rb +55 -41
  29. data/lib/rgeo/geos/ffi_feature_classes.rb +168 -0
  30. data/lib/rgeo/geos/{ffi_classes.rb → ffi_feature_methods.rb} +56 -57
  31. data/lib/rgeo/geos/interface.rb +5 -5
  32. data/lib/rgeo/geos/utils.rb +7 -0
  33. data/lib/rgeo/geos/zm_factory.rb +40 -12
  34. data/lib/rgeo/geos/zm_feature_classes.rb +165 -0
  35. data/lib/rgeo/geos/{zm_impl.rb → zm_feature_methods.rb} +33 -52
  36. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +8 -0
  37. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +8 -0
  38. data/lib/rgeo/impl_helper/basic_point_methods.rb +5 -0
  39. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +8 -0
  40. data/test/common/factory_tests.rb +8 -2
  41. data/test/common/geometry_collection_tests.rb +23 -0
  42. data/test/common/line_string_tests.rb +25 -0
  43. data/test/common/multi_line_string_tests.rb +7 -0
  44. data/test/common/multi_point_tests.rb +7 -0
  45. data/test/common/multi_polygon_tests.rb +7 -0
  46. data/test/common/point_tests.rb +21 -0
  47. data/test/common/polygon_tests.rb +15 -0
  48. data/test/coord_sys/tc_proj4.rb +8 -1
  49. data/test/geos_capi/tc_misc.rb +1 -1
  50. data/test/tc_mixins.rb +1 -1
  51. metadata +9 -7
@@ -127,6 +127,11 @@ module RGeo
127
127
  alias_method :==, :eql?
128
128
 
129
129
 
130
+ def hash
131
+ @hash ||= [@impl_prefix, @support_z, @support_m, @proj4].hash
132
+ end
133
+
134
+
130
135
  # Marshal support
131
136
 
132
137
  def marshal_dump # :nodoc:
@@ -46,37 +46,7 @@ module RGeo
46
46
  include ImplHelper::BasicGeometryMethods
47
47
  include ImplHelper::BasicPointMethods
48
48
  include ProjectedGeometryMethods
49
-
50
-
51
- def _validate_geometry
52
- @y = 85.0511287 if @y > 85.0511287
53
- @y = -85.0511287 if @y < -85.0511287
54
- super
55
- end
56
-
57
-
58
- def canonical_x
59
- x_ = @x % 360.0
60
- x_ -= 360.0 if x_ >= 180.0
61
- x_
62
- end
63
- alias_method :canonical_longitude, :canonical_x
64
- alias_method :canonical_lon, :canonical_x
65
-
66
-
67
- def canonical_point
68
- if @x >= -180.0 && @x < 180.0
69
- self
70
- else
71
- PointImpl.new(@factory, canonical_x, @y)
72
- end
73
- end
74
-
75
-
76
- alias_method :longitude, :x
77
- alias_method :lon, :x
78
- alias_method :latitude, :y
79
- alias_method :lat, :y
49
+ include ProjectedPointMethods
80
50
 
81
51
 
82
52
  Feature::MixinCollection::GLOBAL.for_type(Feature::Point).include_in_class(self, true)
@@ -146,14 +116,7 @@ module RGeo
146
116
  include ImplHelper::BasicPolygonMethods
147
117
  include ProjectedGeometryMethods
148
118
  include ProjectedNSurfaceMethods
149
-
150
-
151
- def _validate_geometry
152
- super
153
- unless projection
154
- raise Error::InvalidGeometry, 'Polygon failed assertions'
155
- end
156
- end
119
+ include ProjectedPolygonMethods
157
120
 
158
121
 
159
122
  Feature::MixinCollection::GLOBAL.for_type(Feature::Polygon).include_in_class(self, true)
@@ -219,14 +182,7 @@ module RGeo
219
182
  include ImplHelper::BasicMultiPolygonMethods
220
183
  include ProjectedGeometryMethods
221
184
  include ProjectedNSurfaceMethods
222
-
223
-
224
- def _validate_geometry
225
- super
226
- unless projection
227
- raise Error::InvalidGeometry, 'MultiPolygon failed assertions'
228
- end
229
- end
185
+ include ProjectedMultiPolygonMethods
230
186
 
231
187
 
232
188
  Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPolygon).include_in_class(self, true)
@@ -159,6 +159,47 @@ module RGeo
159
159
  end
160
160
 
161
161
 
162
+ module ProjectedPointMethods # :nodoc:
163
+
164
+
165
+ def _validate_geometry
166
+ @y = 85.0511287 if @y > 85.0511287
167
+ @y = -85.0511287 if @y < -85.0511287
168
+ super
169
+ end
170
+
171
+
172
+ def canonical_x
173
+ x_ = @x % 360.0
174
+ x_ -= 360.0 if x_ >= 180.0
175
+ x_
176
+ end
177
+ alias_method :canonical_longitude, :canonical_x
178
+ alias_method :canonical_lon, :canonical_x
179
+
180
+
181
+ def canonical_point
182
+ if @x >= -180.0 && @x < 180.0
183
+ self
184
+ else
185
+ PointImpl.new(@factory, canonical_x, @y)
186
+ end
187
+ end
188
+
189
+
190
+ def self.included(klass_)
191
+ klass_.module_eval do
192
+ alias_method :longitude, :x
193
+ alias_method :lon, :x
194
+ alias_method :latitude, :y
195
+ alias_method :lat, :y
196
+ end
197
+ end
198
+
199
+
200
+ end
201
+
202
+
162
203
  module ProjectedNCurveMethods # :nodoc:
163
204
 
164
205
 
@@ -224,6 +265,34 @@ module RGeo
224
265
  end
225
266
 
226
267
 
268
+ module ProjectedPolygonMethods # :nodoc:
269
+
270
+
271
+ def _validate_geometry
272
+ super
273
+ unless projection
274
+ raise Error::InvalidGeometry, 'Polygon failed assertions'
275
+ end
276
+ end
277
+
278
+
279
+ end
280
+
281
+
282
+ module ProjectedMultiPolygonMethods # :nodoc:
283
+
284
+
285
+ def _validate_geometry
286
+ super
287
+ unless projection
288
+ raise Error::InvalidGeometry, 'MultiPolygon failed assertions'
289
+ end
290
+ end
291
+
292
+
293
+ end
294
+
295
+
227
296
  end
228
297
 
229
298
  end
@@ -46,80 +46,7 @@ module RGeo
46
46
  include ImplHelper::BasicGeometryMethods
47
47
  include ImplHelper::BasicPointMethods
48
48
  include SphericalGeometryMethods
49
-
50
-
51
- def _validate_geometry
52
- if @x < -180.0 || @x >= 180.0
53
- @x = @x % 360.0
54
- @x -= 360.0 if @x >= 180.0
55
- end
56
- @y = 90.0 if @y > 90.0
57
- @y = -90.0 if @y < -90.0
58
- super
59
- end
60
-
61
-
62
- def _xyz
63
- @xyz ||= SphericalMath::PointXYZ.from_latlon(@y, @x)
64
- end
65
-
66
-
67
- def distance(rhs_)
68
- rhs_ = Feature.cast(rhs_, @factory)
69
- case rhs_
70
- when SphericalPointImpl
71
- _xyz.dist_to_point(rhs_._xyz) * SphericalMath::RADIUS
72
- else
73
- super
74
- end
75
- end
76
-
77
-
78
- def equals?(rhs_)
79
- return false unless rhs_.is_a?(self.class) && rhs_.factory == self.factory
80
- case rhs_
81
- when Feature::Point
82
- if @y == 90
83
- rhs_.y == 90
84
- elsif @y == -90
85
- rhs_.y == -90
86
- else
87
- rhs_.x == @x && rhs_.y == @y
88
- end
89
- when Feature::LineString
90
- rhs_.num_points > 0 && rhs_.points.all?{ |elem_| equals?(elem_) }
91
- when Feature::GeometryCollection
92
- rhs_.num_geometries > 0 && rhs_.all?{ |elem_| equals?(elem_) }
93
- else
94
- false
95
- end
96
- end
97
-
98
-
99
- def buffer(distance_)
100
- radius_ = distance_ / SphericalMath::RADIUS
101
- radius_ = 1.5 if radius_ > 1.5
102
- cos_ = ::Math.cos(radius_)
103
- sin_ = ::Math.sin(radius_)
104
- point_count_ = factory.property(:buffer_resolution) * 4
105
- p0_ = _xyz
106
- p1_ = p0_.create_perpendicular
107
- p2_ = p1_ % p0_
108
- angle_ = ::Math::PI * 2.0 / point_count_
109
- points_ = (0...point_count_).map do |i_|
110
- r_ = angle_ * i_
111
- pi_ = SphericalMath::PointXYZ.weighted_combination(p1_, ::Math.cos(r_), p2_, ::Math.sin(r_))
112
- p_ = SphericalMath::PointXYZ.weighted_combination(p0_, cos_, pi_, sin_)
113
- factory.point(*p_.lonlat)
114
- end
115
- factory.polygon(factory.linear_ring(points_))
116
- end
117
-
118
-
119
- alias_method :longitude, :x
120
- alias_method :lon, :x
121
- alias_method :latitude, :y
122
- alias_method :lat, :y
49
+ include SphericalPointMethods
123
50
 
124
51
 
125
52
  Feature::MixinCollection::GLOBAL.for_type(Feature::Point).include_in_class(self, true)
@@ -50,6 +50,90 @@ module RGeo
50
50
  end
51
51
 
52
52
 
53
+ module SphericalPointMethods # :nodoc:
54
+
55
+
56
+ def _validate_geometry
57
+ if @x < -180.0 || @x >= 180.0
58
+ @x = @x % 360.0
59
+ @x -= 360.0 if @x >= 180.0
60
+ end
61
+ @y = 90.0 if @y > 90.0
62
+ @y = -90.0 if @y < -90.0
63
+ super
64
+ end
65
+
66
+
67
+ def _xyz
68
+ @xyz ||= SphericalMath::PointXYZ.from_latlon(@y, @x)
69
+ end
70
+
71
+
72
+ def distance(rhs_)
73
+ rhs_ = Feature.cast(rhs_, @factory)
74
+ case rhs_
75
+ when SphericalPointImpl
76
+ _xyz.dist_to_point(rhs_._xyz) * SphericalMath::RADIUS
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+
83
+ def equals?(rhs_)
84
+ return false unless rhs_.is_a?(self.class) && rhs_.factory == self.factory
85
+ case rhs_
86
+ when Feature::Point
87
+ if @y == 90
88
+ rhs_.y == 90
89
+ elsif @y == -90
90
+ rhs_.y == -90
91
+ else
92
+ rhs_.x == @x && rhs_.y == @y
93
+ end
94
+ when Feature::LineString
95
+ rhs_.num_points > 0 && rhs_.points.all?{ |elem_| equals?(elem_) }
96
+ when Feature::GeometryCollection
97
+ rhs_.num_geometries > 0 && rhs_.all?{ |elem_| equals?(elem_) }
98
+ else
99
+ false
100
+ end
101
+ end
102
+
103
+
104
+ def buffer(distance_)
105
+ radius_ = distance_ / SphericalMath::RADIUS
106
+ radius_ = 1.5 if radius_ > 1.5
107
+ cos_ = ::Math.cos(radius_)
108
+ sin_ = ::Math.sin(radius_)
109
+ point_count_ = factory.property(:buffer_resolution) * 4
110
+ p0_ = _xyz
111
+ p1_ = p0_.create_perpendicular
112
+ p2_ = p1_ % p0_
113
+ angle_ = ::Math::PI * 2.0 / point_count_
114
+ points_ = (0...point_count_).map do |i_|
115
+ r_ = angle_ * i_
116
+ pi_ = SphericalMath::PointXYZ.weighted_combination(p1_, ::Math.cos(r_), p2_, ::Math.sin(r_))
117
+ p_ = SphericalMath::PointXYZ.weighted_combination(p0_, cos_, pi_, sin_)
118
+ factory.point(*p_.lonlat)
119
+ end
120
+ factory.polygon(factory.linear_ring(points_))
121
+ end
122
+
123
+
124
+ def self.included(klass_)
125
+ klass_.module_eval do
126
+ alias_method :longitude, :x
127
+ alias_method :lon, :x
128
+ alias_method :latitude, :y
129
+ alias_method :lat, :y
130
+ end
131
+ end
132
+
133
+
134
+ end
135
+
136
+
53
137
  module SphericalLineStringMethods # :nodoc:
54
138
 
55
139
 
@@ -59,9 +59,9 @@ module RGeo
59
59
 
60
60
  def initialize(x_, y_, z_)
61
61
  r_ = ::Math.sqrt(x_ * x_ + y_ * y_ + z_ * z_)
62
- @x = x_ / r_
63
- @y = y_ / r_
64
- @z = z_ / r_
62
+ @x = (x_ / r_).to_f
63
+ @y = (y_ / r_).to_f
64
+ @z = (z_ / r_).to_f
65
65
  raise "Not a number" if @x.nan? || @y.nan? || @z.nan?
66
66
  end
67
67
 
data/lib/rgeo/geos.rb CHANGED
@@ -65,30 +65,38 @@ end
65
65
 
66
66
  # Implementation files
67
67
  require 'rgeo/geos/utils'
68
- require 'rgeo/geos/factory'
69
68
  require 'rgeo/geos/interface'
70
69
  begin
71
70
  require 'rgeo/geos/geos_c_impl'
72
71
  rescue ::LoadError; end
73
- require 'rgeo/geos/impl_additions'
72
+ ::RGeo::Geos::CAPI_SUPPORTED = ::RGeo::Geos.const_defined?(:CAPIGeometryMethods)
73
+ if ::RGeo::Geos::CAPI_SUPPORTED
74
+ require 'rgeo/geos/capi_feature_classes'
75
+ require 'rgeo/geos/capi_factory'
76
+ end
77
+ require 'rgeo/geos/ffi_feature_methods'
78
+ require 'rgeo/geos/ffi_feature_classes'
74
79
  require 'rgeo/geos/ffi_factory'
75
- require 'rgeo/geos/ffi_classes'
80
+ require 'rgeo/geos/zm_feature_methods'
81
+ require 'rgeo/geos/zm_feature_classes'
76
82
  require 'rgeo/geos/zm_factory'
77
- require 'rgeo/geos/zm_impl'
78
83
 
79
84
  # Determine ffi support.
80
85
  begin
81
86
  require 'ffi-geos'
87
+ # An additional check to make sure FFI loaded okay. This can fail on
88
+ # some versions of ffi-geos and some versions of Rubinius.
89
+ raise 'Problem loading FFI' unless ::FFI::AutoPointer
82
90
  ::RGeo::Geos::FFI_SUPPORTED = true
83
- rescue ::LoadError
91
+ ::RGeo::Geos::FFI_SUPPORT_EXCEPTION = nil
92
+ rescue ::LoadError => ex_
84
93
  ::RGeo::Geos::FFI_SUPPORTED = false
85
- rescue
94
+ ::RGeo::Geos::FFI_SUPPORT_EXCEPTION = ex_
95
+ rescue => ex_
86
96
  ::RGeo::Geos::FFI_SUPPORTED = false
97
+ ::RGeo::Geos::FFI_SUPPORT_EXCEPTION = ex_
87
98
  end
88
99
 
89
- # Determine capi support.
90
- ::RGeo::Geos::CAPI_SUPPORTED = ::RGeo::Geos::Factory.respond_to?(:_create) ? true : false
91
-
92
100
  # Determine preferred native interface
93
101
  if ::RGeo::Geos::CAPI_SUPPORTED
94
102
  ::RGeo::Geos.preferred_native_interface = :capi
@@ -41,7 +41,7 @@ module RGeo
41
41
 
42
42
  # This the GEOS CAPI implementation of ::RGeo::Feature::Factory.
43
43
 
44
- class Factory
44
+ class CAPIFactory
45
45
 
46
46
 
47
47
  include Feature::Factory::Instance
@@ -158,13 +158,18 @@ module RGeo
158
158
  # Factory equivalence test.
159
159
 
160
160
  def eql?(rhs_)
161
- rhs_.is_a?(Factory) && rhs_.srid == _srid &&
161
+ rhs_.is_a?(CAPIFactory) && rhs_.srid == _srid &&
162
162
  rhs_._buffer_resolution == _buffer_resolution && rhs_._flags == _flags &&
163
163
  rhs_.proj4 == _proj4
164
164
  end
165
165
  alias_method :==, :eql?
166
166
 
167
167
 
168
+ def hash
169
+ @hash ||= [_srid, _buffer_resolution, _flags, _proj4].hash
170
+ end
171
+
172
+
168
173
  # Marshal support
169
174
 
170
175
  def marshal_dump # :nodoc:
@@ -201,7 +206,7 @@ module RGeo
201
206
  else
202
207
  coord_sys_ = nil
203
208
  end
204
- initialize_copy(Factory.create(
209
+ initialize_copy(CAPIFactory.create(
205
210
  :has_z_coordinate => data_['hasz'],
206
211
  :has_m_coordinate => data_['hasm'],
207
212
  :srid => data_['srid'],
@@ -255,7 +260,7 @@ module RGeo
255
260
  else
256
261
  coord_sys_ = nil
257
262
  end
258
- initialize_copy(Factory.create(
263
+ initialize_copy(CAPIFactory.create(
259
264
  :has_z_coordinate => coder_['has_z_coordinate'],
260
265
  :has_m_coordinate => coder_['has_m_coordinate'],
261
266
  :srid => coder_['srid'],
@@ -344,7 +349,7 @@ module RGeo
344
349
  if extra_.length > (_flags & 6 == 0 ? 0 : 1)
345
350
  nil
346
351
  else
347
- PointImpl.create(self, x_, y_, extra_[0].to_f) rescue nil
352
+ CAPIPointImpl.create(self, x_, y_, extra_[0].to_f) rescue nil
348
353
  end
349
354
  end
350
355
 
@@ -353,14 +358,14 @@ module RGeo
353
358
 
354
359
  def line_string(points_)
355
360
  points_ = points_.to_a unless points_.kind_of?(::Array)
356
- LineStringImpl.create(self, points_) rescue nil
361
+ CAPILineStringImpl.create(self, points_) rescue nil
357
362
  end
358
363
 
359
364
 
360
365
  # See ::RGeo::Feature::Factory#line
361
366
 
362
367
  def line(start_, end_)
363
- LineImpl.create(self, start_, end_) rescue nil
368
+ CAPILineImpl.create(self, start_, end_) rescue nil
364
369
  end
365
370
 
366
371
 
@@ -368,7 +373,7 @@ module RGeo
368
373
 
369
374
  def linear_ring(points_)
370
375
  points_ = points_.to_a unless points_.kind_of?(::Array)
371
- LinearRingImpl.create(self, points_) rescue nil
376
+ CAPILinearRingImpl.create(self, points_) rescue nil
372
377
  end
373
378
 
374
379
 
@@ -376,7 +381,7 @@ module RGeo
376
381
 
377
382
  def polygon(outer_ring_, inner_rings_=nil)
378
383
  inner_rings_ = inner_rings_.to_a unless inner_rings_.kind_of?(::Array)
379
- PolygonImpl.create(self, outer_ring_, inner_rings_) rescue nil
384
+ CAPIPolygonImpl.create(self, outer_ring_, inner_rings_) rescue nil
380
385
  end
381
386
 
382
387
 
@@ -384,7 +389,7 @@ module RGeo
384
389
 
385
390
  def collection(elems_)
386
391
  elems_ = elems_.to_a unless elems_.kind_of?(::Array)
387
- GeometryCollectionImpl.create(self, elems_) rescue nil
392
+ CAPIGeometryCollectionImpl.create(self, elems_) rescue nil
388
393
  end
389
394
 
390
395
 
@@ -392,7 +397,7 @@ module RGeo
392
397
 
393
398
  def multi_point(elems_)
394
399
  elems_ = elems_.to_a unless elems_.kind_of?(::Array)
395
- MultiPointImpl.create(self, elems_) rescue nil
400
+ CAPIMultiPointImpl.create(self, elems_) rescue nil
396
401
  end
397
402
 
398
403
 
@@ -400,7 +405,7 @@ module RGeo
400
405
 
401
406
  def multi_line_string(elems_)
402
407
  elems_ = elems_.to_a unless elems_.kind_of?(::Array)
403
- MultiLineStringImpl.create(self, elems_) rescue nil
408
+ CAPIMultiLineStringImpl.create(self, elems_) rescue nil
404
409
  end
405
410
 
406
411
 
@@ -408,7 +413,7 @@ module RGeo
408
413
 
409
414
  def multi_polygon(elems_)
410
415
  elems_ = elems_.to_a unless elems_.kind_of?(::Array)
411
- MultiPolygonImpl.create(self, elems_) rescue nil
416
+ CAPIMultiPolygonImpl.create(self, elems_) rescue nil
412
417
  end
413
418
 
414
419
 
@@ -436,7 +441,7 @@ module RGeo
436
441
  type_ = original_.geometry_type
437
442
  ntype_ = type_ if keep_subtype_ && type_.include?(ntype_)
438
443
  case original_
439
- when GeometryImpl
444
+ when CAPIGeometryMethods
440
445
  # Optimization if we're just changing factories, but the
441
446
  # factories are zm-compatible and proj4-compatible.
442
447
  if original_.factory != self && ntype_ == type_ &&
@@ -455,7 +460,7 @@ module RGeo
455
460
  then
456
461
  return IMPL_CLASSES[ntype_]._copy_from(self, original_)
457
462
  end
458
- when ZMGeometryImpl
463
+ when ZMGeometryMethods
459
464
  # Optimization for just removing a coordinate from an otherwise
460
465
  # compatible factory
461
466
  if _flags & 0x6 == 0x2 && self == original_.factory.z_factory
@@ -468,6 +473,22 @@ module RGeo
468
473
  end
469
474
 
470
475
 
476
+ # :stopdoc:
477
+
478
+ IMPL_CLASSES = {
479
+ Feature::Point => CAPIPointImpl,
480
+ Feature::LineString => CAPILineStringImpl,
481
+ Feature::LinearRing => CAPILinearRingImpl,
482
+ Feature::Line => CAPILineImpl,
483
+ Feature::GeometryCollection => CAPIGeometryCollectionImpl,
484
+ Feature::MultiPoint => CAPIMultiPointImpl,
485
+ Feature::MultiLineString => CAPIMultiLineStringImpl,
486
+ Feature::MultiPolygon => CAPIMultiPolygonImpl,
487
+ }.freeze
488
+
489
+ # :startdoc:
490
+
491
+
471
492
  end
472
493
 
473
494