deep-cover 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +227 -0
  3. data/Gemfile +5 -2
  4. data/Rakefile +9 -6
  5. data/bin/console +3 -3
  6. data/bin/cov +8 -8
  7. data/bin/gemcov +2 -2
  8. data/bin/selfcov +5 -5
  9. data/bin/test_gems +11 -10
  10. data/bin/testall +6 -6
  11. data/deep_cover.gemspec +26 -21
  12. data/exe/deep-cover +1 -0
  13. data/lib/deep-cover.rb +2 -0
  14. data/lib/deep_cover.rb +3 -0
  15. data/lib/deep_cover/analyser.rb +2 -0
  16. data/lib/deep_cover/analyser/base.rb +2 -0
  17. data/lib/deep_cover/analyser/branch.rb +4 -2
  18. data/lib/deep_cover/analyser/covered_code_source.rb +3 -1
  19. data/lib/deep_cover/analyser/function.rb +3 -1
  20. data/lib/deep_cover/analyser/ignore_uncovered.rb +6 -4
  21. data/lib/deep_cover/analyser/node.rb +3 -0
  22. data/lib/deep_cover/analyser/optionally_covered.rb +12 -7
  23. data/lib/deep_cover/analyser/per_char.rb +7 -6
  24. data/lib/deep_cover/analyser/per_line.rb +9 -8
  25. data/lib/deep_cover/analyser/statement.rb +2 -0
  26. data/lib/deep_cover/analyser/subset.rb +4 -1
  27. data/lib/deep_cover/auto_run.rb +3 -0
  28. data/lib/deep_cover/autoload_tracker.rb +6 -3
  29. data/lib/deep_cover/backports.rb +2 -0
  30. data/lib/deep_cover/base.rb +11 -2
  31. data/lib/deep_cover/builtin_takeover.rb +2 -0
  32. data/lib/deep_cover/cli/debugger.rb +55 -30
  33. data/lib/deep_cover/cli/deep_cover.rb +17 -11
  34. data/lib/deep_cover/cli/instrumented_clone_reporter.rb +16 -14
  35. data/lib/deep_cover/config.rb +29 -16
  36. data/lib/deep_cover/core_ext/autoload_overrides.rb +2 -0
  37. data/lib/deep_cover/core_ext/coverage_replacement.rb +2 -0
  38. data/lib/deep_cover/core_ext/load_overrides.rb +5 -6
  39. data/lib/deep_cover/core_ext/require_overrides.rb +6 -7
  40. data/lib/deep_cover/coverage.rb +21 -18
  41. data/lib/deep_cover/covered_code.rb +22 -12
  42. data/lib/deep_cover/custom_requirer.rb +82 -35
  43. data/lib/deep_cover/memoize.rb +48 -0
  44. data/lib/deep_cover/module_override.rb +2 -0
  45. data/lib/deep_cover/node.rb +14 -1
  46. data/lib/deep_cover/node/arguments.rb +2 -0
  47. data/lib/deep_cover/node/assignments.rb +32 -30
  48. data/lib/deep_cover/node/base.rb +30 -29
  49. data/lib/deep_cover/node/begin.rb +3 -1
  50. data/lib/deep_cover/node/block.rb +5 -2
  51. data/lib/deep_cover/node/branch.rb +2 -1
  52. data/lib/deep_cover/node/case.rb +15 -13
  53. data/lib/deep_cover/node/collections.rb +2 -0
  54. data/lib/deep_cover/node/const.rb +2 -0
  55. data/lib/deep_cover/node/def.rb +10 -8
  56. data/lib/deep_cover/node/empty_body.rb +2 -0
  57. data/lib/deep_cover/node/exceptions.rb +3 -1
  58. data/lib/deep_cover/node/if.rb +3 -1
  59. data/lib/deep_cover/node/keywords.rb +4 -2
  60. data/lib/deep_cover/node/literals.rb +2 -0
  61. data/lib/deep_cover/node/loops.rb +5 -3
  62. data/lib/deep_cover/node/mixin/can_augment_children.rb +8 -7
  63. data/lib/deep_cover/node/mixin/check_completion.rb +3 -1
  64. data/lib/deep_cover/node/mixin/child_can_be_empty.rb +4 -2
  65. data/lib/deep_cover/node/mixin/executed_after_children.rb +2 -0
  66. data/lib/deep_cover/node/mixin/execution_location.rb +4 -2
  67. data/lib/deep_cover/node/mixin/flow_accounting.rb +2 -0
  68. data/lib/deep_cover/node/mixin/has_child.rb +22 -18
  69. data/lib/deep_cover/node/mixin/has_child_handler.rb +10 -8
  70. data/lib/deep_cover/node/mixin/has_tracker.rb +4 -2
  71. data/lib/deep_cover/node/mixin/is_statement.rb +3 -1
  72. data/lib/deep_cover/node/mixin/rewriting.rb +5 -3
  73. data/lib/deep_cover/node/mixin/wrapper.rb +2 -0
  74. data/lib/deep_cover/node/module.rb +11 -9
  75. data/lib/deep_cover/node/root.rb +2 -0
  76. data/lib/deep_cover/node/send.rb +4 -2
  77. data/lib/deep_cover/node/short_circuit.rb +4 -2
  78. data/lib/deep_cover/node/splat.rb +2 -0
  79. data/lib/deep_cover/node/variables.rb +2 -0
  80. data/lib/deep_cover/parser_ext/range.rb +3 -1
  81. data/lib/deep_cover/problem_with_diagnostic.rb +11 -9
  82. data/lib/deep_cover/reporter.rb +2 -0
  83. data/lib/deep_cover/reporter/istanbul.rb +28 -24
  84. data/lib/deep_cover/tools.rb +2 -0
  85. data/lib/deep_cover/tools/builtin_coverage.rb +6 -4
  86. data/lib/deep_cover/tools/camelize.rb +3 -1
  87. data/lib/deep_cover/tools/dasherize.rb +3 -1
  88. data/lib/deep_cover/tools/dump_covered_code.rb +7 -6
  89. data/lib/deep_cover/tools/execute_sample.rb +13 -13
  90. data/lib/deep_cover/tools/format.rb +3 -1
  91. data/lib/deep_cover/tools/format_char_cover.rb +4 -2
  92. data/lib/deep_cover/tools/format_generated_code.rb +3 -1
  93. data/lib/deep_cover/tools/number_lines.rb +2 -0
  94. data/lib/deep_cover/tools/our_coverage.rb +5 -3
  95. data/lib/deep_cover/tools/profiling.rb +66 -0
  96. data/lib/deep_cover/tools/require_relative_dir.rb +3 -1
  97. data/lib/deep_cover/tools/silence_warnings.rb +4 -1
  98. data/lib/deep_cover/tools/slice.rb +3 -1
  99. data/lib/deep_cover/tools/truncate_backtrace.rb +2 -0
  100. data/lib/deep_cover/version.rb +3 -1
  101. metadata +47 -30
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module HasChildHandler
@@ -5,9 +7,9 @@ module DeepCover
5
7
  base.extend ClassMethods
6
8
  end
7
9
 
8
- def call_child_handler template, child, child_name = nil
9
- child_name ||= self.class.child_index_to_name(child.index, children.size) rescue binding.pry
10
- method_name = template % {name: child_name}
10
+ def call_child_handler(template, child, child_name = nil)
11
+ child_name ||= self.class.child_index_to_name(child.index, children.size)
12
+ method_name = format(template, name: child_name)
11
13
  if respond_to?(method_name)
12
14
  args = [child, child_name]
13
15
  arity = method(method_name).arity
@@ -22,10 +24,10 @@ module DeepCover
22
24
 
23
25
  module ClassMethods
24
26
  def has_child_handler(template)
25
- child_method_name = template % {name: 'child'}
27
+ child_method_name = format(template, name: 'child')
26
28
  action = template.gsub(/_%{name}/, '').gsub(/%{name}_/, '')
27
29
  const_name = "#{Tools.camelize(action)}Handler"
28
- class_eval <<-end_eval, __FILE__, __LINE__
30
+ class_eval <<-EVAL, __FILE__, __LINE__ + 1
29
31
  module #{const_name} # module RewriteHandler
30
32
  module ClassMethods # module ClassMethods
31
33
  def has_child(#{action}: nil, **h) # def has_child(rewrite: nil, **h)
@@ -43,11 +45,11 @@ module DeepCover
43
45
  end # end
44
46
  include #{const_name} # include RewriteHandler
45
47
  singleton_class.prepend #{const_name}::ClassMethods # singleton_class.prepend RewriteHandler::ClassMethods
46
- end_eval
48
+ EVAL
47
49
  end
48
50
 
49
51
  def define_child_handler(template, name, action)
50
- method_name = template % {name: name}
52
+ method_name = format(template, name: name)
51
53
  case action
52
54
  when nil
53
55
  # Nothing to do
@@ -63,7 +65,7 @@ module DeepCover
63
65
  when Proc
64
66
  define_method(method_name, &action)
65
67
  else
66
- define_method(method_name) {|*| action }
68
+ define_method(method_name) { |*| action }
67
69
  end
68
70
  end
69
71
  private :define_child_handler
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module HasTracker
@@ -25,14 +27,14 @@ module DeepCover
25
27
 
26
28
  def has_tracker(name)
27
29
  i = self::TRACKERS[name] = self::TRACKERS.size
28
- class_eval <<-end_eval, __FILE__, __LINE__ + 1
30
+ class_eval <<-EVAL, __FILE__, __LINE__ + 1
29
31
  def #{name}_tracker_source
30
32
  covered_code.tracker_source(@tracker_offset + #{i})
31
33
  end
32
34
  def #{name}_tracker_hits
33
35
  covered_code.tracker_hits(@tracker_offset + #{i})
34
36
  end
35
- end_eval
37
+ EVAL
36
38
  end
37
39
  end
38
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module IsStatement
@@ -10,7 +12,7 @@ module DeepCover
10
12
  end
11
13
 
12
14
  # Default child rewriting rule
13
- def is_child_statement(child, name=nil)
15
+ def is_child_statement(child, name = nil)
14
16
  :if_incompatible
15
17
  end
16
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module Rewriting
@@ -10,14 +12,14 @@ module DeepCover
10
12
  end
11
13
 
12
14
  # Default child rewriting rule
13
- def rewrite_child(child, name=nil)
15
+ def rewrite_child(child, name = nil)
14
16
  end
15
17
 
16
18
  # Replaces all the '%{local}' or '%{some_tracker}' in rewriting rules
17
19
  def resolve_rewrite(rule, context)
18
20
  return if rule == nil
19
21
  sources = context.tracker_sources
20
- rule % {local: covered_code.local_var, node: '%{node}', **sources}
22
+ format(rule, local: covered_code.local_var, node: '%{node}', **sources)
21
23
  end
22
24
 
23
25
  # Returns an array of [range, rule], where rule is a string containing '%{node}'
@@ -26,7 +28,7 @@ module DeepCover
26
28
  [
27
29
  resolve_rewrite(rewrite, self),
28
30
  resolve_rewrite(parent.rewrite_child(self), parent),
29
- ].compact.map{|rule| [expression, rule]}
31
+ ].compact.map { |rule| [expression, rule] }
30
32
  end
31
33
  end
32
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module Wrapper
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'const'
2
4
 
3
5
  module DeepCover
@@ -24,10 +26,10 @@ module DeepCover
24
26
  has_tracker :body_entry
25
27
  has_child const: {const: ModuleName}
26
28
  has_child body: Node,
27
- can_be_empty: -> { base_node.loc.end.begin },
28
- rewrite: '%{body_entry_tracker};%{local}=nil;%{node}',
29
- is_statement: true,
30
- flow_entry_count: :body_entry_tracker_hits
29
+ can_be_empty: -> { base_node.loc.end.begin },
30
+ rewrite: '%{body_entry_tracker};%{local}=nil;%{node}',
31
+ is_statement: true,
32
+ flow_entry_count: :body_entry_tracker_hits
31
33
  executed_loc_keys :keyword
32
34
 
33
35
  def execution_count
@@ -39,12 +41,12 @@ module DeepCover
39
41
  check_completion
40
42
  has_tracker :body_entry
41
43
  has_child const: {const: ModuleName}
42
- has_child inherit: [Node, nil] # TODO
44
+ has_child inherit: [Node, nil] # TODO
43
45
  has_child body: Node,
44
- can_be_empty: -> { base_node.loc.end.begin },
45
- rewrite: '%{body_entry_tracker};%{node}',
46
- is_statement: true,
47
- flow_entry_count: :body_entry_tracker_hits
46
+ can_be_empty: -> { base_node.loc.end.begin },
47
+ rewrite: '%{body_entry_tracker};%{node}',
48
+ is_statement: true,
49
+ flow_entry_count: :body_entry_tracker_hits
48
50
  executed_loc_keys :keyword
49
51
 
50
52
  def execution_count
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node::Root < Node
3
5
  has_tracker :root
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'literals'
2
4
  require_relative 'branch'
3
5
 
@@ -90,8 +92,8 @@ module DeepCover
90
92
  end
91
93
 
92
94
  def branches
93
- [ actual_send,
94
- TrivialBranch.new(condition: receiver, other_branch: actual_send)
95
+ [actual_send,
96
+ TrivialBranch.new(condition: receiver, other_branch: actual_send),
95
97
  ]
96
98
  end
97
99
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'branch'
2
4
 
3
5
  module DeepCover
@@ -7,12 +9,12 @@ module DeepCover
7
9
  has_tracker :conditional
8
10
  has_child lhs: Node
9
11
  has_child conditional: Node, flow_entry_count: :conditional_tracker_hits,
10
- rewrite: '((%{conditional_tracker};%{node}))'
12
+ rewrite: '((%{conditional_tracker};%{node}))'
11
13
 
12
14
  def branches
13
15
  [
14
16
  conditional,
15
- TrivialBranch.new(condition: lhs, other_branch: conditional)
17
+ TrivialBranch.new(condition: lhs, other_branch: conditional),
16
18
  ]
17
19
  end
18
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node
3
5
  class Splat < Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node
3
5
  class Variable < Node
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Parser::Source::Range
2
4
  def with(begin_pos: @begin_pos, end_pos: @end_pos)
3
5
  Parser::Source::Range.new(@source_buffer, begin_pos, end_pos)
@@ -9,7 +11,7 @@ class Parser::Source::Range
9
11
  inner_ranges.sort_by!(&:begin_pos)
10
12
  [self.begin, *inner_ranges, self.end]
11
13
  .each_cons(2)
12
- .map{|i, j| with(begin_pos: i.end_pos, end_pos: j.begin_pos)}
14
+ .map { |i, j| with(begin_pos: i.end_pos, end_pos: j.begin_pos) }
13
15
  .reject(&:empty?)
14
16
  end
15
17
 
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class ProblemWithDiagnostic < StandardError
3
5
  attr_reader :covered_code, :line_range, :original_exception
4
6
 
5
- def initialize(covered_code, line_range, original_exception=nil)
7
+ def initialize(covered_code, line_range, original_exception = nil)
6
8
  @covered_code = covered_code
7
9
  if line_range.is_a?(Parser::Source::Range)
8
10
  @line_range = line_range.line..line_range.last_line
@@ -14,11 +16,11 @@ module DeepCover
14
16
 
15
17
  def message
16
18
  msg = []
17
- msg << "You found a problem with DeepCover!"
18
- msg << "Please open an issue at https://github.com/deep-cover/deep-cover/issues"
19
- msg << "and include the following diagnostic information:"
19
+ msg << 'You found a problem with DeepCover!'
20
+ msg << 'Please open an issue at https://github.com/deep-cover/deep-cover/issues'
21
+ msg << 'and include the following diagnostic information:'
20
22
  extra = begin
21
- diagnostic_information_lines.map{|line| "| #{line}"}
23
+ diagnostic_information_lines.map { |line| "| #{line}" }
22
24
  rescue ProblemWithDiagnostic
23
25
  ["Oh no! We're in deep trouble!!!"]
24
26
  rescue Exception => e
@@ -32,13 +34,13 @@ module DeepCover
32
34
  lines = []
33
35
  lines << "Source file: #{covered_code.path}"
34
36
  lines << "Line numbers: #{line_range}"
35
- lines << "Source lines around location:"
36
- lines.concat source_lines.map{|line| " #{line}" }
37
+ lines << 'Source lines around location:'
38
+ lines.concat(source_lines.map { |line| " #{line}" })
37
39
  if original_exception
38
- lines << "Original exception:"
40
+ lines << 'Original exception:'
39
41
  lines << " #{original_exception.class.name}: #{original_exception.message}"
40
42
  backtrace = Tools.truncate_backtrace(original_exception)
41
- lines.concat backtrace.map{|line| " #{line}"}
43
+ lines.concat(backtrace.map { |line| " #{line}" })
42
44
  end
43
45
  lines
44
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Reporter
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
 
3
5
  module DeepCover
@@ -6,20 +8,20 @@ module DeepCover
6
8
  # Converters has no dependency on the including class.
7
9
  module Converters
8
10
  def convert_range(range)
9
- { start: {
10
- line: range.line,
11
- column: range.column,
12
- },
13
- end: {
14
- line: range.last_line,
15
- column: range.last_column-1, # Our ranges are exclusive, Istanbul's are inclusive
16
- },
11
+ {start: {
12
+ line: range.line,
13
+ column: range.column,
14
+ },
15
+ end: {
16
+ line: range.last_line,
17
+ column: range.last_column - 1, # Our ranges are exclusive, Istanbul's are inclusive
18
+ },
17
19
  }
18
20
  end
19
21
 
20
22
  # [:a, :b, :c] => {'1': :a, '2': :b, '3': :c}
21
23
  def convert_list(list)
22
- list.map.with_index{ |val, i| [i.succ.to_s, val] }.to_h
24
+ list.map.with_index { |val, i| [i.succ.to_s, val] }.to_h
23
25
  end
24
26
 
25
27
  def convert_def(node)
@@ -31,7 +33,7 @@ module DeepCover
31
33
  def convert_block(node)
32
34
  decl = node.loc_hash[:begin]
33
35
  if (args = node.args.expression)
34
- decl = decl.join(args) rescue binding.pry
36
+ decl = decl.join(args)
35
37
  end
36
38
  _convert_function(node, '(block)', decl)
37
39
  end
@@ -50,11 +52,12 @@ module DeepCover
50
52
  loc: convert_range(node.expression),
51
53
  type: node.type,
52
54
  line: node.expression.line,
53
- locations: branches.map{|n| convert_range(n.expression || node.expression)}
55
+ locations: branches.map { |n| convert_range(n.expression || node.expression) },
54
56
  }
55
57
  end
56
58
 
57
59
  private
60
+
58
61
  def _convert_function(node, name, decl)
59
62
  loc = node.body ? node.body.expression : decl.end
60
63
  {
@@ -95,15 +98,15 @@ module DeepCover
95
98
 
96
99
  # Istanbul doesn't understand how to ignore a branch...
97
100
  def zero_to_something(values)
98
- values.map{|v| v || 1}
101
+ values.map { |v| v || 1 }
99
102
  end
100
103
 
101
104
  def branch_runs
102
- branches.values.map{|r| zero_to_something(r.values) }
105
+ branches.values.map { |r| zero_to_something(r.values) }
103
106
  end
104
107
 
105
108
  def statement_map
106
- statements.keys.map{ |range| convert_range(range) }
109
+ statements.keys.map { |range| convert_range(range) }
107
110
  end
108
111
 
109
112
  def statement_runs
@@ -111,7 +114,7 @@ module DeepCover
111
114
  end
112
115
 
113
116
  def function_map
114
- functions.keys.map{|n| convert_function(n) }
117
+ functions.keys.map { |n| convert_function(n) }
115
118
  end
116
119
 
117
120
  def function_runs
@@ -120,20 +123,21 @@ module DeepCover
120
123
 
121
124
  def data
122
125
  {
123
- statementMap: statement_map ,
126
+ statementMap: statement_map,
124
127
  s: statement_runs,
125
- fnMap: function_map ,
126
- f: function_runs ,
127
- branchMap: branch_map ,
128
- b: branch_runs ,
128
+ fnMap: function_map,
129
+ f: function_runs,
130
+ branchMap: branch_map,
131
+ b: branch_runs,
129
132
  }
130
133
  end
131
134
 
132
135
  def convert
133
- { covered_code.name => {
134
- path: covered_code.path,
135
- **data.transform_values{|l| convert_list(l)},
136
- } }
136
+ {covered_code.name => {
137
+ path: covered_code.path,
138
+ **data.transform_values { |l| convert_list(l) },
139
+ },
140
+ }
137
141
  end
138
142
 
139
143
  def report
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  Tools = Module.new
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Tools::BuiltinCoverage
3
5
  require 'coverage'
@@ -6,7 +8,7 @@ module DeepCover
6
8
  fn = File.absolute_path(File.expand_path(fn))
7
9
  ::Coverage.start
8
10
  Tools.silence_warnings do
9
- execute_sample ->{ run_with_line_coverage(source, fn, lineno)}
11
+ execute_sample -> { run_with_line_coverage(source, fn, lineno) }
10
12
  end
11
13
  unshift_coverage(::Coverage.result.fetch(fn), lineno)
12
14
  end
@@ -14,7 +16,7 @@ module DeepCover
14
16
  if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
15
17
  # Executes the source as if it was in the specified file while
16
18
  # builtin coverage information is still captured
17
- def run_with_line_coverage(source, fn=nil, lineno=1)
19
+ def run_with_line_coverage(source, fn = nil, lineno = 1)
18
20
  source = shift_source(source, lineno)
19
21
  Object.to_java.getRuntime.executeScript(source, fn)
20
22
  end
@@ -31,7 +33,7 @@ module DeepCover
31
33
 
32
34
  # Executes the source as if it was in the specified file while
33
35
  # builtin coverage information is still captured
34
- def run_with_line_coverage(source, fn=nil, lineno=1)
36
+ def run_with_line_coverage(source, fn = nil, lineno = 1)
35
37
  source = shift_source(source, lineno)
36
38
  RubyVM::InstructionSequence.compile(source, fn).eval
37
39
  end
@@ -44,7 +46,7 @@ module DeepCover
44
46
  end
45
47
 
46
48
  def unshift_coverage(coverage, lineno)
47
- coverage[(lineno-1)..-1]
49
+ coverage[(lineno - 1)..-1]
48
50
  end
49
51
  end
50
52
  end