elasticsearch-api 0.4.11 → 1.0.0.rc1
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.
- data/Gemfile +2 -6
- data/README.md +3 -4
- data/lib/elasticsearch/api.rb +16 -9
- data/lib/elasticsearch/api/actions/cat/aliases.rb +67 -0
- data/lib/elasticsearch/api/actions/cat/allocation.rb +69 -0
- data/lib/elasticsearch/api/actions/cat/count.rb +59 -0
- data/lib/elasticsearch/api/actions/cat/health.rb +43 -0
- data/lib/elasticsearch/api/actions/cat/help.rb +25 -0
- data/lib/elasticsearch/api/actions/cat/indices.rb +77 -0
- data/lib/elasticsearch/api/actions/cat/master.rb +40 -0
- data/lib/elasticsearch/api/actions/cat/nodes.rb +38 -0
- data/lib/elasticsearch/api/actions/cat/pending_tasks.rb +40 -0
- data/lib/elasticsearch/api/actions/cat/recovery.rb +73 -0
- data/lib/elasticsearch/api/actions/cat/shards.rb +72 -0
- data/lib/elasticsearch/api/actions/cluster/put_settings.rb +3 -1
- data/lib/elasticsearch/api/actions/cluster/state.rb +23 -14
- data/lib/elasticsearch/api/actions/count_percolate.rb +78 -0
- data/lib/elasticsearch/api/actions/indices/exists.rb +4 -1
- data/lib/elasticsearch/api/actions/indices/exists_alias.rb +5 -3
- data/lib/elasticsearch/api/actions/indices/exists_template.rb +34 -0
- data/lib/elasticsearch/api/actions/indices/exists_type.rb +4 -1
- data/lib/elasticsearch/api/actions/indices/get_alias.rb +5 -3
- data/lib/elasticsearch/api/actions/indices/get_aliases.rb +6 -3
- data/lib/elasticsearch/api/actions/indices/get_field_mapping.rb +2 -1
- data/lib/elasticsearch/api/actions/indices/get_mapping.rb +8 -3
- data/lib/elasticsearch/api/actions/indices/get_settings.rb +7 -2
- data/lib/elasticsearch/api/actions/indices/get_warmer.rb +0 -2
- data/lib/elasticsearch/api/actions/indices/put_alias.rb +0 -1
- data/lib/elasticsearch/api/actions/indices/put_mapping.rb +11 -4
- data/lib/elasticsearch/api/actions/indices/put_warmer.rb +0 -1
- data/lib/elasticsearch/api/actions/mpercolate.rb +58 -0
- data/lib/elasticsearch/api/actions/mtermvectors.rb +67 -0
- data/lib/elasticsearch/api/actions/{cluster/node_hot_threads.rb → nodes/hot_threads.rb} +3 -3
- data/lib/elasticsearch/api/actions/{cluster/node_info.rb → nodes/info.rb} +3 -3
- data/lib/elasticsearch/api/actions/{cluster/node_shutdown.rb → nodes/shutdown.rb} +3 -3
- data/lib/elasticsearch/api/actions/nodes/stats.rb +79 -0
- data/lib/elasticsearch/api/actions/percolate.rb +67 -21
- data/lib/elasticsearch/api/actions/snapshot/create.rb +48 -0
- data/lib/elasticsearch/api/actions/snapshot/create_repository.rb +44 -0
- data/lib/elasticsearch/api/actions/snapshot/delete.rb +41 -0
- data/lib/elasticsearch/api/actions/snapshot/delete_repository.rb +38 -0
- data/lib/elasticsearch/api/actions/snapshot/get.rb +47 -0
- data/lib/elasticsearch/api/actions/snapshot/get_repository.rb +42 -0
- data/lib/elasticsearch/api/actions/snapshot/restore.rb +53 -0
- data/lib/elasticsearch/api/actions/termvector.rb +77 -0
- data/lib/elasticsearch/api/namespace/cat.rb +20 -0
- data/lib/elasticsearch/api/namespace/nodes.rb +20 -0
- data/lib/elasticsearch/api/namespace/snapshot.rb +20 -0
- data/lib/elasticsearch/api/utils.rb +2 -4
- data/lib/elasticsearch/api/version.rb +1 -1
- data/test/integration/yaml_test_runner.rb +37 -8
- data/test/unit/cat/aliases_test.rb +26 -0
- data/test/unit/cat/allocation_test.rb +26 -0
- data/test/unit/cat/count_test.rb +26 -0
- data/test/unit/cat/health_test.rb +26 -0
- data/test/unit/cat/help_test.rb +26 -0
- data/test/unit/cat/indices_test.rb +26 -0
- data/test/unit/cat/master_test.rb +26 -0
- data/test/unit/cat/nodes_test.rb +26 -0
- data/test/unit/cat/pending_tasks_test.rb +26 -0
- data/test/unit/cat/recovery_test.rb +26 -0
- data/test/unit/cat/shards_test.rb +26 -0
- data/test/unit/cluster/state_test.rb +12 -3
- data/test/unit/count_percolate_test.rb +26 -0
- data/test/unit/indices/exists_alias_test.rb +0 -6
- data/test/unit/indices/exists_template_test.rb +59 -0
- data/test/unit/indices/get_alias_test.rb +0 -6
- data/test/unit/indices/get_aliases_test.rb +10 -0
- data/test/unit/indices/get_field_mapping_test.rb +1 -1
- data/test/unit/indices/get_mapping_test.rb +3 -3
- data/test/unit/indices/get_settings_test.rb +10 -0
- data/test/unit/indices/get_warmer_test.rb +0 -6
- data/test/unit/indices/put_alias_test.rb +0 -6
- data/test/unit/indices/put_mapping_test.rb +5 -11
- data/test/unit/indices/put_settings_test.rb +9 -0
- data/test/unit/indices/put_warmer_test.rb +0 -6
- data/test/unit/mpercolate_test.rb +51 -0
- data/test/unit/mtermvectors_test.rb +38 -0
- data/test/unit/{cluster/node_hot_threads_test.rb → nodes/hot_threads_test.rb} +5 -5
- data/test/unit/{cluster/node_info_test.rb → nodes/info_test.rb} +6 -6
- data/test/unit/{cluster/node_shutdown_test.rb → nodes/shutdown_test.rb} +6 -6
- data/test/unit/{cluster/node_stats_test.rb → nodes/stats_test.rb} +10 -10
- data/test/unit/percolate_test.rb +2 -13
- data/test/unit/snapshot/create_repository_test.rb +38 -0
- data/test/unit/snapshot/create_test.rb +38 -0
- data/test/unit/snapshot/delete_repository_test.rb +35 -0
- data/test/unit/snapshot/delete_test.rb +38 -0
- data/test/unit/snapshot/get_repository_test.rb +26 -0
- data/test/unit/snapshot/get_test.rb +38 -0
- data/test/unit/snapshot/restore_test.rb +38 -0
- data/test/unit/termvector_test.rb +44 -0
- data/test/unit/utils_test.rb +11 -0
- metadata +89 -17
- data/lib/elasticsearch/api/actions/cluster/node_stats.rb +0 -75
@@ -0,0 +1,20 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module API
|
3
|
+
module Cat
|
4
|
+
module Actions; end
|
5
|
+
|
6
|
+
# Client for the "cat" namespace (includes the {Cat::Actions} methods)
|
7
|
+
#
|
8
|
+
class CatClient
|
9
|
+
include Common::Client, Common::Client::Base, Cat::Actions
|
10
|
+
end
|
11
|
+
|
12
|
+
# Proxy method for {CatClient}, available in the receiving object
|
13
|
+
#
|
14
|
+
def cat
|
15
|
+
@cat ||= CatClient.new(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module API
|
3
|
+
module Nodes
|
4
|
+
module Actions; end
|
5
|
+
|
6
|
+
# Client for the "nodes" namespace (includes the {Nodes::Actions} methods)
|
7
|
+
#
|
8
|
+
class NodesClient
|
9
|
+
include Common::Client, Common::Client::Base, Nodes::Actions
|
10
|
+
end
|
11
|
+
|
12
|
+
# Proxy method for {NodesClient}, available in the receiving object
|
13
|
+
#
|
14
|
+
def nodes
|
15
|
+
@nodes ||= NodesClient.new(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module API
|
3
|
+
module Snapshot
|
4
|
+
module Actions; end
|
5
|
+
|
6
|
+
# Client for the "snapshot" namespace (includes the {Snapshot::Actions} methods)
|
7
|
+
#
|
8
|
+
class SnapshotClient
|
9
|
+
include Common::Client, Common::Client::Base, Snapshot::Actions
|
10
|
+
end
|
11
|
+
|
12
|
+
# Proxy method for {SnapshotClient}, available in the receiving object
|
13
|
+
#
|
14
|
+
def snapshot
|
15
|
+
@snapshot ||= SnapshotClient.new(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -30,8 +30,6 @@ module Elasticsearch
|
|
30
30
|
#
|
31
31
|
# @api private
|
32
32
|
def __listify(*list)
|
33
|
-
# require 'pry'
|
34
|
-
# binding.pry
|
35
33
|
Array(list).flatten.
|
36
34
|
map { |e| e.respond_to?(:split) ? e.split(',') : e }.
|
37
35
|
flatten.
|
@@ -124,10 +122,10 @@ module Elasticsearch
|
|
124
122
|
def __validate_and_extract_params(arguments, valid_params=[])
|
125
123
|
arguments.each do |k,v|
|
126
124
|
raise ArgumentError, "URL parameter '#{k}' is not supported" \
|
127
|
-
unless
|
125
|
+
unless COMMON_PARAMS.include?(k) || COMMON_QUERY_PARAMS.include?(k) || valid_params.include?(k)
|
128
126
|
end
|
129
127
|
|
130
|
-
params = arguments.select { |k,v| valid_params.include?(k) }
|
128
|
+
params = arguments.select { |k,v| COMMON_QUERY_PARAMS.include?(k) || valid_params.include?(k) }
|
131
129
|
params = Hash[params] unless params.is_a?(Hash) # Normalize Ruby 1.8 and Ruby 1.9 Hash#select behaviour
|
132
130
|
params
|
133
131
|
end
|
@@ -13,6 +13,9 @@ require 'elasticsearch/extensions/test/cluster'
|
|
13
13
|
require 'elasticsearch/extensions/test/startup_shutdown'
|
14
14
|
require 'elasticsearch/extensions/test/profiling' unless JRUBY
|
15
15
|
|
16
|
+
# Skip features
|
17
|
+
SKIP_FEATURES = ENV['TEST_SKIP_FEATURES'] || ''
|
18
|
+
|
16
19
|
# Turn configuration
|
17
20
|
ENV['ansi'] = 'false' if ENV['CI']
|
18
21
|
Turn.config.format = :pretty
|
@@ -215,7 +218,9 @@ module Elasticsearch
|
|
215
218
|
|
216
219
|
def skip?(actions)
|
217
220
|
skip = actions.select { |a| a['skip'] }.first
|
218
|
-
|
221
|
+
|
222
|
+
# Skip version
|
223
|
+
if skip && skip['skip']['version']
|
219
224
|
min, max = skip['skip']['version'].split('-').map(&:strip)
|
220
225
|
|
221
226
|
min_normalized = sprintf "%03d-%03d-%03d",
|
@@ -234,7 +239,14 @@ module Elasticsearch
|
|
234
239
|
if min_normalized <= es_normalized && max_normalized >= es_normalized
|
235
240
|
return skip['skip']['reason'] ? skip['skip']['reason'] : true
|
236
241
|
end
|
242
|
+
|
243
|
+
# Skip features
|
244
|
+
elsif skip && skip['skip']['features']
|
245
|
+
if (skip['skip']['features'].split(',') & SKIP_FEATURES.split(',') ).size > 0
|
246
|
+
return skip['skip']['features']
|
247
|
+
end
|
237
248
|
end
|
249
|
+
|
238
250
|
return false
|
239
251
|
end
|
240
252
|
|
@@ -278,9 +290,11 @@ suites.each do |suite|
|
|
278
290
|
# Extract setup actions
|
279
291
|
setup_actions = tests.select { |t| t['setup'] }.first['setup'] rescue []
|
280
292
|
|
281
|
-
# Skip all the tests when `skip` is part
|
282
|
-
|
283
|
-
|
293
|
+
# Skip all the tests when `skip` is part of the `setup` part
|
294
|
+
if features = Runner.skip?(setup_actions)
|
295
|
+
$stdout.puts "#{'SKIP'.ansi(:yellow)} [#{name}] #{file.gsub(PATH.to_s, '').ansi(:bold)} (Feature not implemented: #{features})"
|
296
|
+
next
|
297
|
+
end
|
284
298
|
|
285
299
|
# Remove setup actions from tests
|
286
300
|
tests = tests.reject { |t| t['setup'] }
|
@@ -365,10 +379,25 @@ suites.each do |suite|
|
|
365
379
|
when a = action['match']
|
366
380
|
property, value = a.to_a.first
|
367
381
|
|
368
|
-
value
|
369
|
-
|
370
|
-
|
371
|
-
|
382
|
+
if value.is_a?(String) && value =~ %r{\s*^/\s*.*\s*/$\s*}mx # Begins and ends with /
|
383
|
+
pattern = Regexp.new(value.strip[1..-2], Regexp::EXTENDED|Regexp::MULTILINE)
|
384
|
+
else
|
385
|
+
value = Runner.fetch_or_return(value)
|
386
|
+
end
|
387
|
+
|
388
|
+
if property == '$body'
|
389
|
+
result = $results[test.hash]
|
390
|
+
else
|
391
|
+
result = Runner.evaluate(test, property)
|
392
|
+
end
|
393
|
+
|
394
|
+
if pattern
|
395
|
+
$stderr.puts "CHECK: Expected '#{property}' to match #{pattern}, is: #{result.inspect}" if ENV['DEBUG']
|
396
|
+
assert_match(pattern, result)
|
397
|
+
else
|
398
|
+
$stderr.puts "CHECK: Expected '#{property}' to be '#{value}', is: #{result.inspect}" if ENV['DEBUG']
|
399
|
+
assert_equal(value, result)
|
400
|
+
end
|
372
401
|
|
373
402
|
when a = action['length']
|
374
403
|
property, value = a.to_a.first
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatAliasesTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Aliases" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/aliases', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.aliases
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatAllocationTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Allocation" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/allocation', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.allocation
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatCountTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Count" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/count', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.count
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatHealthTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Health" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/health', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.health
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatHelpTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Help" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.help
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatIndicesTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Indices" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/indices', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.indices
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatMasterTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Master" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/master', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.master
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatNodesTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Nodes" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/nodes', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.nodes
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatPendingTasksTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Pending tasks" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/pending_tasks', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.pending_tasks
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Test
|
5
|
+
class CatRecoveryTest < ::Test::Unit::TestCase
|
6
|
+
|
7
|
+
context "Cat: Recovery" do
|
8
|
+
subject { FakeClient.new }
|
9
|
+
|
10
|
+
should "perform correct request" do
|
11
|
+
subject.expects(:perform_request).with do |method, url, params, body|
|
12
|
+
assert_equal 'GET', method
|
13
|
+
assert_equal '_cat/recovery', url
|
14
|
+
assert_equal Hash.new, params
|
15
|
+
assert_nil body
|
16
|
+
true
|
17
|
+
end.returns(FakeResponse.new)
|
18
|
+
|
19
|
+
subject.cat.recovery
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|