activerecord-spatialite-adapter 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +9 -0
- data/README.rdoc +15 -7
- data/Version +1 -1
- data/lib/active_record/connection_adapters/spatialite_adapter.rb +30 -31
- data/lib/active_record/connection_adapters/spatialite_adapter/arel_tosql.rb +13 -13
- data/lib/active_record/connection_adapters/spatialite_adapter/databases.rake +6 -6
- data/lib/active_record/connection_adapters/spatialite_adapter/main_adapter.rb +71 -60
- data/lib/active_record/connection_adapters/spatialite_adapter/native_format_parser.rb +37 -37
- data/lib/active_record/connection_adapters/spatialite_adapter/railtie.rb +16 -16
- data/lib/active_record/connection_adapters/spatialite_adapter/spatial_column.rb +43 -37
- data/lib/active_record/connection_adapters/spatialite_adapter/spatial_table_definition.rb +25 -25
- data/lib/active_record/connection_adapters/spatialite_adapter/version.rb +15 -15
- data/lib/rgeo/active_record/spatialite_adapter/railtie.rb +6 -6
- data/test/README.txt +17 -0
- data/test/tc_basic.rb +50 -50
- data/test/tc_spatial_queries.rb +48 -36
- metadata +49 -41
@@ -1,15 +1,15 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# SpatiaLite adapter for ActiveRecord
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
# Copyright 2010 Daniel Azuma
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# All rights reserved.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# Redistribution and use in source and binary forms, with or without
|
11
11
|
# modification, are permitted provided that the following conditions are met:
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# * Redistributions of source code must retain the above copyright notice,
|
14
14
|
# this list of conditions and the following disclaimer.
|
15
15
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# * Neither the name of the copyright holder, nor the names of any other
|
19
19
|
# contributors to this software, may be used to endorse or promote products
|
20
20
|
# derived from this software without specific prior written permission.
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
23
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
24
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
@@ -41,23 +41,23 @@ end
|
|
41
41
|
|
42
42
|
|
43
43
|
module ActiveRecord
|
44
|
-
|
44
|
+
|
45
45
|
module ConnectionAdapters
|
46
|
-
|
46
|
+
|
47
47
|
module SpatiaLiteAdapter
|
48
|
-
|
49
|
-
|
48
|
+
|
49
|
+
|
50
50
|
# Current version of SpatiaLiteAdapter as a frozen string
|
51
51
|
VERSION_STRING = ::File.read(::File.dirname(__FILE__)+'/../../../../Version').strip.freeze
|
52
|
-
|
52
|
+
|
53
53
|
# Current version of SpatiaLiteAdapter as a Versionomy object, if the
|
54
54
|
# Versionomy gem is available; otherwise equal to VERSION_STRING.
|
55
55
|
VERSION = defined?(::Versionomy) ? ::Versionomy.parse(VERSION_STRING) : VERSION_STRING
|
56
|
-
|
57
|
-
|
56
|
+
|
57
|
+
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
end
|
63
63
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# Railtie for SpatiaLite adapter
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
# Copyright 2010 Daniel Azuma
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# All rights reserved.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# Redistribution and use in source and binary forms, with or without
|
11
11
|
# modification, are permitted provided that the following conditions are met:
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# * Redistributions of source code must retain the above copyright notice,
|
14
14
|
# this list of conditions and the following disclaimer.
|
15
15
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# * Neither the name of the copyright holder, nor the names of any other
|
19
19
|
# contributors to this software, may be used to endorse or promote products
|
20
20
|
# derived from this software without specific prior written permission.
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
23
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
24
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
data/test/README.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# TO RUN THE TESTS...
|
2
|
+
#
|
3
|
+
# Create a file named "test/database.yml" with the content below.
|
4
|
+
# If your libspatialite.{so,dylib} is not in a "typical" location,
|
5
|
+
# you may need to uncomment the libspatialite value and provide the
|
6
|
+
# full path to the library.
|
7
|
+
#
|
8
|
+
# Make sure the sqlite3, activerecord, and rgeo-activerecord gems
|
9
|
+
# are installed.
|
10
|
+
#
|
11
|
+
# Then run:
|
12
|
+
# rake test
|
13
|
+
|
14
|
+
adapter: spatialite
|
15
|
+
encoding: utf8
|
16
|
+
database: tmp/spatialite_test.db
|
17
|
+
# libspatialite: /usr/local/lib/libspatialite.so
|
data/test/tc_basic.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# Tests for the MysqlSpatial ActiveRecord adapter
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
# Copyright 2010 Daniel Azuma
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# All rights reserved.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# Redistribution and use in source and binary forms, with or without
|
11
11
|
# modification, are permitted provided that the following conditions are met:
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# * Redistributions of source code must retain the above copyright notice,
|
14
14
|
# this list of conditions and the following disclaimer.
|
15
15
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# * Neither the name of the copyright holder, nor the names of any other
|
19
19
|
# contributors to this software, may be used to endorse or promote products
|
20
20
|
# derived from this software without specific prior written permission.
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
23
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
24
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
@@ -41,29 +41,29 @@ module RGeo
|
|
41
41
|
module ActiveRecord # :nodoc:
|
42
42
|
module SpatiaLiteAdapter # :nodoc:
|
43
43
|
module Tests # :nodoc:
|
44
|
-
|
44
|
+
|
45
45
|
class TestBasic < ::Test::Unit::TestCase # :nodoc:
|
46
|
-
|
47
|
-
|
46
|
+
|
47
|
+
|
48
48
|
DATABASE_CONFIG_PATH = ::File.dirname(__FILE__)+'/database.yml'
|
49
|
-
|
49
|
+
|
50
50
|
def self.before_open_database(params_)
|
51
51
|
database_ = params_[:config][:database]
|
52
52
|
dir_ = ::File.dirname(database_)
|
53
53
|
::FileUtils.mkdir_p(dir_) unless dir_ == '.'
|
54
54
|
::FileUtils.rm_f(database_)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def self.initialize_database(params_)
|
58
58
|
params_[:connection].execute('SELECT InitSpatialMetaData()')
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
include AdapterTestHelper
|
62
|
-
|
63
|
-
|
62
|
+
|
63
|
+
|
64
64
|
define_test_methods do
|
65
|
-
|
66
|
-
|
65
|
+
|
66
|
+
|
67
67
|
def populate_ar_class(content_)
|
68
68
|
klass_ = create_ar_class
|
69
69
|
case content_
|
@@ -74,19 +74,19 @@ module RGeo
|
|
74
74
|
end
|
75
75
|
klass_
|
76
76
|
end
|
77
|
-
|
78
|
-
|
77
|
+
|
78
|
+
|
79
79
|
def test_version
|
80
80
|
assert_not_nil(::ActiveRecord::ConnectionAdapters::SpatiaLiteAdapter::VERSION)
|
81
81
|
end
|
82
|
-
|
83
|
-
|
82
|
+
|
83
|
+
|
84
84
|
def test_meta_data_present
|
85
85
|
result_ = DEFAULT_AR_CLASS.connection.select_value("SELECT COUNT(*) FROM spatial_ref_sys").to_i
|
86
86
|
assert_not_equal(0, result_)
|
87
87
|
end
|
88
|
-
|
89
|
-
|
88
|
+
|
89
|
+
|
90
90
|
def test_create_simple_geometry
|
91
91
|
klass_ = create_ar_class
|
92
92
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -98,8 +98,8 @@ module RGeo
|
|
98
98
|
klass_.connection.drop_table(:spatial_test)
|
99
99
|
assert_equal(0, klass_.connection.select_value("SELECT COUNT(*) FROM geometry_columns WHERE f_table_name='spatial_test'").to_i)
|
100
100
|
end
|
101
|
-
|
102
|
-
|
101
|
+
|
102
|
+
|
103
103
|
def test_create_point_geometry
|
104
104
|
klass_ = create_ar_class
|
105
105
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -108,8 +108,8 @@ module RGeo
|
|
108
108
|
assert_equal(::RGeo::Feature::Point, klass_.columns.last.geometric_type)
|
109
109
|
assert(klass_.cached_attributes.include?('latlon'))
|
110
110
|
end
|
111
|
-
|
112
|
-
|
111
|
+
|
112
|
+
|
113
113
|
def test_create_geometry_with_index
|
114
114
|
klass_ = create_ar_class
|
115
115
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -123,8 +123,8 @@ module RGeo
|
|
123
123
|
klass_.connection.drop_table(:spatial_test)
|
124
124
|
assert_equal(0, klass_.connection.select_value("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='idx_spatial_test_latlon'").to_i)
|
125
125
|
end
|
126
|
-
|
127
|
-
|
126
|
+
|
127
|
+
|
128
128
|
def test_set_and_get_point
|
129
129
|
klass_ = populate_ar_class(:latlon_point)
|
130
130
|
obj_ = klass_.new
|
@@ -133,8 +133,8 @@ module RGeo
|
|
133
133
|
assert_equal(@factory.point(1, 2), obj_.latlon)
|
134
134
|
assert_equal(3785, obj_.latlon.srid)
|
135
135
|
end
|
136
|
-
|
137
|
-
|
136
|
+
|
137
|
+
|
138
138
|
def test_set_and_get_point_from_wkt
|
139
139
|
klass_ = populate_ar_class(:latlon_point)
|
140
140
|
obj_ = klass_.new
|
@@ -143,8 +143,8 @@ module RGeo
|
|
143
143
|
assert_equal(@factory.point(1, 2), obj_.latlon)
|
144
144
|
assert_equal(3785, obj_.latlon.srid)
|
145
145
|
end
|
146
|
-
|
147
|
-
|
146
|
+
|
147
|
+
|
148
148
|
if false
|
149
149
|
def test_save_and_load_point
|
150
150
|
klass_ = populate_ar_class(:latlon_point)
|
@@ -156,8 +156,8 @@ if false
|
|
156
156
|
assert_equal(@factory.point(1, 2), obj2_.latlon)
|
157
157
|
assert_equal(3785, obj2_.latlon.srid)
|
158
158
|
end
|
159
|
-
|
160
|
-
|
159
|
+
|
160
|
+
|
161
161
|
def test_save_and_load_point_from_wkt
|
162
162
|
klass_ = populate_ar_class(:latlon_point)
|
163
163
|
obj_ = klass_.new
|
@@ -169,8 +169,8 @@ if false
|
|
169
169
|
assert_equal(3785, obj2_.latlon.srid)
|
170
170
|
end
|
171
171
|
end
|
172
|
-
|
173
|
-
|
172
|
+
|
173
|
+
|
174
174
|
def test_add_column
|
175
175
|
klass_ = create_ar_class
|
176
176
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -188,8 +188,8 @@ end
|
|
188
188
|
assert_equal(4326, cols_[-2].srid)
|
189
189
|
assert_nil(cols_[-1].geometric_type)
|
190
190
|
end
|
191
|
-
|
192
|
-
|
191
|
+
|
192
|
+
|
193
193
|
def test_readme_example
|
194
194
|
klass_ = create_ar_class
|
195
195
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -211,8 +211,8 @@ end
|
|
211
211
|
rec_.shape = loc_
|
212
212
|
assert_equal(true, ::RGeo::Geos.is_geos?(rec_.shape))
|
213
213
|
end
|
214
|
-
|
215
|
-
|
214
|
+
|
215
|
+
|
216
216
|
def test_create_simple_geometry_using_shortcut
|
217
217
|
klass_ = create_ar_class
|
218
218
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -224,8 +224,8 @@ end
|
|
224
224
|
klass_.connection.drop_table(:spatial_test)
|
225
225
|
assert_equal(0, klass_.connection.select_value("SELECT COUNT(*) FROM geometry_columns WHERE f_table_name='spatial_test'").to_i)
|
226
226
|
end
|
227
|
-
|
228
|
-
|
227
|
+
|
228
|
+
|
229
229
|
def test_create_point_geometry_using_shortcut
|
230
230
|
klass_ = create_ar_class
|
231
231
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -234,8 +234,8 @@ end
|
|
234
234
|
assert_equal(::RGeo::Feature::Point, klass_.columns.last.geometric_type)
|
235
235
|
assert(klass_.cached_attributes.include?('latlon'))
|
236
236
|
end
|
237
|
-
|
238
|
-
|
237
|
+
|
238
|
+
|
239
239
|
def test_create_geometry_with_options
|
240
240
|
klass_ = create_ar_class
|
241
241
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -250,8 +250,8 @@ end
|
|
250
250
|
klass_.connection.drop_table(:spatial_test)
|
251
251
|
assert_equal(0, klass_.connection.select_value("SELECT COUNT(*) FROM geometry_columns WHERE f_table_name='spatial_test'").to_i)
|
252
252
|
end
|
253
|
-
|
254
|
-
|
253
|
+
|
254
|
+
|
255
255
|
def test_create_geometry_using_limit
|
256
256
|
klass_ = create_ar_class
|
257
257
|
klass_.connection.create_table(:spatial_test) do |t_|
|
@@ -266,12 +266,12 @@ end
|
|
266
266
|
klass_.connection.drop_table(:spatial_test)
|
267
267
|
assert_equal(0, klass_.connection.select_value("SELECT COUNT(*) FROM geometry_columns WHERE f_table_name='spatial_test'").to_i)
|
268
268
|
end
|
269
|
-
|
270
|
-
|
269
|
+
|
270
|
+
|
271
271
|
end
|
272
|
-
|
272
|
+
|
273
273
|
end
|
274
|
-
|
274
|
+
|
275
275
|
end
|
276
276
|
end
|
277
277
|
end
|
data/test/tc_spatial_queries.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# Tests for the MysqlSpatial ActiveRecord adapter
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
# Copyright 2010 Daniel Azuma
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# All rights reserved.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# Redistribution and use in source and binary forms, with or without
|
11
11
|
# modification, are permitted provided that the following conditions are met:
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# * Redistributions of source code must retain the above copyright notice,
|
14
14
|
# this list of conditions and the following disclaimer.
|
15
15
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# * Neither the name of the copyright holder, nor the names of any other
|
19
19
|
# contributors to this software, may be used to endorse or promote products
|
20
20
|
# derived from this software without specific prior written permission.
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
23
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
24
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
@@ -41,29 +41,29 @@ module RGeo
|
|
41
41
|
module ActiveRecord # :nodoc:
|
42
42
|
module SpatiaLiteAdapter # :nodoc:
|
43
43
|
module Tests # :nodoc:
|
44
|
-
|
44
|
+
|
45
45
|
class TestSpatialQueries < ::Test::Unit::TestCase # :nodoc:
|
46
|
-
|
47
|
-
|
46
|
+
|
47
|
+
|
48
48
|
DATABASE_CONFIG_PATH = ::File.dirname(__FILE__)+'/database.yml'
|
49
|
-
|
49
|
+
|
50
50
|
def self.before_open_database(params_)
|
51
51
|
database_ = params_[:config][:database]
|
52
52
|
dir_ = ::File.dirname(database_)
|
53
53
|
::FileUtils.mkdir_p(dir_) unless dir_ == '.'
|
54
54
|
::FileUtils.rm_f(database_)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def self.initialize_database(params_)
|
58
58
|
params_[:connection].execute('SELECT InitSpatialMetaData()')
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
include AdapterTestHelper
|
62
|
-
|
63
|
-
|
62
|
+
|
63
|
+
|
64
64
|
define_test_methods do
|
65
|
-
|
66
|
-
|
65
|
+
|
66
|
+
|
67
67
|
def populate_ar_class(content_)
|
68
68
|
klass_ = create_ar_class
|
69
69
|
case content_
|
@@ -78,8 +78,8 @@ module RGeo
|
|
78
78
|
end
|
79
79
|
klass_
|
80
80
|
end
|
81
|
-
|
82
|
-
|
81
|
+
|
82
|
+
|
83
83
|
def test_query_point
|
84
84
|
klass_ = populate_ar_class(:latlon_point)
|
85
85
|
obj_ = klass_.new
|
@@ -91,8 +91,8 @@ module RGeo
|
|
91
91
|
obj3_ = klass_.where(:latlon => @factory.point(2, 2)).first
|
92
92
|
assert_nil(obj3_)
|
93
93
|
end
|
94
|
-
|
95
|
-
|
94
|
+
|
95
|
+
|
96
96
|
def _test_query_point_wkt
|
97
97
|
klass_ = populate_ar_class(:latlon_point)
|
98
98
|
obj_ = klass_.new
|
@@ -104,11 +104,23 @@ module RGeo
|
|
104
104
|
obj3_ = klass_.where(:latlon => 'POINT(2 2)').first
|
105
105
|
assert_nil(obj3_)
|
106
106
|
end
|
107
|
-
|
108
|
-
|
107
|
+
|
108
|
+
|
109
|
+
def test_nil_spatial_column
|
110
|
+
klass_ = populate_ar_class(:latlon_point)
|
111
|
+
obj_ = klass_.new
|
112
|
+
assert_nil(obj_.latlon)
|
113
|
+
obj_.save!
|
114
|
+
id_ = obj_.id
|
115
|
+
obj2_ = klass_.find(id_)
|
116
|
+
assert_equal(id_, obj2_.id)
|
117
|
+
assert_nil(obj2_.latlon)
|
118
|
+
end
|
119
|
+
|
120
|
+
|
109
121
|
if ::RGeo::ActiveRecord.spatial_expressions_supported?
|
110
|
-
|
111
|
-
|
122
|
+
|
123
|
+
|
112
124
|
def test_query_st_distance
|
113
125
|
klass_ = populate_ar_class(:latlon_point)
|
114
126
|
obj_ = klass_.new
|
@@ -120,8 +132,8 @@ module RGeo
|
|
120
132
|
obj3_ = klass_.where(klass_.arel_table[:latlon].st_distance('POINT(2 3)').gt(2)).first
|
121
133
|
assert_nil(obj3_)
|
122
134
|
end
|
123
|
-
|
124
|
-
|
135
|
+
|
136
|
+
|
125
137
|
def test_query_st_distance_from_constant
|
126
138
|
klass_ = populate_ar_class(:latlon_point)
|
127
139
|
obj_ = klass_.new
|
@@ -133,8 +145,8 @@ module RGeo
|
|
133
145
|
obj3_ = klass_.where(::Arel.spatial('POINT(2 3)').st_distance(klass_.arel_table[:latlon]).gt(2)).first
|
134
146
|
assert_nil(obj3_)
|
135
147
|
end
|
136
|
-
|
137
|
-
|
148
|
+
|
149
|
+
|
138
150
|
def test_query_st_length
|
139
151
|
klass_ = populate_ar_class(:path_linestring)
|
140
152
|
obj_ = klass_.new
|
@@ -146,19 +158,19 @@ module RGeo
|
|
146
158
|
obj3_ = klass_.where(klass_.arel_table[:path].st_length.gt(3)).first
|
147
159
|
assert_nil(obj3_)
|
148
160
|
end
|
149
|
-
|
150
|
-
|
161
|
+
|
162
|
+
|
151
163
|
else
|
152
|
-
|
164
|
+
|
153
165
|
puts "WARNING: The current Arel does not support named functions. Spatial expression tests skipped."
|
154
|
-
|
166
|
+
|
155
167
|
end
|
156
|
-
|
157
|
-
|
168
|
+
|
169
|
+
|
158
170
|
end
|
159
|
-
|
171
|
+
|
160
172
|
end
|
161
|
-
|
173
|
+
|
162
174
|
end
|
163
175
|
end
|
164
176
|
end
|