mutant 0.5.17 → 0.5.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +6 -0
- data/Rakefile +13 -0
- data/config/flay.yml +1 -1
- data/config/reek.yml +8 -1
- data/lib/mutant.rb +18 -3
- data/lib/mutant/cli.rb +6 -3
- data/lib/mutant/constants.rb +3 -0
- data/lib/mutant/expression.rb +110 -0
- data/lib/mutant/expression/method.rb +92 -0
- data/lib/mutant/expression/namespace.rb +90 -0
- data/lib/mutant/matcher/namespace.rb +3 -4
- data/lib/mutant/meta.rb +31 -0
- data/lib/mutant/meta/example.rb +152 -0
- data/lib/mutant/meta/example/dsl.rb +105 -0
- data/lib/mutant/mutator/node.rb +6 -6
- data/lib/mutant/mutator/node/arguments.rb +1 -1
- data/lib/mutant/mutator/node/begin.rb +1 -1
- data/lib/mutant/mutator/node/const.rb +1 -1
- data/lib/mutant/mutator/node/if.rb +6 -6
- data/lib/mutant/mutator/node/literal/array.rb +2 -2
- data/lib/mutant/mutator/node/literal/hash.rb +2 -2
- data/lib/mutant/mutator/node/literal/range.rb +3 -3
- data/lib/mutant/mutator/node/literal/regex.rb +2 -2
- data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
- data/lib/mutant/mutator/node/op_asgn.rb +1 -3
- data/lib/mutant/mutator/node/or_asgn.rb +31 -0
- data/lib/mutant/mutator/node/send.rb +1 -1
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -1
- data/lib/mutant/reporter/cli/report/mutation.rb +11 -1
- data/lib/mutant/strategy.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- data/meta/and.rb +12 -0
- data/meta/and_asgn.rb +12 -0
- data/meta/array.rb +30 -0
- data/meta/begin.rb +15 -0
- data/meta/binary.rb +12 -0
- data/meta/block.rb +55 -0
- data/meta/block_pass.rb +8 -0
- data/meta/blockarg.rb +10 -0
- data/meta/boolean.rb +15 -0
- data/meta/break.rb +11 -0
- data/meta/case.rb +303 -0
- data/meta/casgn.rb +9 -0
- data/meta/cbase.rb +8 -0
- data/meta/const.rb +9 -0
- data/meta/cvar.rb +7 -0
- data/meta/cvasgn.rb +10 -0
- data/meta/define.rb +118 -0
- data/meta/defined.rb +7 -0
- data/meta/dstr.rb +10 -0
- data/meta/dsym.rb +11 -0
- data/meta/ensure.rb +9 -0
- data/meta/fixnum.rb +19 -0
- data/meta/float.rb +38 -0
- data/meta/gvar.rb +7 -0
- data/meta/gvasgn.rb +10 -0
- data/meta/hash.rb +25 -0
- data/meta/if.rb +57 -0
- data/meta/ivasgn.rb +10 -0
- data/meta/kwbegin.rb +9 -0
- data/meta/lvar.rb +14 -0
- data/meta/lvasgn.rb +10 -0
- data/meta/masgn.rb +7 -0
- data/meta/match_current_line.rb +14 -0
- data/meta/next.rb +11 -0
- data/meta/nil.rb +5 -0
- data/meta/nthref.rb +14 -0
- data/meta/op_assgn.rb +15 -0
- data/meta/or_asgn.rb +22 -0
- data/meta/range.rb +41 -0
- data/meta/redo.rb +5 -0
- data/meta/regex.rb +20 -0
- data/meta/rescue.rb +38 -0
- data/meta/restarg.rb +11 -0
- data/meta/return.rb +15 -0
- data/meta/self.rb +7 -0
- data/meta/send.rb +240 -0
- data/meta/string.rb +7 -0
- data/meta/super.rb +26 -0
- data/meta/symbol.rb +8 -0
- data/meta/unless.rb +15 -0
- data/meta/while.rb +24 -0
- data/meta/yield.rb +10 -0
- data/mutant.gemspec +1 -0
- data/spec/integration/mutant/corpus_spec.rb +29 -25
- data/spec/spec_helper.rb +2 -0
- data/spec/support/mutation_verifier.rb +1 -0
- data/spec/unit/mutant/cli_new_spec.rb +6 -6
- data/spec/unit/mutant/expression/method_spec.rb +50 -0
- data/spec/unit/mutant/expression/namespace/flat_spec.rb +32 -0
- data/spec/unit/mutant/expression/namespace/recursive_spec.rb +37 -0
- data/spec/unit/mutant/matcher/namespace_spec.rb +2 -2
- data/spec/unit/mutant/mutation_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node_spec.rb +14 -0
- metadata +123 -139
- data/lib/mutant/cli/classifier.rb +0 -139
- data/lib/mutant/cli/classifier/method.rb +0 -105
- data/lib/mutant/cli/classifier/namespace.rb +0 -49
- data/spec/unit/mutant/cli/classifier/method_spec.rb +0 -77
- data/spec/unit/mutant/cli/classifier/namespace/flat_spec.rb +0 -58
- data/spec/unit/mutant/cli/classifier/namespace/recursive_spec.rb +0 -58
- data/spec/unit/mutant/cli/classifier_spec.rb +0 -59
- data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +0 -19
- data/spec/unit/mutant/mutator/node/begin_spec.rb +0 -32
- data/spec/unit/mutant/mutator/node/binary_spec.rb +0 -41
- data/spec/unit/mutant/mutator/node/block_pass_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/block_spec.rb +0 -83
- data/spec/unit/mutant/mutator/node/blockarg_spec.rb +0 -17
- data/spec/unit/mutant/mutator/node/case_spec.rb +0 -329
- data/spec/unit/mutant/mutator/node/cbase_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/conditional_loop_spec.rb +0 -58
- data/spec/unit/mutant/mutator/node/const_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/define_spec.rb +0 -171
- data/spec/unit/mutant/mutator/node/defined_spec.rb +0 -14
- data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -17
- data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -18
- data/spec/unit/mutant/mutator/node/ensure_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/if_spec.rb +0 -77
- data/spec/unit/mutant/mutator/node/kwbegin_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/literal/array_spec.rb +0 -47
- data/spec/unit/mutant/mutator/node/literal/boolean_spec.rb +0 -25
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +0 -13
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -53
- data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +0 -33
- data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +0 -10
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -56
- data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +0 -36
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +0 -15
- data/spec/unit/mutant/mutator/node/loop_ctrl_spec.rb +0 -37
- data/spec/unit/mutant/mutator/node/masgn_spec.rb +0 -14
- data/spec/unit/mutant/mutator/node/match_current_line_spec.rb +0 -21
- data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +0 -78
- data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +0 -16
- data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +0 -61
- data/spec/unit/mutant/mutator/node/nthref_spec.rb +0 -19
- data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -22
- data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +0 -19
- data/spec/unit/mutant/mutator/node/redo_spec.rb +0 -10
- data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -63
- data/spec/unit/mutant/mutator/node/restarg_spec.rb +0 -18
- data/spec/unit/mutant/mutator/node/return_spec.rb +0 -31
- data/spec/unit/mutant/mutator/node/send_spec.rb +0 -382
- data/spec/unit/mutant/mutator/node/super_spec.rb +0 -46
- data/spec/unit/mutant/mutator/node/yield_spec.rb +0 -17
@@ -36,7 +36,7 @@ module Mutant
|
|
36
36
|
# @api private
|
37
37
|
#
|
38
38
|
def pattern
|
39
|
-
/\A#{Regexp.escape(namespace
|
39
|
+
/\A#{Regexp.escape(namespace)}(?:::)?/
|
40
40
|
end
|
41
41
|
memoize :pattern
|
42
42
|
|
@@ -87,12 +87,11 @@ It raised an error: #{exception.inspect} fix your lib!
|
|
87
87
|
#
|
88
88
|
def emit_scope(scope)
|
89
89
|
name = self.class.scope_name(scope)
|
90
|
-
# FIXME: Fix nokogiri to return a string here
|
91
90
|
unless name.nil? or name.kind_of?(String)
|
92
91
|
$stderr.puts <<-MESSAGE
|
93
92
|
WARNING:
|
94
|
-
#{scope.class}#name did not return a
|
95
|
-
Fix your lib!
|
93
|
+
#{scope.class}#name from: #{scope.inspect} did not return a String or nil.
|
94
|
+
Fix your lib to support normal ruby semantics!
|
96
95
|
MESSAGE
|
97
96
|
return
|
98
97
|
end
|
data/lib/mutant/meta.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Mutant
|
2
|
+
# Namespace for mutant metadata
|
3
|
+
module Meta
|
4
|
+
|
5
|
+
require 'mutant/meta/example'
|
6
|
+
require 'mutant/meta/example/dsl'
|
7
|
+
|
8
|
+
# Mutation example
|
9
|
+
class Example
|
10
|
+
|
11
|
+
ALL = []
|
12
|
+
|
13
|
+
# Add example
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def self.add(&block)
|
20
|
+
ALL << DSL.run(block)
|
21
|
+
end
|
22
|
+
|
23
|
+
Pathname.glob(Pathname.new(__FILE__).parent.parent.parent.join('meta', '**/*.rb'))
|
24
|
+
.sort
|
25
|
+
.each(&method(:require))
|
26
|
+
ALL.freeze
|
27
|
+
|
28
|
+
end # Example
|
29
|
+
|
30
|
+
end # Meta
|
31
|
+
end # Mutant
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
module Meta
|
5
|
+
class Example
|
6
|
+
include Adamantium, Concord::Public.new(:node, :mutations)
|
7
|
+
|
8
|
+
# Return a verification instance
|
9
|
+
#
|
10
|
+
# @return [Verification]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
def verification
|
15
|
+
Verification.new(self, generated)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return generated mutations
|
19
|
+
#
|
20
|
+
# @return [Emumerable<Parser::AST::Node>]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
def generated
|
25
|
+
Mutant::Mutator.each(node).to_a
|
26
|
+
end
|
27
|
+
memoize :generated
|
28
|
+
|
29
|
+
# Example verification
|
30
|
+
class Verification
|
31
|
+
include Adamantium::Flat, Concord.new(:example, :generated)
|
32
|
+
|
33
|
+
# Test if mutation was verified successfully
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
def success?
|
40
|
+
unparser.success? && missing.empty? && unexpected.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return error report
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
def error_report
|
50
|
+
unless unparser.success?
|
51
|
+
return unparser.report
|
52
|
+
end
|
53
|
+
mutation_report
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Return unexpected mutationso
|
59
|
+
#
|
60
|
+
# @return [Array<Parser::AST::Node>]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
#
|
64
|
+
def unexpected
|
65
|
+
generated - example.mutations
|
66
|
+
end
|
67
|
+
memoize :unexpected
|
68
|
+
|
69
|
+
# Return mutation report
|
70
|
+
#
|
71
|
+
# @return [String]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
#
|
75
|
+
def mutation_report
|
76
|
+
original_node = example.node
|
77
|
+
[
|
78
|
+
'Original-AST:',
|
79
|
+
original_node.inspect,
|
80
|
+
'Original-Source:',
|
81
|
+
Unparser.unparse(original_node),
|
82
|
+
*missing_report,
|
83
|
+
*unexpected_report
|
84
|
+
].join("\n======\n")
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return missing report
|
88
|
+
#
|
89
|
+
# @return [Array, nil]
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
#
|
93
|
+
def missing_report
|
94
|
+
if missing.any?
|
95
|
+
['Missing mutations:', missing.map(&method(:format_mutation)).join("\n-----\n")]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Return unexpected report
|
100
|
+
#
|
101
|
+
# @return [Array, nil]
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
#
|
105
|
+
def unexpected_report
|
106
|
+
if unexpected.any?
|
107
|
+
[
|
108
|
+
'Unexpected mutations:',
|
109
|
+
unexpected.map(&method(:format_mutation)).join("\n-----\n")
|
110
|
+
]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Format mutation
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
#
|
120
|
+
def format_mutation(node)
|
121
|
+
[
|
122
|
+
node.inspect,
|
123
|
+
Unparser.unparse(node)
|
124
|
+
].join("\n")
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return missing mutationso
|
128
|
+
#
|
129
|
+
# @return [Array<Parser::AST::Node>]
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
#
|
133
|
+
def missing
|
134
|
+
example.mutations - generated
|
135
|
+
end
|
136
|
+
memoize :missing
|
137
|
+
|
138
|
+
# Return unparser verifier
|
139
|
+
#
|
140
|
+
# @return [Unparser::CLI::Source]
|
141
|
+
#
|
142
|
+
# @api private
|
143
|
+
#
|
144
|
+
def unparser
|
145
|
+
Unparser::CLI::Source::Node.new(Unparser::Preprocessor.run(example.node))
|
146
|
+
end
|
147
|
+
memoize :unparser
|
148
|
+
|
149
|
+
end # Verification
|
150
|
+
end # Example
|
151
|
+
end # Meta
|
152
|
+
end # Mutant
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Mutant
|
2
|
+
module Meta
|
3
|
+
class Example
|
4
|
+
|
5
|
+
# Example DSL
|
6
|
+
class DSL
|
7
|
+
include NodeHelpers
|
8
|
+
|
9
|
+
# Run DSL on block
|
10
|
+
#
|
11
|
+
# @return [Example]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
def self.run(block)
|
16
|
+
instance = new
|
17
|
+
instance.instance_eval(&block)
|
18
|
+
instance.example
|
19
|
+
end
|
20
|
+
|
21
|
+
# Initialize DSL context
|
22
|
+
#
|
23
|
+
# @return [undefined]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def initialize
|
28
|
+
@source = nil
|
29
|
+
@expected = []
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return example
|
33
|
+
#
|
34
|
+
# @return [Example]
|
35
|
+
#
|
36
|
+
# @raise [RuntimeError]
|
37
|
+
# in case example cannot be build
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def example
|
42
|
+
raise 'source not defined' unless @source
|
43
|
+
Example.new(@source, @expected)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Set original source
|
49
|
+
#
|
50
|
+
# @param [String,Parser::AST::Node] input
|
51
|
+
#
|
52
|
+
# @return [self]
|
53
|
+
#
|
54
|
+
def source(input)
|
55
|
+
raise 'source already defined' if @source
|
56
|
+
@source = node(input)
|
57
|
+
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Add expected mutation
|
62
|
+
#
|
63
|
+
# @param [String,Parser::AST::Node] input
|
64
|
+
#
|
65
|
+
# @return [self]
|
66
|
+
#
|
67
|
+
def mutation(input)
|
68
|
+
node = node(input)
|
69
|
+
if @expected.include?(node)
|
70
|
+
raise "Node for input: #{input.inspect} is already expected"
|
71
|
+
end
|
72
|
+
@expected << node
|
73
|
+
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
# Helper method to coerce input to node
|
78
|
+
#
|
79
|
+
# @param [String,Parser::AST::Node] input
|
80
|
+
#
|
81
|
+
# @return [Parser::AST::Node]
|
82
|
+
#
|
83
|
+
# @raise [RuntimeError]
|
84
|
+
# in case input cannot be coerced
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
#
|
88
|
+
def node(input)
|
89
|
+
node =
|
90
|
+
case input
|
91
|
+
when String
|
92
|
+
Parser::CurrentRuby.parse(input)
|
93
|
+
when Parser::AST::Node
|
94
|
+
input
|
95
|
+
else
|
96
|
+
raise "Cannot coerce to node: #{source.inspect}"
|
97
|
+
end
|
98
|
+
|
99
|
+
Unparser::Preprocessor.run(node)
|
100
|
+
end
|
101
|
+
|
102
|
+
end # DSL
|
103
|
+
end # Example
|
104
|
+
end # Meta
|
105
|
+
end # Mutant
|
data/lib/mutant/mutator/node.rb
CHANGED
@@ -96,7 +96,7 @@ module Mutant
|
|
96
96
|
#
|
97
97
|
def emit_children_mutations
|
98
98
|
Mutator::Util::Array.each(children, self) do |children|
|
99
|
-
|
99
|
+
emit_type(*children)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -136,7 +136,7 @@ module Mutant
|
|
136
136
|
def delete_child(index)
|
137
137
|
dup_children = children.dup
|
138
138
|
dup_children.delete_at(index)
|
139
|
-
|
139
|
+
emit_type(*dup_children)
|
140
140
|
end
|
141
141
|
|
142
142
|
# Emit updated child
|
@@ -151,7 +151,7 @@ module Mutant
|
|
151
151
|
def emit_child_update(index, node)
|
152
152
|
new_children = children.dup
|
153
153
|
new_children[index] = node
|
154
|
-
|
154
|
+
emit_type(*new_children)
|
155
155
|
end
|
156
156
|
|
157
157
|
# Emit a new AST node with same class as wrapped node
|
@@ -162,7 +162,7 @@ module Mutant
|
|
162
162
|
#
|
163
163
|
# @api private
|
164
164
|
#
|
165
|
-
def
|
165
|
+
def emit_type(*children)
|
166
166
|
emit(new_self(*children))
|
167
167
|
end
|
168
168
|
|
@@ -196,7 +196,7 @@ module Mutant
|
|
196
196
|
#
|
197
197
|
def emit_values(values)
|
198
198
|
values.each do |value|
|
199
|
-
|
199
|
+
emit_type(value)
|
200
200
|
end
|
201
201
|
end
|
202
202
|
|
@@ -221,7 +221,7 @@ module Mutant
|
|
221
221
|
# @api private
|
222
222
|
#
|
223
223
|
def asgn_left?
|
224
|
-
OP_ASSIGN.include?(parent_type) && parent.
|
224
|
+
OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
|
225
225
|
end
|
226
226
|
|
227
227
|
end # Node
|
@@ -19,7 +19,7 @@ module Mutant
|
|
19
19
|
#
|
20
20
|
def dispatch
|
21
21
|
emit_nil unless parent_type == :const
|
22
|
-
|
22
|
+
emit_type(nil, *children.drop(1))
|
23
23
|
children.each_with_index do |child, index|
|
24
24
|
mutate_child(index) if child.kind_of?(Parser::AST::Node)
|
25
25
|
end
|
@@ -33,9 +33,9 @@ module Mutant
|
|
33
33
|
#
|
34
34
|
def mutate_condition
|
35
35
|
emit_condition_mutations
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
emit_type(n_not(condition), if_branch, else_branch) unless condition.type == :match_current_line
|
37
|
+
emit_type(N_TRUE, if_branch, else_branch)
|
38
|
+
emit_type(N_FALSE, if_branch, else_branch)
|
39
39
|
end
|
40
40
|
|
41
41
|
# Emit if branch mutations
|
@@ -45,10 +45,10 @@ module Mutant
|
|
45
45
|
# @api private
|
46
46
|
#
|
47
47
|
def mutate_if_branch
|
48
|
-
|
48
|
+
emit_type(condition, else_branch, nil) if else_branch
|
49
49
|
if if_branch
|
50
50
|
emit_if_branch_mutations
|
51
|
-
|
51
|
+
emit_type(condition, if_branch, nil)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -61,7 +61,7 @@ module Mutant
|
|
61
61
|
def mutate_else_branch
|
62
62
|
if else_branch
|
63
63
|
emit_else_branch_mutations
|
64
|
-
|
64
|
+
emit_type(condition, nil, else_branch)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -19,7 +19,7 @@ module Mutant
|
|
19
19
|
#
|
20
20
|
def dispatch
|
21
21
|
emit_nil
|
22
|
-
|
22
|
+
emit_type
|
23
23
|
mutate_body
|
24
24
|
if children.one?
|
25
25
|
emit(children.first)
|
@@ -36,7 +36,7 @@ module Mutant
|
|
36
36
|
children.each_index do |index|
|
37
37
|
dup_children = children.dup
|
38
38
|
dup_children.delete_at(index)
|
39
|
-
|
39
|
+
emit_type(*dup_children)
|
40
40
|
mutate_child(index)
|
41
41
|
end
|
42
42
|
end
|