lemon 0.9.0 → 0.9.1
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/.ruby +23 -14
- data/.yardopts +6 -0
- data/Config.rb +14 -0
- data/{HISTORY.rdoc → HISTORY.md} +26 -11
- data/LICENSE.txt +27 -0
- data/README.md +42 -28
- data/SPECSHEET.md +314 -0
- data/bin/{lemonade → lemons} +0 -0
- data/lib/lemon.yml +23 -14
- data/lib/lemon/cli.rb +19 -8
- data/lib/lemon/cli/base.rb +50 -20
- data/lib/lemon/cli/generate.rb +51 -16
- data/lib/lemon/cli/lemon.ascii +84 -0
- data/lib/lemon/cli/obrother.rb +35 -0
- data/lib/lemon/cli/scaffold.rb +116 -0
- data/lib/lemon/core_ext.rb +2 -2
- data/lib/lemon/core_ext/module.rb +9 -0
- data/lib/lemon/coverage/analyzer.rb +76 -5
- data/lib/lemon/coverage/cover_unit.rb +38 -14
- data/lib/lemon/coverage/formats/verbose.rb +1 -1
- data/lib/lemon/coverage/generator.rb +196 -0
- data/lib/lemon/coverage/snapshot.rb +16 -16
- data/lib/lemon/coverage/source_parser.rb +103 -37
- data/lib/lemon/ignore_callers.rb +19 -0
- data/lib/lemon/test_case.rb +135 -26
- data/lib/lemon/test_class.rb +16 -3
- data/lib/lemon/test_class_method.rb +58 -0
- data/lib/lemon/test_method.rb +57 -68
- data/lib/lemon/test_module.rb +47 -44
- data/lib/lemon/test_proc.rb +28 -2
- data/lib/lemon/test_scope.rb +14 -0
- data/lib/lemon/test_setup.rb +1 -1
- data/lib/lemon/test_world.rb +7 -0
- data/{work/deprecated/features/support → spec/applique}/ae.rb +0 -0
- data/spec/coverage/{01_complete.rdoc → 01_complete.md} +3 -3
- data/spec/coverage/{02_incomplete.rdoc → 02_incomplete.md} +2 -2
- data/spec/coverage/{03_extensions.rdoc → 03_extensions.md} +2 -2
- data/try/case_scope.rb +19 -0
- metadata +50 -102
- data/.gemspec +0 -152
- data/.gitignore +0 -8
- data/.reap/digest +0 -678
- data/.reap/test.reap +0 -7
- data/Assembly +0 -37
- data/COPYING.rdoc +0 -33
- data/MANIFEST +0 -55
- data/PROFILE +0 -30
- data/Rakefile +0 -23
- data/VERSION +0 -1
- data/lib/lemon/core_ext/omission.rb +0 -18
- data/lib/lemon/generator.rb +0 -149
- data/notes/2010-05-05-coverage.rdoc +0 -47
- data/notes/2010-05-06-files-not-classes.rdoc +0 -19
- data/notes/2010-07-11-acid-testing.rdoc +0 -52
- data/notes/2010-08-02-enforcing-the-unit.md +0 -68
- data/notes/2010-08-03-new-api.md +0 -37
- data/notes/2011-07-07-nailing-down-the-nomenclature.md +0 -6
- data/site/.rsync-filter +0 -8
- data/site/assets/images/cut-lemon.png +0 -0
- data/site/assets/images/forkme.png +0 -0
- data/site/assets/images/github-logo.png +0 -0
- data/site/assets/images/lemon.jpg +0 -0
- data/site/assets/images/lemon.svg +0 -39
- data/site/assets/images/lemons-are-good.png +0 -0
- data/site/assets/images/opensource.png +0 -0
- data/site/assets/images/ruby-logo.png +0 -0
- data/site/assets/images/skin.jpg +0 -0
- data/site/assets/images/skin1.jpg +0 -0
- data/site/assets/images/tap.png +0 -0
- data/site/assets/images/title.png +0 -0
- data/site/assets/styles/class.css +0 -6
- data/site/assets/styles/reset.css +0 -17
- data/site/assets/styles/site.css +0 -33
- data/site/index.html +0 -218
- data/work/deprecated/command/abstract.rb +0 -29
- data/work/deprecated/command/coverage.rb +0 -115
- data/work/deprecated/command/generate.rb +0 -124
- data/work/deprecated/command/test.rb +0 -112
- data/work/deprecated/cucumber.yml +0 -3
- data/work/deprecated/features/coverage.feature +0 -65
- data/work/deprecated/features/generate.feature +0 -66
- data/work/deprecated/features/step_definitions/coverage_steps.rb +0 -1
- data/work/deprecated/features/support/aruba.rb +0 -1
- data/work/deprecated/features/test.feature +0 -67
- data/work/deprecated/model/dsl/advice.rb +0 -78
- data/work/deprecated/model/dsl/subject.rb +0 -40
- data/work/deprecated/model/main.rb +0 -87
- data/work/deprecated/model/test.rb +0 -54
- data/work/deprecated/model/test_base_dsl.rb +0 -88
- data/work/deprecated/model/test_clause.rb +0 -112
- data/work/deprecated/model/test_context.rb +0 -90
- data/work/deprecated/model/test_feature.rb +0 -128
- data/work/deprecated/model/test_scenario.rb +0 -137
- data/work/deprecated/model/test_suite.rb +0 -297
- data/work/deprecated/rake.rb +0 -103
- data/work/deprecated/test/case_coverage_analyzer.rb +0 -25
- data/work/deprecated/test/case_test_case_dsl.rb +0 -46
- data/work/deprecated/test/fixtures/case_complete.rb +0 -25
- data/work/deprecated/test/fixtures/case_inclusion.rb +0 -18
- data/work/deprecated/test/fixtures/case_incomplete.rb +0 -12
- data/work/deprecated/test/fixtures/example.rb +0 -13
- data/work/deprecated/test/fixtures/helper.rb +0 -13
- data/work/deprecated/test/runner +0 -2
- data/work/old-tests/case_example.rb +0 -15
- data/work/old-tests/feature_example.rb +0 -40
- data/work/reference/dsl2.rb +0 -140
- data/work/reference/dynamic_constant_lookup.rb +0 -76
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
module Lemon
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
class TestClause
|
|
5
|
-
|
|
6
|
-
# New unit test procedure.
|
|
7
|
-
#
|
|
8
|
-
def initialize(scenario, description, options={}) #, &procedure)
|
|
9
|
-
@context = scenario
|
|
10
|
-
@description = description
|
|
11
|
-
|
|
12
|
-
@type = options[:type]
|
|
13
|
-
|
|
14
|
-
#@subject = options[:subject]
|
|
15
|
-
#@aspect = options[:aspect]
|
|
16
|
-
#@omit = options[:omit]
|
|
17
|
-
|
|
18
|
-
#@procedure = procedure
|
|
19
|
-
|
|
20
|
-
@tested = false
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
attr :type
|
|
24
|
-
|
|
25
|
-
public
|
|
26
|
-
|
|
27
|
-
# The case to which this test belongs.
|
|
28
|
-
attr :context
|
|
29
|
-
|
|
30
|
-
# Setup and teardown procedures.
|
|
31
|
-
#attr :subject
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
#def target
|
|
35
|
-
# context.
|
|
36
|
-
#end
|
|
37
|
-
|
|
38
|
-
# Description of test.
|
|
39
|
-
attr :description
|
|
40
|
-
|
|
41
|
-
# Test procedure, in which test assertions should be made.
|
|
42
|
-
#attr :procedure
|
|
43
|
-
|
|
44
|
-
# The before and after advice from the context.
|
|
45
|
-
#def advice
|
|
46
|
-
# context.advice
|
|
47
|
-
#end
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
#def name ; @target ; end
|
|
51
|
-
|
|
52
|
-
# Is this unit test for a class or module level method?
|
|
53
|
-
#def function?
|
|
54
|
-
# context.function?
|
|
55
|
-
#end
|
|
56
|
-
|
|
57
|
-
#
|
|
58
|
-
attr_accessor :omit
|
|
59
|
-
|
|
60
|
-
#
|
|
61
|
-
def omit?
|
|
62
|
-
@omit
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
#
|
|
66
|
-
#attr_accessor :tested
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
#def to_s
|
|
70
|
-
# if function?
|
|
71
|
-
# "#{test_case}.#{target}"
|
|
72
|
-
# else
|
|
73
|
-
# "#{test_case}##{target}"
|
|
74
|
-
# end
|
|
75
|
-
#end
|
|
76
|
-
|
|
77
|
-
#
|
|
78
|
-
def to_s
|
|
79
|
-
"#{type.to_s.capitalize} #{description}"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
def subject
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
#
|
|
87
|
-
def scope
|
|
88
|
-
context.scope
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
#
|
|
92
|
-
def to_proc
|
|
93
|
-
lambda{ call }
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
#
|
|
97
|
-
#def match?(match)
|
|
98
|
-
# match == target || match === aspect
|
|
99
|
-
#end
|
|
100
|
-
|
|
101
|
-
#
|
|
102
|
-
def call
|
|
103
|
-
context.run(self) do
|
|
104
|
-
#subject.run_setup(scope) if subject
|
|
105
|
-
scope.instance_exec(*arguments, &procedure)
|
|
106
|
-
#subject.run_teardown(scope) if subject
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
end
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
=begin
|
|
2
|
-
module Lemon
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
class TestContext
|
|
6
|
-
|
|
7
|
-
# The test case to which this concern belongs.
|
|
8
|
-
attr :test_case
|
|
9
|
-
|
|
10
|
-
# The description of this concern. Make this
|
|
11
|
-
# as detailed as you wish.
|
|
12
|
-
attr :description
|
|
13
|
-
|
|
14
|
-
# New case instance.
|
|
15
|
-
def initialize(test_case, description, options={}, &block)
|
|
16
|
-
@test_case = test_case
|
|
17
|
-
@description = description.to_s
|
|
18
|
-
@function = options[:function] || options[:singleton]
|
|
19
|
-
@type = options[:type] || :context
|
|
20
|
-
@block = block
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
def teardown=(procedure)
|
|
25
|
-
@teardown = procedure
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Teardown instance.
|
|
29
|
-
def teardown(scope=nil)
|
|
30
|
-
if scope
|
|
31
|
-
scope.instance_eval(&@teardown) if @teardown
|
|
32
|
-
else
|
|
33
|
-
@teardown
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Create instance.
|
|
38
|
-
def setup(scope)
|
|
39
|
-
if @block
|
|
40
|
-
scope.instance_eval(&@block)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def function? ; false ; end
|
|
45
|
-
alias_method :meta?, :function?
|
|
46
|
-
|
|
47
|
-
# Returns the description with newlines removed.
|
|
48
|
-
def to_s
|
|
49
|
-
description.gsub(/\n/, ' ')
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
=end
|
|
55
|
-
|
|
56
|
-
=begin
|
|
57
|
-
#
|
|
58
|
-
class TestInstance < TestContext
|
|
59
|
-
|
|
60
|
-
# Create instance.
|
|
61
|
-
def setup(scope)
|
|
62
|
-
if @block
|
|
63
|
-
ins = scope.instance_eval(&@block)
|
|
64
|
-
raise "target type mismatch" unless test_case.target === ins
|
|
65
|
-
end
|
|
66
|
-
ins
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
#
|
|
72
|
-
class TestSingleton < TestContext
|
|
73
|
-
|
|
74
|
-
# Create instance.
|
|
75
|
-
def setup(scope)
|
|
76
|
-
if @block
|
|
77
|
-
ins = scope.instance_eval(&@block)
|
|
78
|
-
raise "target type mismatch" unless test_case.target == ins
|
|
79
|
-
else
|
|
80
|
-
ins = @test_case.target
|
|
81
|
-
end
|
|
82
|
-
ins
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def function? ; true ; end
|
|
86
|
-
alias_method :meta?, :function?
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
=end
|
|
90
|
-
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
require 'lemon/model/pending'
|
|
2
|
-
require 'lemon/model/test_context'
|
|
3
|
-
require 'lemon/model/test_advice'
|
|
4
|
-
require 'lemon/model/test_scenario'
|
|
5
|
-
|
|
6
|
-
module Lemon
|
|
7
|
-
|
|
8
|
-
# The TestFeature ...
|
|
9
|
-
#
|
|
10
|
-
# * `tests` are _scenarios_,
|
|
11
|
-
# * `advice` are _given_, _when_ and _then_ rules.
|
|
12
|
-
#
|
|
13
|
-
class TestFeature < TestCase
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
def initialize(context, settings={}, &block)
|
|
17
|
-
@story = []
|
|
18
|
-
super(context, settings, &block)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
## This has to be redefined in each subclass to pick
|
|
22
|
-
## up there respective DSL classes.
|
|
23
|
-
#def evaluate(&block)
|
|
24
|
-
# @dsl = DSL.new(self, &block)
|
|
25
|
-
#end
|
|
26
|
-
|
|
27
|
-
attr :story
|
|
28
|
-
|
|
29
|
-
# Feature scenarios are tests.
|
|
30
|
-
alias_method :scenarios, :tests
|
|
31
|
-
|
|
32
|
-
#
|
|
33
|
-
def to_s
|
|
34
|
-
"Feature #{target}"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
def to_s #description
|
|
39
|
-
(["Feature: #{target}"] + story).join("\n ")
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Run test in the context of this case.
|
|
43
|
-
#
|
|
44
|
-
# @param [TestProc] test
|
|
45
|
-
# The test procedure instance to run.
|
|
46
|
-
#
|
|
47
|
-
def run(&block)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
#
|
|
51
|
-
class DSL < Module
|
|
52
|
-
|
|
53
|
-
#
|
|
54
|
-
def initialize(feature, &code)
|
|
55
|
-
@feature = feature
|
|
56
|
-
|
|
57
|
-
module_eval(&code)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
#
|
|
61
|
-
def To(description)
|
|
62
|
-
@feature.story << "To " + description
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
#
|
|
66
|
-
def As(description)
|
|
67
|
-
@feature.story << "As " + description
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
def We(description)
|
|
72
|
-
@feature.story << "We " + description
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
#
|
|
76
|
-
def Scenario(description, &procedure)
|
|
77
|
-
scenario = TestScenario.new(@feature, description, &procedure)
|
|
78
|
-
@feature.scenarios << scenario
|
|
79
|
-
scenario
|
|
80
|
-
end
|
|
81
|
-
alias_method :scenario, :Scenario
|
|
82
|
-
|
|
83
|
-
# Omit a scenario from test runs.
|
|
84
|
-
#
|
|
85
|
-
# omit unit :foo do
|
|
86
|
-
# # ...
|
|
87
|
-
# end
|
|
88
|
-
#
|
|
89
|
-
def Omit(scenario)
|
|
90
|
-
scenario.omit = true
|
|
91
|
-
end
|
|
92
|
-
alias_method :omit, :Omit
|
|
93
|
-
|
|
94
|
-
# Given ...
|
|
95
|
-
#
|
|
96
|
-
# @param [String] description
|
|
97
|
-
# A brief description of the _given_ criteria.
|
|
98
|
-
#
|
|
99
|
-
def Given(description, &procedure)
|
|
100
|
-
@feature.advice[:given][description] = procedure
|
|
101
|
-
end
|
|
102
|
-
alias_method :given, :Given
|
|
103
|
-
|
|
104
|
-
# When ...
|
|
105
|
-
#
|
|
106
|
-
# @param [String] description
|
|
107
|
-
# A brief description of the _when_ criteria.
|
|
108
|
-
#
|
|
109
|
-
def When(description, &procedure)
|
|
110
|
-
@feature.advice[:when][description] = procedure
|
|
111
|
-
end
|
|
112
|
-
alias_method :wence, :When
|
|
113
|
-
|
|
114
|
-
# Then ...
|
|
115
|
-
#
|
|
116
|
-
# @param [String] description
|
|
117
|
-
# A brief description of the _then_ criteria.
|
|
118
|
-
#
|
|
119
|
-
def Then(description, &procedure)
|
|
120
|
-
@feature.advice[:then][description] = procedure
|
|
121
|
-
end
|
|
122
|
-
alias_method :hence, :Then
|
|
123
|
-
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
end
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
require 'lemon/model/test_clause'
|
|
2
|
-
|
|
3
|
-
module Lemon
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
class TestScenario < TestCase
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
def initialize(feature, summary, options={}, &block)
|
|
10
|
-
@feature = feature
|
|
11
|
-
@summary = summary
|
|
12
|
-
|
|
13
|
-
@tests = []
|
|
14
|
-
|
|
15
|
-
evaluate(&block)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
def evaluate(&procedure)
|
|
20
|
-
@dsl = DSL.new(self, &procedure)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
attr :feature
|
|
25
|
-
|
|
26
|
-
#
|
|
27
|
-
attr :dsl
|
|
28
|
-
|
|
29
|
-
attr_accessor :omit
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
def omit?
|
|
33
|
-
@omit
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
#
|
|
37
|
-
def to_s
|
|
38
|
-
"Scenario: #{@summary}"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def subject
|
|
42
|
-
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
def run(clause)
|
|
47
|
-
type = clause.type
|
|
48
|
-
desc = clause.description
|
|
49
|
-
feature.advice[type].each do |mask, proc|
|
|
50
|
-
if md = match_regexp(mask).match(desc)
|
|
51
|
-
scope.instance_exec(*md[1..-1], &proc)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
#
|
|
57
|
-
#--
|
|
58
|
-
# TODO: Change so that the scope is the DSL
|
|
59
|
-
# and includes the DSL of the context?
|
|
60
|
-
#++
|
|
61
|
-
def scope
|
|
62
|
-
@scope ||= (
|
|
63
|
-
#if feature
|
|
64
|
-
# scope = feature.scope || Object.new
|
|
65
|
-
# scope.extend(dsl)
|
|
66
|
-
#else
|
|
67
|
-
scope = Object.new
|
|
68
|
-
scope.extend(dsl)
|
|
69
|
-
#end
|
|
70
|
-
)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
#
|
|
74
|
-
#def find
|
|
75
|
-
# features.clauses[@type].find{ |c| c =~ @description }
|
|
76
|
-
#end
|
|
77
|
-
|
|
78
|
-
# Convert matching string into a regular expression. If the string
|
|
79
|
-
# contains double parenthesis, such as ((.*?)), then the text within
|
|
80
|
-
# them is treated as in regular expression and kept verbatium.
|
|
81
|
-
#
|
|
82
|
-
# TODO: Better way to isolate regexp. Maybe ?:(.*?) or /(.*?)/.
|
|
83
|
-
#
|
|
84
|
-
def match_regexp(str)
|
|
85
|
-
str = str.split(/(\(\(.*?\)\))(?!\))/).map{ |x|
|
|
86
|
-
x =~ /\A\(\((.*)\)\)\Z/ ? $1 : Regexp.escape(x)
|
|
87
|
-
}.join
|
|
88
|
-
str = str.gsub(/\\\s+/, '\s+')
|
|
89
|
-
Regexp.new(str, Regexp::IGNORECASE)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# TODO: Need to ensure the correct order of Given, When, Then.
|
|
94
|
-
class DSL < Module
|
|
95
|
-
|
|
96
|
-
#
|
|
97
|
-
def initialize(scenario, &code)
|
|
98
|
-
@scenario = scenario
|
|
99
|
-
|
|
100
|
-
module_eval(&code)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Given ...
|
|
104
|
-
#
|
|
105
|
-
# @param [String] description
|
|
106
|
-
# A brief description of what the setup procedure sets-up.
|
|
107
|
-
#
|
|
108
|
-
def Given(description)
|
|
109
|
-
@scenario.tests << TestClause.new(@scenario, description, :type=>:given)
|
|
110
|
-
end
|
|
111
|
-
alias_method :given, :Given
|
|
112
|
-
|
|
113
|
-
# When ...
|
|
114
|
-
#
|
|
115
|
-
# @param [String] description
|
|
116
|
-
# A brief description of what the setup procedure sets-up.
|
|
117
|
-
#
|
|
118
|
-
def When(description)
|
|
119
|
-
@scenario.tests << TestClause.new(@scenario, description, :type=>:when)
|
|
120
|
-
end
|
|
121
|
-
alias_method :wence, :When
|
|
122
|
-
|
|
123
|
-
# Then ...
|
|
124
|
-
#
|
|
125
|
-
# @param [String] description
|
|
126
|
-
# A brief description of what the setup procedure sets-up.
|
|
127
|
-
#
|
|
128
|
-
def Then(description)
|
|
129
|
-
@scenario.tests << TestClause.new(@scenario, description, :type=>:then)
|
|
130
|
-
end
|
|
131
|
-
alias_method :hence, :Then
|
|
132
|
-
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
end
|