rundeck 0.0.3.pre → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/.rubocop_todo.yml +0 -10
  4. data/.travis.yml +1 -1
  5. data/lib/rundeck/client.rb +61 -3
  6. data/lib/rundeck/client/execution.rb +194 -0
  7. data/lib/rundeck/client/{jobs.rb → job.rb} +19 -36
  8. data/lib/rundeck/client/{keys.rb → key.rb} +42 -20
  9. data/lib/rundeck/configuration.rb +5 -1
  10. data/lib/rundeck/objectified_hash.rb +13 -3
  11. data/lib/rundeck/request.rb +7 -1
  12. data/lib/rundeck/version.rb +1 -1
  13. data/rundeck.gemspec +2 -1
  14. data/spec/cassettes/12/abort_execution_not_running.yml +41 -0
  15. data/spec/cassettes/12/abort_execution_valid.yml +41 -0
  16. data/spec/cassettes/12/abort_executions_invalid.yml +41 -0
  17. data/spec/cassettes/12/bulk_delete_executions_invalid.yml +46 -0
  18. data/spec/cassettes/12/bulk_delete_executions_valid.yml +41 -0
  19. data/spec/cassettes/12/create_private_key.yml +64 -0
  20. data/spec/cassettes/12/create_public_key.yml +38 -0
  21. data/spec/cassettes/12/delete_execution_invalid.yml +41 -0
  22. data/spec/cassettes/12/delete_execution_valid.yml +32 -0
  23. data/spec/cassettes/12/delete_job_executions.yml +41 -0
  24. data/spec/cassettes/12/delete_job_executions_invalid.yml +41 -0
  25. data/spec/cassettes/12/delete_job_invalid.yml +41 -0
  26. data/spec/cassettes/12/delete_job_valid.yml +32 -0
  27. data/spec/cassettes/12/delete_key_invalid.yml +41 -0
  28. data/spec/cassettes/12/delete_key_private.yml +32 -0
  29. data/spec/cassettes/12/delete_key_public.yml +32 -0
  30. data/spec/cassettes/12/execution_invalid.yml +41 -0
  31. data/spec/cassettes/12/execution_query_invalid.yml +39 -0
  32. data/spec/cassettes/12/execution_query_no_params_valid.yml +124 -0
  33. data/spec/cassettes/12/execution_state_invalid.yml +41 -0
  34. data/spec/cassettes/12/execution_state_valid.yml +39 -0
  35. data/spec/cassettes/12/execution_valid.yml +60 -0
  36. data/spec/cassettes/12/export_job_xml.yml +234 -0
  37. data/spec/cassettes/12/export_job_yaml.yml +228 -0
  38. data/spec/cassettes/12/import_job_xml.yml +69 -0
  39. data/spec/cassettes/12/import_job_yaml.yml +63 -0
  40. data/spec/cassettes/12/job.yml +84 -0
  41. data/spec/cassettes/12/job_executions.yml +96 -0
  42. data/spec/cassettes/12/jobs.yml +76 -0
  43. data/spec/cassettes/12/key_contents_direct.yml +67 -0
  44. data/spec/cassettes/12/key_contents_multiple.yml +38 -0
  45. data/spec/cassettes/12/key_contents_private.yml +35 -0
  46. data/spec/cassettes/12/key_metadata_direct.yml +35 -0
  47. data/spec/cassettes/12/key_metadata_multiple.yml +38 -0
  48. data/spec/cassettes/12/keys_direct.yml +35 -0
  49. data/spec/cassettes/12/keys_multiple.yml +38 -0
  50. data/spec/cassettes/12/keys_none.yml +34 -0
  51. data/spec/cassettes/12/run_job_invalid.yml +44 -0
  52. data/spec/cassettes/12/run_job_valid.yml +77 -0
  53. data/spec/cassettes/12/running_jobs_multiple.yml +70 -0
  54. data/spec/cassettes/12/running_jobs_none.yml +39 -0
  55. data/spec/cassettes/12/running_jobs_single.yml +55 -0
  56. data/spec/cassettes/12/update_private_key.yml +96 -0
  57. data/spec/cassettes/12/update_public_key.yml +70 -0
  58. data/spec/rundeck/client/execution_spec.rb +346 -0
  59. data/spec/rundeck/client/job_spec.rb +175 -0
  60. data/spec/rundeck/client/key_spec.rb +223 -0
  61. data/spec/spec_helper.rb +15 -60
  62. data/spec/support/helpers.rb +136 -0
  63. metadata +118 -35
  64. data/spec/fixtures/empty.xml +0 -0
  65. data/spec/fixtures/job.xml +0 -17
  66. data/spec/fixtures/job_executions.xml +0 -31
  67. data/spec/fixtures/job_run.xml +0 -16
  68. data/spec/fixtures/jobs_import.xml +0 -23
  69. data/spec/fixtures/jobs_my_project.xml +0 -14
  70. data/spec/fixtures/jobs_xml.xml +0 -32
  71. data/spec/fixtures/jobs_yaml.xml +0 -22
  72. data/spec/fixtures/key_contents_public.xml +0 -1
  73. data/spec/fixtures/key_private.xml +0 -8
  74. data/spec/fixtures/key_public.xml +0 -7
  75. data/spec/fixtures/keys.xml +0 -27
  76. data/spec/rundeck/client/jobs_spec.rb +0 -181
  77. data/spec/rundeck/client/keys_spec.rb +0 -216
@@ -1,32 +0,0 @@
1
- <joblist>
2
- <job>
3
- <id>c07518ef-b697-4792-9a59-5b4f08855b67</id>
4
- <loglevel>INFO</loglevel>
5
- <sequence keepgoing='false' strategy='node-first'>
6
- <command>
7
- <exec>echo 'hello world'</exec>
8
- </command>
9
- </sequence>
10
- <description>Hello World</description>
11
- <name>hello</name>
12
- <context>
13
- <project>my_project</project>
14
- </context>
15
- <uuid>c07518ef-b697-4792-9a59-5b4f08855b67</uuid>
16
- </job>
17
- <job>
18
- <id>9c922902-faa6-49cf-aa8d-4de3f5e1d3e1</id>
19
- <loglevel>INFO</loglevel>
20
- <sequence keepgoing='false' strategy='node-first'>
21
- <command>
22
- <exec>echo 'foo'</exec>
23
- </command>
24
- </sequence>
25
- <description>Foo Bar</description>
26
- <name>foo</name>
27
- <context>
28
- <project>my_project</project>
29
- </context>
30
- <uuid>9c922902-faa6-49cf-aa8d-4de3f5e1d3e1</uuid>
31
- </job>
32
- </joblist>
@@ -1,22 +0,0 @@
1
- - id: c07518ef-b697-4792-9a59-5b4f08855b67
2
- project: Endeca
3
- loglevel: INFO
4
- sequence:
5
- keepgoing: false
6
- strategy: node-first
7
- commands:
8
- - exec: echo 'boom'
9
- description: test
10
- name: test
11
- uuid: c07518ef-b697-4792-9a59-5b4f08855b67
12
- - id: 9c922902-faa6-49cf-aa8d-4de3f5e1d3e1
13
- project: Endeca
14
- loglevel: INFO
15
- sequence:
16
- keepgoing: false
17
- strategy: node-first
18
- commands:
19
- - exec: echo 'boom'
20
- description: test
21
- name: test
22
- uuid: 9c922902-faa6-49cf-aa8d-4de3f5e1d3e1
@@ -1 +0,0 @@
1
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDaNirADvOztppFoWeH+fc+5u8zQwRNeiamCXbrcWEK+/fB+Jqf/k1CLlikvp0dt1TKFmQXYJc58ZHv2RRxfe1lMdnv04VDVTE6DoB1jShnv0VL/KN0J+bNm4WLCyJ1NEdhnlZN5nt9U0RkYSG8hcuvREJ5R/5miCCRMSeH4hDmT22v7mV+qZQArRprs1EOE3o25lItefa/c5h85uJMYgnMIMQjT4hhr1JhWg2NdpN08fwS0Bif3JKk3C1YOa3RgW+Wrd0hFQ5iPSBTgmAxWjdgMp1xT4Nw8V8kujiH1jBLfJTXwDgm7csS/Z0H+gORpz6qnkbWKcWVzX3izFLZlxUH user@example.com
@@ -1,8 +0,0 @@
1
- <resource path='keys/path/to/my_key' type='file' url='http://localhost:4440/api/12/storage/keys/path/to/my_key' name='path/to/my_key'>
2
- <resource-meta>
3
- <Rundeck-content-type>application/octet-stream</Rundeck-content-type>
4
- <Rundeck-content-size>1765</Rundeck-content-size>
5
- <Rundeck-content-mask>content</Rundeck-content-mask>
6
- <Rundeck-key-type>private</Rundeck-key-type>
7
- </resource-meta>
8
- </resource>
@@ -1,7 +0,0 @@
1
- <resource path='keys/key1' type='file' url='http://localhost:4440/api/12/storage/keys/key1' name='key1'>
2
- <resource-meta>
3
- <Rundeck-content-type>application/pgp-keys</Rundeck-content-type>
4
- <Rundeck-content-size>406</Rundeck-content-size>
5
- <Rundeck-key-type>public</Rundeck-key-type>
6
- </resource-meta>
7
- </resource>
@@ -1,27 +0,0 @@
1
- <resource path='keys' type='directory' url='http://localhost:4440/api/12/storage/keys'>
2
- <contents count='4'>
3
- <resource path='keys/key1' type='file' url='http://localhost:4440/api/12/storage/keys/key1' name='key1'>
4
- <resource-meta>
5
- <Rundeck-content-type>application/pgp-keys</Rundeck-content-type>
6
- <Rundeck-content-size>406</Rundeck-content-size>
7
- <Rundeck-key-type>public</Rundeck-key-type>
8
- </resource-meta>
9
- </resource>
10
- <resource path='keys/key2' type='file' url='http://localhost:4440/api/12/storage/keys/key2' name='key2'>
11
- <resource-meta>
12
- <Rundeck-content-type>application/octet-stream</Rundeck-content-type>
13
- <Rundeck-content-size>1765</Rundeck-content-size>
14
- <Rundeck-content-mask>content</Rundeck-content-mask>
15
- <Rundeck-key-type>private</Rundeck-key-type>
16
- </resource-meta>
17
- </resource>
18
- <resource path='keys/key3' type='file' url='http://localhost:4440/api/12/storage/keys/key3' name='key3'>
19
- <resource-meta>
20
- <Rundeck-content-type>application/octet-stream</Rundeck-content-type>
21
- <Rundeck-content-size>1765</Rundeck-content-size>
22
- <Rundeck-content-mask>content</Rundeck-content-mask>
23
- <Rundeck-key-type>private</Rundeck-key-type>
24
- </resource-meta>
25
- </resource>
26
- </contents>
27
- </resource>
@@ -1,181 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Rundeck::Client do
4
- describe '.jobs' do
5
- before do
6
- stub_get('/project/My_Project/jobs', 'jobs_my_project')
7
- @jobs = Rundeck.jobs('My_Project')
8
- end
9
- subject { @jobs }
10
-
11
- it { is_expected.to be_an Array }
12
- its('first.name') { is_expected.to eq('Job 1') }
13
-
14
- it 'expects a get to have been made' do
15
- expect(a_get('/project/My_Project/jobs')).to have_been_made
16
- end
17
- end
18
-
19
- describe '.job' do
20
- before do
21
- stub_get('/job/c07518ef-b697-4792-9a59-5b4f08855b67', 'job')
22
- @job = Rundeck.job('c07518ef-b697-4792-9a59-5b4f08855b67')
23
- end
24
- subject { @job }
25
-
26
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
27
- its(:name) { is_expected.to eq('Hello World') }
28
-
29
- it 'expects a get to have been made' do
30
- expect(
31
- a_get('/job/c07518ef-b697-4792-9a59-5b4f08855b67')
32
- ).to have_been_made
33
- end
34
- end
35
-
36
- describe '.delete_job' do
37
- before do
38
- stub_delete('/job/c07518ef-b697-4792-9a59-5b4f08855b67', 'empty')
39
- @job = Rundeck.delete_job('c07518ef-b697-4792-9a59-5b4f08855b67')
40
- end
41
- subject { @job }
42
-
43
- it { is_expected.to be_nil }
44
-
45
- it 'expects a delete to have been made' do
46
- expect(
47
- a_delete('/job/c07518ef-b697-4792-9a59-5b4f08855b67')
48
- ).to have_been_made
49
- end
50
- end
51
-
52
- describe '.job_executions' do
53
- before do
54
- stub_get('/job/c07518ef-b697-4792-9a59-5b4f08855b67/executions',
55
- 'job_executions')
56
- @job_executions =
57
- Rundeck.job_executions('c07518ef-b697-4792-9a59-5b4f08855b67')
58
- end
59
- subject { @job_executions }
60
-
61
- it { is_expected.to be_an Array }
62
- its('first.job.name') { is_expected.to eq('Job 1') }
63
-
64
- it 'expects a get to have been made' do
65
- expect(
66
- a_get('/job/c07518ef-b697-4792-9a59-5b4f08855b67/executions')
67
- ).to have_been_made
68
- end
69
- end
70
-
71
- describe '.run_job' do
72
- before do
73
- stub_post('/job/c07518ef-b697-4792-9a59-5b4f08855b67/executions',
74
- 'job_run')
75
- @run_job =
76
- Rundeck.run_job('c07518ef-b697-4792-9a59-5b4f08855b67')
77
- end
78
- subject { @run_job }
79
-
80
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
81
- its('job.name') { is_expected.to eq('My_Job') }
82
-
83
- it 'expects a post to have been made' do
84
- expect(
85
- a_post('/job/c07518ef-b697-4792-9a59-5b4f08855b67/executions')
86
- ).to have_been_made
87
- end
88
- end
89
-
90
- describe '.import_job' do
91
- context 'with valid format' do
92
- before do
93
- stub_post("/jobs/import?format=#{format}", 'jobs_import')
94
- @import = Rundeck.import_jobs(content, format)
95
- end
96
- subject { @import }
97
-
98
- context 'yaml' do
99
- let(:format) { 'yaml' }
100
- let(:content) { '- id: 123456' }
101
-
102
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
103
- its('succeeded.count') { is_expected.to eq('1') }
104
- its('failed.count') { is_expected.to eq('0') }
105
-
106
- it 'expects a post to have been made' do
107
- expect(a_post('/jobs/import?format=yaml')).to have_been_made
108
- end
109
- end
110
-
111
- context 'xml' do
112
- let(:format) { 'xml' }
113
- let(:content) { '<id>12345</id>' }
114
-
115
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
116
- its('succeeded.count') { is_expected.to eq('1') }
117
- its('failed.count') { is_expected.to eq('0') }
118
-
119
- it 'expects a post to have been made' do
120
- expect(a_post('/jobs/import?format=xml')).to have_been_made
121
- end
122
- end
123
- end
124
-
125
- context 'with invalid format' do
126
- specify do
127
- expect do
128
- Rundeck.import_jobs('content', 'invalid_format')
129
- end.to raise_error(Rundeck::Error::InvalidAttributes,
130
- 'format must be yaml or xml')
131
- end
132
- end
133
- end
134
-
135
- describe '.export_job' do
136
- context 'with valid format' do
137
- before do
138
- stub_get("/jobs/export?project=my_project&format=#{format}", fixture)
139
- @jobs = Rundeck.export_jobs('my_project', format)
140
- end
141
- subject { @jobs }
142
-
143
- context 'yaml' do
144
- let(:format) { 'yaml' }
145
- let(:fixture) { 'jobs_yaml' }
146
-
147
- it { is_expected.to be_a String }
148
- it { is_expected.to include 'id: c07518ef-b697-4792-9a59-5b4f08855b67' }
149
-
150
- it 'expects a get to have been made' do
151
- expect(
152
- a_get('/jobs/export?project=my_project&format=yaml')
153
- ).to have_been_made
154
- end
155
- end
156
-
157
- context 'xml' do
158
- let(:format) { 'xml' }
159
- let(:fixture) { 'jobs_xml' }
160
-
161
- it { is_expected.to be_a String }
162
- it { is_expected.to include '<id>c07518ef-b697-4792-9a59-5b4f08855b67</id>' }
163
-
164
- it 'expects a get to have been made' do
165
- expect(
166
- a_get('/jobs/export?project=my_project&format=xml')
167
- ).to have_been_made
168
- end
169
- end
170
- end
171
-
172
- context 'with invalid format' do
173
- specify do
174
- expect do
175
- Rundeck.export_jobs('my_project', 'invalid_format')
176
- end.to raise_error(Rundeck::Error::InvalidAttributes,
177
- 'format must be yaml or xml')
178
- end
179
- end
180
- end
181
- end
@@ -1,216 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Rundeck::Client do
4
- describe '.keys' do
5
- context 'with a path containing multiple keys' do
6
- before do
7
- stub_get('/storage/keys/', 'keys')
8
- @keys = Rundeck.keys
9
- end
10
- subject { @keys }
11
-
12
- it { is_expected.to be_an Array }
13
- its('first.resource_meta.rundeck_key_type') { is_expected.to eq('public') }
14
-
15
- it 'expects a get to have been made' do
16
- expect(a_get('/storage/keys/')).to have_been_made
17
- end
18
- end
19
-
20
- context 'with a direct path to a key' do
21
- before do
22
- stub_get('/storage/keys/path/to/key1', 'key_public')
23
- end
24
-
25
- specify do
26
- expect do
27
- Rundeck.keys('path/to/key1')
28
- end.to raise_error(Rundeck::Error::InvalidAttributes,
29
- 'Please provide a key storage path that ' \
30
- 'isn\'t a direct path to a key')
31
- end
32
- end
33
- end
34
-
35
- describe '.key_metadata' do
36
- context 'with a direct path to a key' do
37
- before do
38
- stub_get('/storage/keys/path/to/key1', 'key_public')
39
- @key = Rundeck.key_metadata('path/to/key1')
40
- end
41
- subject { @key }
42
-
43
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
44
- its(:rundeck_content_type) { is_expected.to eq('application/pgp-keys') }
45
-
46
- it 'expects a get to have been made' do
47
- expect(a_get('/storage/keys/path/to/key1')).to have_been_made
48
- end
49
- end
50
-
51
- context 'with a path containing multiple keys' do
52
- before do
53
- stub_get('/storage/keys/path/to/keys', 'keys')
54
- end
55
-
56
- it do
57
- expect do
58
- Rundeck.key_metadata('path/to/keys')
59
- end.to raise_error(Rundeck::Error::InvalidAttributes,
60
- 'Please provide a key storage path that ' \
61
- 'is a direct path to a key')
62
- end
63
- end
64
- end
65
-
66
- describe '.key_contents' do
67
- context 'with a direct path to a key' do
68
- before do
69
- stub_get('/storage/keys/path/to/key1', 'key_public')
70
- stub_get('/storage/keys/path/to/key1', 'key_contents_public', 'pgp-keys')
71
- @key = Rundeck.key_contents('path/to/key1')
72
- end
73
- subject { @key }
74
-
75
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
76
- its(:public_key) { is_expected.to include('ssh-rsa') }
77
-
78
- it 'expects a get to have been made' do
79
- expect(a_get('/storage/keys/path/to/key1')).to have_been_made
80
- end
81
- it 'expects a get to have been made' do
82
- expect(a_get('/storage/keys/path/to/key1', 'pgp-keys')).to have_been_made
83
- end
84
- end
85
-
86
- context 'with a path containing multiple keys' do
87
- before do
88
- stub_get('/storage/keys/path/to/keys', 'keys')
89
- end
90
-
91
- it do
92
- expect do
93
- Rundeck.key_contents('path/to/keys')
94
- end.to raise_error(Rundeck::Error::InvalidAttributes,
95
- 'Please provide a key storage path that ' \
96
- 'is a direct path to a key')
97
- end
98
- end
99
-
100
- context 'when trying to get a private key' do
101
- before do
102
- stub_get('/storage/keys/path/to/key2', 'key_private')
103
- end
104
-
105
- it do
106
- expect do
107
- Rundeck.key_contents('path/to/key2')
108
- end.to raise_error(Rundeck::Error::Unauthorized,
109
- 'You are not allowed to retrieve the contents ' \
110
- 'of a private key')
111
- end
112
- end
113
- end
114
-
115
- describe '.create_private_key' do
116
- before do
117
- keystring = <<-EOD
118
- -----BEGIN RSA PRIVATE KEY-----
119
- Proc-Type: 4,ENCRYPTED
120
- DEK-Info: AES-128-CBC,E283774838299...
121
- -----END RSA PRIVATE KEY-----
122
- EOD
123
- stub_post('/storage/keys/path/to/my_key', 'key_private')
124
- @key = Rundeck.create_private_key('path/to/my_key', keystring)
125
- end
126
- subject { @key }
127
-
128
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
129
- its(:rundeck_key_type) { is_expected.to eq('private') }
130
-
131
- it 'expects a post to have been made' do
132
- expect(
133
- a_post('/storage/keys/path/to/my_key')
134
- ).to have_been_made
135
- end
136
- end
137
-
138
- describe '.update_private_key' do
139
- before do
140
- keystring = <<-EOD
141
- -----BEGIN RSA PRIVATE KEY-----
142
- Proc-Type: 4,ENCRYPTED
143
- DEK-Info: AES-128-CBC,E283774838299...
144
- -----END RSA PRIVATE KEY-----
145
- EOD
146
- stub_get('/storage/keys/path/to/key1', 'key_private')
147
- stub_put('/storage/keys/path/to/key1', 'key_private')
148
- @key = Rundeck.update_private_key('path/to/key1', keystring)
149
- end
150
- subject { @key }
151
-
152
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
153
- its(:rundeck_key_type) { is_expected.to eq('private') }
154
-
155
- it 'expects a get to have been made' do
156
- expect(a_get('/storage/keys/path/to/key1')).to have_been_made
157
- end
158
- it 'expects a put to have been made' do
159
- expect(a_put('/storage/keys/path/to/key1')).to have_been_made
160
- end
161
- end
162
-
163
- describe '.create_public_key' do
164
- before do
165
- keystring = 'ssh-rsa AAAA....3MOj user@example.com'
166
- stub_post('/storage/keys/path/to/my_public_key', 'key_public')
167
- @key = Rundeck.create_public_key('path/to/my_public_key', keystring)
168
- end
169
- subject { @key }
170
-
171
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
172
- its(:rundeck_content_type) { is_expected.to eq('application/pgp-keys') }
173
-
174
- it 'expects a post to have been made' do
175
- expect(
176
- a_post('/storage/keys/path/to/my_public_key')
177
- ).to have_been_made
178
- end
179
- end
180
-
181
- describe '.update_public_key' do
182
- before do
183
- keystring = <<-EOD
184
- ssh-rsa AAAA....ZlxUH user@example.com
185
- EOD
186
- stub_get('/storage/keys/path/to/key1', 'key_public')
187
- stub_put('/storage/keys/path/to/key1', 'key_public')
188
- @key = Rundeck.update_public_key('path/to/key1', keystring)
189
- end
190
- subject { @key }
191
-
192
- it { is_expected.to be_a Rundeck::ObjectifiedHash }
193
- its(:rundeck_content_type) { is_expected.to eq('application/pgp-keys') }
194
-
195
- it 'expects a get to have been made' do
196
- expect(a_get('/storage/keys/path/to/key1')).to have_been_made
197
- end
198
- it 'expects a put to have been made' do
199
- expect(a_put('/storage/keys/path/to/key1')).to have_been_made
200
- end
201
- end
202
-
203
- describe '.delete_key' do
204
- before do
205
- stub_delete('/storage/keys/path/to/my_key', 'empty')
206
- @key = Rundeck.delete_key('path/to/my_key')
207
- end
208
- subject { @key }
209
-
210
- it { is_expected.to be_nil }
211
-
212
- it 'expects a delete to have been made' do
213
- expect(a_delete('/storage/keys/path/to/my_key')).to have_been_made
214
- end
215
- end
216
- end