turnip_formatter 0.1.2 → 0.2.0
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/.gitignore +1 -1
- data/{spec/examples → example}/README.md +8 -8
- data/{spec/examples → example}/features/battle.feature +0 -0
- data/{spec/examples → example}/features/battle2.feature +0 -0
- data/{spec/examples → example}/features/battle3.feature +0 -0
- data/{spec/examples → example}/features/songs.feature +0 -0
- data/{spec/examples → example}/images/background.png +0 -0
- data/{spec/examples → example}/images/basic_step.png +0 -0
- data/{spec/examples → example}/images/failed_step.png +0 -0
- data/{spec/examples → example}/images/multiline.png +0 -0
- data/{spec/examples → example}/images/outline.png +0 -0
- data/{spec/examples → example}/images/pending_step.png +0 -0
- data/{spec/examples → example}/images/tag_step.png +0 -0
- data/{spec/examples → example}/spec_helper.rb +0 -0
- data/{spec/examples → example}/steps/spell_steps.rb +0 -0
- data/{spec/examples → example}/steps/steps.rb +0 -0
- data/lib/turnip_formatter/formatter.css +0 -21
- data/lib/turnip_formatter/formatter.scss +0 -32
- data/lib/turnip_formatter/scenario.rb +5 -0
- data/lib/turnip_formatter/step/dsl.rb +5 -5
- data/lib/turnip_formatter/step/failure.rb +0 -8
- data/lib/turnip_formatter/step/pending.rb +0 -7
- data/lib/turnip_formatter/step.rb +4 -4
- data/lib/turnip_formatter/step_template/exception.rb +61 -0
- data/lib/turnip_formatter/step_template/source.rb +46 -0
- data/lib/turnip_formatter/step_template.rb +8 -0
- data/lib/turnip_formatter/template/exception.erb +26 -0
- data/lib/turnip_formatter/template/exception_backtrace.erb +7 -0
- data/lib/turnip_formatter/template/scenario.erb +24 -0
- data/lib/turnip_formatter/template/scenario_tags.erb +5 -0
- data/lib/turnip_formatter/template/section_report.erb +15 -0
- data/lib/turnip_formatter/template/step_multiline.erb +1 -0
- data/lib/turnip_formatter/template/step_outline.erb +9 -0
- data/lib/turnip_formatter/template.rb +88 -125
- data/lib/turnip_formatter/version.rb +1 -1
- data/lib/turnip_formatter.rb +1 -0
- data/spec/turnip_formatter/step/failure_spec.rb +19 -4
- data/spec/turnip_formatter/step/pending_spec.rb +18 -4
- data/spec/turnip_formatter/step_spec.rb +37 -24
- data/spec/turnip_formatter/{template/step_exception_spec.rb → step_template/exception_spec.rb} +4 -4
- data/spec/turnip_formatter/{template/step_source_spec.rb → step_template/source_spec.rb} +5 -5
- data/spec/turnip_formatter/template_spec.rb +60 -40
- data/turnip_formatter.gemspec +2 -1
- metadata +47 -44
- data/lib/turnip_formatter/template/step_exception.rb +0 -30
- data/lib/turnip_formatter/template/step_multiline.rb +0 -13
- data/lib/turnip_formatter/template/step_outline.rb +0 -29
- data/lib/turnip_formatter/template/step_source.rb +0 -15
- data/spec/turnip_formatter/template/step_multiline_spec.rb +0 -18
- data/spec/turnip_formatter/template/step_outline_spec.rb +0 -31
@@ -5,16 +5,42 @@ require 'rspec/core/formatters/helpers'
|
|
5
5
|
require 'turnip_formatter/template/tab/speed_statistics'
|
6
6
|
require 'turnip_formatter/template/tab/feature_statistics'
|
7
7
|
require 'turnip_formatter/template/tab/tag_statistics'
|
8
|
+
require 'sass'
|
8
9
|
|
9
10
|
module TurnipFormatter
|
10
11
|
class Template
|
11
12
|
include ERB::Util
|
12
13
|
include RSpec::Core::BacktraceFormatter
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
class << self
|
16
|
+
def add_js(js_string)
|
17
|
+
js_list << js_string
|
18
|
+
end
|
19
|
+
|
20
|
+
def js_render
|
21
|
+
js_list.join("\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def css_render
|
25
|
+
css_list.join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_scss(scss_string)
|
29
|
+
css_list << scss_compile(scss_string)
|
30
|
+
end
|
31
|
+
|
32
|
+
def js_list
|
33
|
+
@js_list ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
def css_list
|
37
|
+
@css_list ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
def scss_compile(scss)
|
41
|
+
Sass::Engine.new(scss, syntax: :scss).render
|
42
|
+
end
|
43
|
+
end
|
18
44
|
|
19
45
|
def print_header
|
20
46
|
<<-EOS
|
@@ -29,7 +55,8 @@ module TurnipFormatter
|
|
29
55
|
|
30
56
|
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/themes/smoothness/jquery-ui.css">
|
31
57
|
<style>
|
32
|
-
|
58
|
+
#{File.read(File.dirname(__FILE__) + '/formatter.css')}
|
59
|
+
#{self.class.css_render}
|
33
60
|
</style>
|
34
61
|
|
35
62
|
<script>
|
@@ -83,11 +110,13 @@ module TurnipFormatter
|
|
83
110
|
1: { sorter: false }
|
84
111
|
}
|
85
112
|
});
|
113
|
+
|
114
|
+
#{self.class.js_render}
|
86
115
|
});
|
87
116
|
</script>
|
88
117
|
</head>
|
89
118
|
<body>
|
90
|
-
#{
|
119
|
+
#{print_section_report}
|
91
120
|
<div id="main" role="main">
|
92
121
|
<ul>
|
93
122
|
<li><a href="#steps-statistics">Steps</a></li>
|
@@ -159,27 +188,50 @@ module TurnipFormatter
|
|
159
188
|
end
|
160
189
|
|
161
190
|
def print_scenario(scenario)
|
162
|
-
|
191
|
+
render_template(:scenario, { scenario: scenario })
|
163
192
|
end
|
164
193
|
|
165
194
|
def print_runtime_error(example, exception)
|
166
195
|
exception.set_backtrace(format_backtrace(exception.backtrace))
|
167
|
-
|
196
|
+
render_template(:exception, { example: example, exception: exception })
|
168
197
|
end
|
169
198
|
|
170
|
-
|
199
|
+
def print_exception_backtrace(e)
|
200
|
+
render_template(:exception_backtrace, { backtrace: e.backtrace })
|
201
|
+
end
|
202
|
+
|
203
|
+
def print_scenario_tags(scenario)
|
204
|
+
if scenario.tags.empty?
|
205
|
+
''
|
206
|
+
else
|
207
|
+
render_template(:scenario_tags, { tags: scenario.tags })
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def print_step_extra_args(extra_args)
|
212
|
+
extra_args.map do |arg|
|
213
|
+
if arg.instance_of?(Turnip::Table)
|
214
|
+
print_step_outline(arg)
|
215
|
+
else
|
216
|
+
print_step_multiline(arg)
|
217
|
+
end
|
218
|
+
end.join("\n")
|
219
|
+
end
|
171
220
|
|
172
|
-
def
|
173
|
-
|
174
|
-
name = scenario.feature_name
|
175
|
-
"\"#{name}\" in #{path}"
|
221
|
+
def print_step_outline(table)
|
222
|
+
render_template(:step_outline, { table: table.to_a })
|
176
223
|
end
|
177
224
|
|
178
|
-
def
|
179
|
-
|
180
|
-
template_scenario_tags.result(binding)
|
225
|
+
def print_step_multiline(lines)
|
226
|
+
render_template(:step_multiline, { lines: lines })
|
181
227
|
end
|
182
228
|
|
229
|
+
def print_section_report
|
230
|
+
render_template(:section_report)
|
231
|
+
end
|
232
|
+
|
233
|
+
private
|
234
|
+
|
183
235
|
def step_attr(step)
|
184
236
|
attr = 'step'
|
185
237
|
attr += " #{step.status}" if step.attention?
|
@@ -191,129 +243,40 @@ module TurnipFormatter
|
|
191
243
|
|
192
244
|
step.docs.each do |style, template|
|
193
245
|
if style == :extra_args
|
194
|
-
output <<
|
246
|
+
output << print_step_extra_args(template[:value])
|
195
247
|
else
|
196
|
-
output <<
|
248
|
+
output << template[:klass].build(template[:value])
|
197
249
|
end
|
198
250
|
end
|
199
251
|
|
200
252
|
output.join("\n")
|
201
253
|
end
|
202
254
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
def step_template(style, klass)
|
211
|
-
return klass if !!klass
|
212
|
-
|
213
|
-
# call Built-in template (StepException, StepSource, etc...)
|
214
|
-
klass = ['step', style.to_s].map(&:capitalize).join
|
215
|
-
self.class.const_get(klass)
|
255
|
+
#
|
256
|
+
# @example
|
257
|
+
# render_template(:main, { name: 'user' })
|
258
|
+
# # => ERB.new('/path/to/main.erb') render { name: 'user' }
|
259
|
+
#
|
260
|
+
def render_template(name, params = {})
|
261
|
+
render_template_list(name).result(template_params_binding(params))
|
216
262
|
end
|
217
263
|
|
218
|
-
def
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
<label for="passed_check">Passed</label><input type="checkbox" checked id="passed_check">
|
224
|
-
<label for="failed_check">Failed</label><input type="checkbox" checked id="failed_check">
|
225
|
-
<label for="pending_check">Pending</label><input type="checkbox" checked id="pending_check">
|
226
|
-
</section>
|
227
|
-
|
228
|
-
<section class="result">
|
229
|
-
<p>
|
230
|
-
<span id="total_count"></span> Scenario (<span id="failed_count"></span> failed <span id="pending_count"></span> pending).
|
231
|
-
</p>
|
232
|
-
<p>Finished in <span id="total_time"></span></p>
|
233
|
-
</section>
|
234
|
-
</div>
|
235
|
-
EOS
|
236
|
-
end
|
237
|
-
|
238
|
-
def template_scenario
|
239
|
-
@template_scenario ||= ERB.new(<<-EOS)
|
240
|
-
<section class="scenario <%= h(scenario.status) %>">
|
241
|
-
<header>
|
242
|
-
<span class="permalink">
|
243
|
-
<a href="#<%= scenario.id %>">¶</a>
|
244
|
-
</span>
|
245
|
-
<span class="scenario_name" id="<%= scenario.id %>">
|
246
|
-
Scenario: <%= h(scenario.name) %>
|
247
|
-
</span>
|
248
|
-
<span class="feature_name">
|
249
|
-
(Feature: <%= h(feature_name(scenario)) %>)
|
250
|
-
at <%= h(scenario.run_time) %> sec
|
251
|
-
</span>
|
252
|
-
</header>
|
253
|
-
<%= scenario_tags(scenario) %>
|
254
|
-
<ul class="steps">
|
255
|
-
<% scenario.steps.each do |step| %>
|
256
|
-
<li <%= step_attr(step) %>><span><%= h(step.name) %></span>
|
257
|
-
<div class="args"><%= step_args(step) %></div>
|
258
|
-
</li>
|
259
|
-
<% end %>
|
260
|
-
</ul>
|
261
|
-
</section>
|
262
|
-
EOS
|
263
|
-
end
|
264
|
+
def render_template_list(name)
|
265
|
+
if templates[name].nil?
|
266
|
+
path = File.dirname(__FILE__) + "/template/#{name.to_s}.erb"
|
267
|
+
templates[name] = ERB.new(File.read(path))
|
268
|
+
end
|
264
269
|
|
265
|
-
|
266
|
-
@template_scenario_tags ||= ERB.new(<<-EOS)
|
267
|
-
<ul class="tags">
|
268
|
-
<% scenario.tags.each do |tag| %>
|
269
|
-
<li>@<%= h(tag) %></li>
|
270
|
-
<% end %>
|
271
|
-
</ul>
|
272
|
-
EOS
|
270
|
+
templates[name]
|
273
271
|
end
|
274
272
|
|
275
|
-
def
|
276
|
-
|
277
|
-
|
278
|
-
<h1>TurnipFormatter RuntimeError</h1>
|
279
|
-
<dl>
|
280
|
-
<dt>Runtime Exception</dt>
|
281
|
-
<dd><%= h(exception.to_s) %></dd>
|
282
|
-
|
283
|
-
<dt>Runtime Exception Backtrace</dt>
|
284
|
-
<%= template_exception_backtrace(exception) %>
|
285
|
-
|
286
|
-
<dt>Example Full Description</dt>
|
287
|
-
<dd><%= h(example.metadata[:full_description]) %></dd>
|
288
|
-
|
289
|
-
<% if example.exception %>
|
290
|
-
<dt>Example Exception</dt>
|
291
|
-
<dd><%= h(example.exception.to_s) %></dd>
|
292
|
-
|
293
|
-
<dt>Example Backtrace</dt>
|
294
|
-
<%= template_exception_backtrace(example.exception) %>
|
295
|
-
<% end %>
|
296
|
-
|
297
|
-
<% if example.pending %>
|
298
|
-
<dt>Example Pending description</dt>
|
299
|
-
<dd><%= h(example.metadata[:description]) %></dd>
|
300
|
-
<% end %>
|
301
|
-
</dl>
|
302
|
-
</section>
|
303
|
-
EOS
|
273
|
+
def template_params_binding(params)
|
274
|
+
code = params.keys.map { |k| "#{k} = params[#{k.inspect}];" }.join
|
275
|
+
eval(code + ";binding")
|
304
276
|
end
|
305
277
|
|
306
|
-
def
|
307
|
-
@
|
308
|
-
<dd>
|
309
|
-
<ol>
|
310
|
-
<% exception.backtrace.each do |line| %>
|
311
|
-
<li><%= h(line) %></li>
|
312
|
-
<% end %>
|
313
|
-
</ol>
|
314
|
-
</dd>
|
315
|
-
EOS
|
316
|
-
@template_exception_backtrace.result(binding)
|
278
|
+
def templates
|
279
|
+
@templates ||= {}
|
317
280
|
end
|
318
281
|
end
|
319
282
|
end
|
data/lib/turnip_formatter.rb
CHANGED
@@ -6,6 +6,7 @@ require 'turnip'
|
|
6
6
|
module TurnipFormatter
|
7
7
|
require 'rspec/core/formatters/turnip_formatter'
|
8
8
|
require 'turnip_formatter/template'
|
9
|
+
require 'turnip_formatter/step_template'
|
9
10
|
require 'turnip_formatter/ext/turnip/rspec'
|
10
11
|
require 'turnip_formatter/ext/turnip/builder'
|
11
12
|
end
|
@@ -13,25 +13,40 @@ module TurnipFormatter
|
|
13
13
|
step
|
14
14
|
end
|
15
15
|
|
16
|
+
let(:klasses) do
|
17
|
+
builtin_klass1 = ::TurnipFormatter::StepTemplate::Source
|
18
|
+
builtin_klass2 = ::TurnipFormatter::StepTemplate::Exception
|
19
|
+
[builtin_klass1, builtin_klass2]
|
20
|
+
end
|
21
|
+
|
16
22
|
it 'exists built-in step template' do
|
17
23
|
templates = TurnipFormatter::Step::Failure.templates
|
18
|
-
expect(templates.keys).to
|
24
|
+
expect(templates.keys).to include(*klasses)
|
19
25
|
end
|
20
26
|
|
21
27
|
context 'add custom step template' do
|
28
|
+
let :custom_template do
|
29
|
+
Module.new do
|
30
|
+
def self.build(message)
|
31
|
+
'[error] ' + message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
22
36
|
before do
|
23
|
-
TurnipFormatter::Step::Failure.add_template
|
37
|
+
TurnipFormatter::Step::Failure.add_template(custom_template) do
|
24
38
|
example.example_group.description
|
25
39
|
end
|
26
40
|
end
|
27
41
|
|
28
42
|
after do
|
29
|
-
TurnipFormatter::Step::Failure.remove_template
|
43
|
+
TurnipFormatter::Step::Failure.remove_template(custom_template)
|
30
44
|
end
|
31
45
|
|
32
46
|
it 'should get custom step template' do
|
33
47
|
templates = TurnipFormatter::Step::Failure.templates
|
34
|
-
|
48
|
+
klasses << custom_template
|
49
|
+
expect(templates.keys).to include(*klasses)
|
35
50
|
end
|
36
51
|
end
|
37
52
|
|
@@ -13,25 +13,39 @@ module TurnipFormatter
|
|
13
13
|
step
|
14
14
|
end
|
15
15
|
|
16
|
+
let(:klasses) do
|
17
|
+
builtin_klass = ::TurnipFormatter::StepTemplate::Exception
|
18
|
+
[builtin_klass]
|
19
|
+
end
|
20
|
+
|
16
21
|
it 'exists built-in step template' do
|
17
22
|
templates = TurnipFormatter::Step::Pending.templates
|
18
|
-
expect(templates.keys).to
|
23
|
+
expect(templates.keys).to include(*klasses)
|
19
24
|
end
|
20
25
|
|
21
26
|
context 'add custom step template' do
|
27
|
+
let :custom_template do
|
28
|
+
Module.new do
|
29
|
+
def self.build(message)
|
30
|
+
'[pending] ' + message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
22
35
|
before do
|
23
|
-
TurnipFormatter::Step::Pending.add_template
|
36
|
+
TurnipFormatter::Step::Pending.add_template custom_template do
|
24
37
|
example.example_group.description
|
25
38
|
end
|
26
39
|
end
|
27
40
|
|
28
41
|
after do
|
29
|
-
TurnipFormatter::Step::Failure.remove_template
|
42
|
+
TurnipFormatter::Step::Failure.remove_template custom_template
|
30
43
|
end
|
31
44
|
|
32
45
|
it 'should get custom step template' do
|
33
46
|
templates = TurnipFormatter::Step::Pending.templates
|
34
|
-
|
47
|
+
klasses << custom_template
|
48
|
+
expect(templates.keys).to include(*klasses)
|
35
49
|
end
|
36
50
|
end
|
37
51
|
|
@@ -22,8 +22,8 @@ module TurnipFormatter
|
|
22
22
|
it { should include :extra_args }
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
let :
|
25
|
+
context 'using template' do
|
26
|
+
let :custom_template1 do
|
27
27
|
Module.new do
|
28
28
|
def self.build(hoge)
|
29
29
|
hoge * 3
|
@@ -31,42 +31,55 @@ module TurnipFormatter
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
let :custom_template2 do
|
35
|
+
Module.new do
|
36
|
+
def self.build(hoge)
|
37
|
+
'aiueo' + hoge
|
38
|
+
end
|
37
39
|
end
|
40
|
+
end
|
38
41
|
|
39
|
-
|
42
|
+
before do
|
43
|
+
TurnipFormatter::Step.add_template :hoge, custom_template1 do
|
40
44
|
'12345'
|
41
45
|
end
|
46
|
+
|
47
|
+
TurnipFormatter::Step.add_template :hoge, custom_template2 do
|
48
|
+
'abcde'
|
49
|
+
end
|
42
50
|
end
|
43
51
|
|
44
52
|
after do
|
45
|
-
TurnipFormatter::Step.remove_template(:hoge,
|
46
|
-
TurnipFormatter::Step.remove_template(:hoge,
|
53
|
+
TurnipFormatter::Step.remove_template(:hoge, custom_template1)
|
54
|
+
TurnipFormatter::Step.remove_template(:hoge, custom_template2)
|
47
55
|
end
|
48
56
|
|
49
|
-
|
50
|
-
|
51
|
-
|
57
|
+
describe '#add_template' do
|
58
|
+
it 'can add step template' do
|
59
|
+
style1 = TurnipFormatter::Step.templates[:hoge][custom_template1]
|
60
|
+
klass1 = style1[:klass]
|
61
|
+
block1 = style1[:block]
|
62
|
+
expect(klass1.build(block1.call)).to eq('123451234512345')
|
52
63
|
|
53
|
-
|
54
|
-
|
64
|
+
style2 = TurnipFormatter::Step.templates[:hoge][custom_template2]
|
65
|
+
klass2 = style2[:klass]
|
66
|
+
block2 = style2[:block]
|
67
|
+
expect(klass2.build(block2.call)).to eq('aiueoabcde')
|
68
|
+
end
|
55
69
|
end
|
56
|
-
end
|
57
70
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
expect(TurnipFormatter::Step.templates[:hoge]).to have_key :style1
|
63
|
-
expect(TurnipFormatter::Step.templates[:hoge]).to have_key :style2
|
71
|
+
describe '#remove_template' do
|
72
|
+
it 'can remove step template' do
|
73
|
+
expect(TurnipFormatter::Step.templates[:hoge]).to have_key custom_template1
|
74
|
+
expect(TurnipFormatter::Step.templates[:hoge]).to have_key custom_template2
|
64
75
|
|
65
|
-
|
66
|
-
|
76
|
+
TurnipFormatter::Step.remove_template(:hoge, custom_template1)
|
77
|
+
expect(TurnipFormatter::Step.templates[:hoge]).not_to have_key custom_template1
|
78
|
+
expect(TurnipFormatter::Step.templates[:hoge]).to have_key custom_template2
|
67
79
|
|
68
|
-
|
69
|
-
|
80
|
+
TurnipFormatter::Step.remove_template(:hoge, custom_template2)
|
81
|
+
expect(TurnipFormatter::Step.templates).not_to have_key custom_template2
|
82
|
+
end
|
70
83
|
end
|
71
84
|
end
|
72
85
|
end
|
data/spec/turnip_formatter/{template/step_exception_spec.rb → step_template/exception_spec.rb}
RENAMED
@@ -1,12 +1,12 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
-
require 'turnip_formatter/
|
4
|
+
require 'turnip_formatter/step_template/exception'
|
5
5
|
|
6
6
|
module TurnipFormatter
|
7
|
-
|
8
|
-
describe
|
9
|
-
let(:template) { ::TurnipFormatter::
|
7
|
+
module StepTemplate
|
8
|
+
describe Exception do
|
9
|
+
let(:template) { ::TurnipFormatter::StepTemplate::Exception }
|
10
10
|
let(:exception) do
|
11
11
|
StandardError.new('StepExceptionError').tap do |e|
|
12
12
|
e.set_backtrace('/path/to/error.rb: 10')
|
@@ -1,19 +1,19 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
-
require 'turnip_formatter/
|
4
|
+
require 'turnip_formatter/step_template/source'
|
5
5
|
|
6
6
|
module TurnipFormatter
|
7
|
-
|
8
|
-
describe
|
9
|
-
let(:template) { ::TurnipFormatter::
|
7
|
+
module StepTemplate
|
8
|
+
describe Source do
|
9
|
+
let(:template) { ::TurnipFormatter::StepTemplate::Source }
|
10
10
|
let(:source) { __FILE__ + ':3' }
|
11
11
|
|
12
12
|
describe '.build' do
|
13
13
|
subject { template.build(source) }
|
14
14
|
it do
|
15
15
|
should match '<pre class="source"><code class="ruby">'
|
16
|
-
should match "require 'turnip_formatter/
|
16
|
+
should match "require 'turnip_formatter/step_template/source'"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|