sunstone 5.0.1.3 → 5.0.1.4
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.
- checksums.yaml +4 -4
- data/Rakefile.rb +2 -2
- data/ext/active_record/associations.rb +52 -0
- data/ext/active_record/persistence.rb +11 -0
- data/ext/active_record/relation.rb +23 -0
- data/ext/active_record/transactions.rb +12 -4
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +1 -2
- data/lib/arel/collectors/sunstone.rb +9 -7
- data/lib/arel/visitors/sunstone.rb +118 -93
- data/lib/sunstone.rb +1 -0
- data/lib/sunstone/version.rb +1 -1
- data/sunstone.gemspec +4 -3
- data/test/active_record/associations/has_and_belongs_to_many_test.rb +25 -2
- data/test/active_record/associations/has_many_test.rb +28 -4
- data/test/active_record/eager_loading_test.rb +37 -2
- data/test/active_record/persistance_test.rb +72 -10
- data/test/active_record/preload_test.rb +39 -4
- data/test/active_record/query/all_test.rb +33 -0
- data/test/active_record/query/count_test.rb +38 -0
- data/test/active_record/query/distinct_test.rb +30 -0
- data/test/active_record/query/find_test.rb +37 -0
- data/test/active_record/query/where_test.rb +79 -0
- data/test/active_record/query_test.rb +53 -112
- data/test/schema_mock.rb +117 -0
- data/test/sunstone/connection/configuration_test.rb +1 -1
- data/test/sunstone/connection/cookie_store_test.rb +1 -1
- data/test/sunstone/connection/request_helper_test.rb +1 -1
- data/test/sunstone/connection/send_request_test.rb +1 -1
- data/test/sunstone/connection_test.rb +1 -1
- data/test/test_helper.rb +7 -4
- metadata +23 -26
- data/test/models.rb +0 -115
data/lib/sunstone.rb
CHANGED
@@ -21,6 +21,7 @@ require File.expand_path(File.join(__FILE__, '../arel/collectors/sunstone'))
|
|
21
21
|
|
22
22
|
# ActiveRecord Extensions
|
23
23
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/statement_cache'))
|
24
|
+
require File.expand_path(File.join(__FILE__, '../../ext/active_record/associations'))
|
24
25
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/relation'))
|
25
26
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/relation/calculations'))
|
26
27
|
require File.expand_path(File.join(__FILE__, '../../ext/active_record/persistence'))
|
data/lib/sunstone/version.rb
CHANGED
data/sunstone.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
# Developoment
|
18
18
|
s.add_development_dependency 'rake'
|
19
19
|
s.add_development_dependency 'rdoc'
|
20
|
-
s.add_development_dependency 'sdoc'
|
20
|
+
# s.add_development_dependency 'sdoc'
|
21
21
|
s.add_development_dependency 'bundler'
|
22
22
|
s.add_development_dependency 'minitest'
|
23
23
|
s.add_development_dependency 'minitest-reporters'
|
@@ -25,11 +25,12 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_development_dependency 'faker'
|
26
26
|
s.add_development_dependency 'factory_girl'
|
27
27
|
s.add_development_dependency 'webmock'
|
28
|
-
s.add_development_dependency 'sdoc-templates-42floors'
|
28
|
+
#s.add_development_dependency 'sdoc-templates-42floors'
|
29
29
|
s.add_development_dependency 'rgeo'
|
30
30
|
s.add_development_dependency 'simplecov'
|
31
31
|
s.add_development_dependency 'byebug'
|
32
|
-
|
32
|
+
s.add_development_dependency 'activesupport', '~> 5.0.1'
|
33
|
+
|
33
34
|
# Runtime
|
34
35
|
s.add_runtime_dependency 'msgpack'
|
35
36
|
s.add_runtime_dependency 'cookie_store'
|
@@ -1,10 +1,33 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ActiveRecord::Associations::HasAndBelongsToManyTest <
|
3
|
+
class ActiveRecord::Associations::HasAndBelongsToManyTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships" do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table "sailors" do |t|
|
11
|
+
t.string "name", limit: 255
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table "sailors_ships", id: false do |t|
|
15
|
+
t.integer "ship_id", null: false
|
16
|
+
t.integer "sailor_id", null: false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Ship < ActiveRecord::Base
|
21
|
+
has_and_belongs_to_many :sailors
|
22
|
+
end
|
23
|
+
|
24
|
+
class Sailor < ActiveRecord::Base
|
25
|
+
has_and_belongs_to_many :ships
|
26
|
+
end
|
4
27
|
|
5
28
|
test '#relation_ids' do
|
6
29
|
webmock(:get, "/ships", where: {id: 42}, limit: 1).to_return(body: [{id: 42, name: "The Niña"}].to_json)
|
7
|
-
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 42}}}
|
30
|
+
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 42}}}).to_return(body: [{id: 43, name: "Chris"}].to_json)
|
8
31
|
|
9
32
|
assert_equal [43], Ship.find(42).sailor_ids
|
10
33
|
end
|
@@ -1,9 +1,28 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ActiveRecord::Associations::HasManyTest <
|
3
|
+
class ActiveRecord::Associations::HasManyTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships" do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
t.integer "fleet_id"
|
9
|
+
end
|
4
10
|
|
11
|
+
create_table "fleets" do |t|
|
12
|
+
t.string "name", limit: 255
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Fleet < ActiveRecord::Base
|
17
|
+
has_many :ships
|
18
|
+
end
|
19
|
+
|
20
|
+
class Ship < ActiveRecord::Base
|
21
|
+
belongs_to :fleet
|
22
|
+
end
|
23
|
+
|
5
24
|
test '#create with has_many_ids=' do
|
6
|
-
webmock(:get, "/ships", where: {id: 2}
|
25
|
+
webmock(:get, "/ships", where: {id: 2}).to_return(body: [{id: 2, fleet_id: nil, name: 'Duo'}].to_json)
|
7
26
|
webmock(:post, "/fleets").with(
|
8
27
|
body: {
|
9
28
|
fleet: {
|
@@ -19,8 +38,8 @@ class ActiveRecord::Associations::HasManyTest < Minitest::Test
|
|
19
38
|
|
20
39
|
test '#update with has_many_ids=' do
|
21
40
|
webmock(:get, "/fleets", where: {id: 42}, limit: 1).to_return(body: [{id: 42, name: "Spanish Armada"}].to_json)
|
22
|
-
webmock(:get, "/ships", where:
|
23
|
-
webmock(:get, "/ships", where:
|
41
|
+
webmock(:get, "/ships", where: {id: 2}).to_return(body: [{id: 2, fleet_id: nil, name: 'Duo'}].to_json)
|
42
|
+
webmock(:get, "/ships", where: {fleet_id: 42}).to_return(body: [].to_json)
|
24
43
|
|
25
44
|
webmock(:patch, "/fleets/42").with(
|
26
45
|
body: {
|
@@ -68,5 +87,10 @@ class ActiveRecord::Associations::HasManyTest < Minitest::Test
|
|
68
87
|
|
69
88
|
assert_requested req_stub
|
70
89
|
end
|
90
|
+
|
91
|
+
# test 'relation#delete_all' do
|
92
|
+
# webmock(:get, "/fleets", where: {id: 42}, limit: 1).to_return(body: [{id: 42, name: "Spanish Armada"}].to_json)
|
93
|
+
# Fleet.find(42).ships.delete_all
|
94
|
+
# end
|
71
95
|
|
72
96
|
end
|
@@ -1,6 +1,41 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ActiveRecord::EagerLoadingTest <
|
3
|
+
class ActiveRecord::EagerLoadingTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships" do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
t.integer "fleet_id"
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table "fleets" do |t|
|
12
|
+
t.string "name", limit: 255
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table "sailors" do |t|
|
16
|
+
t.string "name", limit: 255
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table "sailors_ships", id: false do |t|
|
20
|
+
t.integer "ship_id", null: false
|
21
|
+
t.integer "sailor_id", null: false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class Fleet < ActiveRecord::Base
|
27
|
+
has_many :ships
|
28
|
+
end
|
29
|
+
|
30
|
+
class Ship < ActiveRecord::Base
|
31
|
+
belongs_to :fleet
|
32
|
+
|
33
|
+
has_and_belongs_to_many :sailors
|
34
|
+
end
|
35
|
+
|
36
|
+
class Sailor < ActiveRecord::Base
|
37
|
+
has_and_belongs_to_many :ships
|
38
|
+
end
|
4
39
|
|
5
40
|
test '#eager_load' do
|
6
41
|
webmock(:get, "/fleets", include: [{:ships => :sailors}]).to_return(body: [{
|
@@ -12,4 +47,4 @@ class ActiveRecord::EagerLoadingTest < Minitest::Test
|
|
12
47
|
assert_equal [1], fleets.first.ships.map(&:id)
|
13
48
|
end
|
14
49
|
|
15
|
-
end
|
50
|
+
end
|
@@ -1,10 +1,46 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ActiveRecord::PersistanceTest <
|
3
|
+
class ActiveRecord::PersistanceTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships" do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
t.integer "fleet_id"
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table "fleets" do |t|
|
12
|
+
t.string "name", limit: 255
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table "sailors" do |t|
|
16
|
+
t.string "name", limit: 255
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table "sailors_ships", id: false do |t|
|
20
|
+
t.integer "ship_id", null: false
|
21
|
+
t.integer "sailor_id", null: false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
4
25
|
|
5
|
-
class
|
26
|
+
class Fleet < ActiveRecord::Base
|
27
|
+
has_many :ships
|
6
28
|
end
|
7
|
-
|
29
|
+
|
30
|
+
class Ship < ActiveRecord::Base
|
31
|
+
belongs_to :fleet
|
32
|
+
|
33
|
+
has_and_belongs_to_many :sailors
|
34
|
+
end
|
35
|
+
|
36
|
+
class Sailor < ActiveRecord::Base
|
37
|
+
has_and_belongs_to_many :ships
|
38
|
+
end
|
39
|
+
|
40
|
+
class TestModelA < ActiveRecord::Base
|
41
|
+
end
|
42
|
+
|
43
|
+
class TestModelB < ActiveRecord::Base
|
8
44
|
before_save do
|
9
45
|
TestModelA.create
|
10
46
|
end
|
@@ -55,8 +91,7 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
55
91
|
columns: {
|
56
92
|
id: {type: 'integer', primary_key: true, null: false, array: false},
|
57
93
|
name: {type: 'string', primary_key: false, null: true, array: false}
|
58
|
-
}
|
59
|
-
limit: 100
|
94
|
+
}
|
60
95
|
}.to_json,
|
61
96
|
headers: { 'StandardAPI-Version' => '5.0.0.5' }
|
62
97
|
)
|
@@ -65,8 +100,7 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
65
100
|
columns: {
|
66
101
|
id: {type: 'integer', primary_key: true, null: false, array: false},
|
67
102
|
name: {type: 'string', primary_key: false, null: true, array: false}
|
68
|
-
}
|
69
|
-
limit: 100
|
103
|
+
}
|
70
104
|
}.to_json,
|
71
105
|
headers: { 'StandardAPI-Version' => '5.0.0.5' }
|
72
106
|
)
|
@@ -134,6 +168,21 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
134
168
|
|
135
169
|
assert_requested req_stub
|
136
170
|
end
|
171
|
+
|
172
|
+
test '#update!' do
|
173
|
+
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
174
|
+
body: [{id: 1, fleet_id: nil, name: 'Armada Uno'}].to_json
|
175
|
+
)
|
176
|
+
req_stub = webmock(:patch, "/ships").with(
|
177
|
+
body: { ship: { name: 'Armada Trio' } }.to_json
|
178
|
+
).to_return(
|
179
|
+
body: {id: 1, name: 'Armada Trio'}.to_json
|
180
|
+
)
|
181
|
+
|
182
|
+
Ship.find(1).update!(name: 'Armada Trio')
|
183
|
+
|
184
|
+
assert_requested req_stub
|
185
|
+
end
|
137
186
|
|
138
187
|
test '#update habtm relationships' do
|
139
188
|
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
@@ -142,7 +191,7 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
142
191
|
webmock(:get, "/sailors", where: {id: 1}, limit: 1).to_return(
|
143
192
|
body: [{id: 1, name: 'Captain'}].to_json
|
144
193
|
)
|
145
|
-
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 1}}}
|
194
|
+
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 1}}}).to_return(
|
146
195
|
body: [].to_json
|
147
196
|
)
|
148
197
|
req_stub = webmock(:patch, '/ships/1').with(
|
@@ -163,7 +212,7 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
163
212
|
webmock(:get, "/sailors", where: {id: 1}, limit: 1).to_return(
|
164
213
|
body: [{id: 1, name: 'Captain'}].to_json
|
165
214
|
)
|
166
|
-
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 1}}}
|
215
|
+
webmock(:get, "/sailors", where: {sailors_ships: {ship_id: {eq: 1}}}).to_return(
|
167
216
|
body: [{id: 1, name: 'Captain'}].to_json
|
168
217
|
)
|
169
218
|
req_stub = webmock(:patch, '/ships/1').with(
|
@@ -181,7 +230,7 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
181
230
|
webmock(:get, "/fleets", where: {id: 1}, limit: 1).to_return(
|
182
231
|
body: [{id: 1, name: 'Armada Uno'}].to_json
|
183
232
|
)
|
184
|
-
webmock(:get, "/ships", where: {fleet_id: 1}
|
233
|
+
webmock(:get, "/ships", where: {fleet_id: 1}).to_return(
|
185
234
|
body: [{id: 1, name: 'Saucer Trio'}].to_json
|
186
235
|
)
|
187
236
|
req_stub = webmock(:patch, '/fleets/1').with(
|
@@ -195,4 +244,17 @@ class ActiveRecord::PersistanceTest < Minitest::Test
|
|
195
244
|
assert_requested req_stub
|
196
245
|
end
|
197
246
|
|
247
|
+
test "#destroy with habtm relationship" do
|
248
|
+
webmock(:get, "/ships", where: {id: 1}, limit: 1).to_return(
|
249
|
+
body: [{id: 1, fleet_id: nil, name: 'Armada Uno'}].to_json
|
250
|
+
)
|
251
|
+
req_stub = webmock(:delete, '/ships/1').to_return(
|
252
|
+
status: 204
|
253
|
+
)
|
254
|
+
|
255
|
+
ship = Ship.find(1)
|
256
|
+
assert ship.destroy
|
257
|
+
assert_requested req_stub
|
258
|
+
end
|
259
|
+
|
198
260
|
end
|
@@ -1,12 +1,47 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class ActiveRecord::PreloadTest <
|
3
|
+
class ActiveRecord::PreloadTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships" do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
t.integer "fleet_id"
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table "fleets" do |t|
|
12
|
+
t.string "name", limit: 255
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table "sailors" do |t|
|
16
|
+
t.string "name", limit: 255
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table "sailors_ships", id: false do |t|
|
20
|
+
t.integer "ship_id", null: false
|
21
|
+
t.integer "sailor_id", null: false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
4
25
|
|
26
|
+
class Fleet < ActiveRecord::Base
|
27
|
+
has_many :ships
|
28
|
+
end
|
29
|
+
|
30
|
+
class Ship < ActiveRecord::Base
|
31
|
+
belongs_to :fleet
|
32
|
+
|
33
|
+
has_and_belongs_to_many :sailors
|
34
|
+
end
|
35
|
+
|
36
|
+
class Sailor < ActiveRecord::Base
|
37
|
+
has_and_belongs_to_many :ships
|
38
|
+
end
|
39
|
+
|
5
40
|
test '#preload' do
|
6
41
|
webmock(:get, "/fleets").to_return(body: [{id: 1}].to_json)
|
7
|
-
webmock(:get, "/ships", where: {fleet_id: 1}
|
8
|
-
webmock(:get, "/sailors_ships", where: {ship_id: 1}
|
9
|
-
webmock(:get, "/sailors", where: {id: 1}
|
42
|
+
webmock(:get, "/ships", where: {fleet_id: 1}).to_return(body: [{id: 1, fleet_id: 1}].to_json)
|
43
|
+
webmock(:get, "/sailors_ships", where: {ship_id: 1}).to_return(body: [{ship_id: 1, sailor_id: 1}].to_json)
|
44
|
+
webmock(:get, "/sailors", where: {id: 1}).to_return(body: [{id: 1}].to_json)
|
10
45
|
|
11
46
|
fleets = Fleet.preload(:ships => :sailors)
|
12
47
|
assert_equal [1], fleets.map(&:id)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::QueryAllTest < ActiveSupport::TestCase
|
4
|
+
schema do
|
5
|
+
create_table "ships" do |t|
|
6
|
+
t.string "name", limit: 255
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table "cars", limit: 100 do |t|
|
10
|
+
t.string "name", limit: 255
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Ship < ActiveRecord::Base
|
15
|
+
end
|
16
|
+
|
17
|
+
class Car < ActiveRecord::Base
|
18
|
+
end
|
19
|
+
|
20
|
+
test '::all' do
|
21
|
+
webmock(:get, "/ships").to_return(body: [{id: 42}].to_json)
|
22
|
+
assert_equal [Ship.new(id: 42)], Ship.all
|
23
|
+
end
|
24
|
+
|
25
|
+
test '::all w/resource_limit' do
|
26
|
+
cars = []
|
27
|
+
101.times { |i| cars << Car.new(id: i) }
|
28
|
+
webmock(:get, "/cars", { limit: 100, offset: 0 }).to_return(body: cars[0..100].to_json)
|
29
|
+
webmock(:get, "/cars", { limit: 100, offset: 100 }).to_return(body: cars[101..-1].to_json)
|
30
|
+
assert_equal cars, Car.all
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::QueryCountTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships", limit: 100 do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Ship < ActiveRecord::Base
|
12
|
+
end
|
13
|
+
|
14
|
+
test '::count' do
|
15
|
+
webmock(:get, "/ships/calculate", select: [{count: "*"}], limit: 100, offset: 0).to_return({
|
16
|
+
body: [10].to_json
|
17
|
+
})
|
18
|
+
|
19
|
+
assert_equal 10, Ship.count
|
20
|
+
end
|
21
|
+
|
22
|
+
test '::count(:column)' do
|
23
|
+
webmock(:get, "/ships/calculate", select: [{count: "id"}], limit: 100, offset: 0).to_return({
|
24
|
+
body: [10].to_json
|
25
|
+
})
|
26
|
+
|
27
|
+
assert_equal 10, Ship.count(:id)
|
28
|
+
end
|
29
|
+
|
30
|
+
test '::sum(:column)' do
|
31
|
+
webmock(:get, "/ships/calculate", select: [{sum: "weight"}], limit: 100, offset: 0).to_return({
|
32
|
+
body: [10].to_json
|
33
|
+
})
|
34
|
+
|
35
|
+
assert_equal 10, Ship.sum(:weight)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::QueryDistinctTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
schema do
|
6
|
+
create_table "ships", limit: 100 do |t|
|
7
|
+
t.string "name", limit: 255
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Ship < ActiveRecord::Base
|
12
|
+
end
|
13
|
+
|
14
|
+
# Distinct
|
15
|
+
test '::distinct query' do
|
16
|
+
webmock(:get, "/ships", distinct: true, limit: 100, offset: 0).to_return({
|
17
|
+
body: [].to_json
|
18
|
+
})
|
19
|
+
|
20
|
+
assert_equal [], Ship.distinct
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: i need arel-extensions....
|
24
|
+
# test '::distinct_on query' do
|
25
|
+
# webmock(:get, "/ships", distinct_on: ['id']).to_return(body: [].to_json)
|
26
|
+
#
|
27
|
+
# assert_equal [], Ship.distinct_on(:id)
|
28
|
+
# end
|
29
|
+
|
30
|
+
end
|