rubocop 0.70.0 → 0.72.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -10
  3. data/config/default.yml +50 -491
  4. data/lib/rubocop.rb +5 -53
  5. data/lib/rubocop/ast/builder.rb +2 -0
  6. data/lib/rubocop/ast/node.rb +1 -1
  7. data/lib/rubocop/ast/node/float_node.rb +12 -0
  8. data/lib/rubocop/ast/node/int_node.rb +12 -0
  9. data/lib/rubocop/ast/node/mixin/numeric_node.rb +21 -0
  10. data/lib/rubocop/ast/node/resbody_node.rb +1 -6
  11. data/lib/rubocop/cached_data.rb +1 -1
  12. data/lib/rubocop/config.rb +35 -6
  13. data/lib/rubocop/config_loader.rb +2 -2
  14. data/lib/rubocop/config_loader_resolver.rb +0 -6
  15. data/lib/rubocop/cop/cop.rb +0 -4
  16. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +55 -0
  17. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  18. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +3 -1
  19. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -0
  20. data/lib/rubocop/cop/layout/indent_first_argument.rb +6 -2
  21. data/lib/rubocop/cop/layout/indent_first_parameter.rb +7 -3
  22. data/lib/rubocop/cop/layout/indent_heredoc.rb +0 -1
  23. data/lib/rubocop/cop/layout/indentation_consistency.rb +13 -12
  24. data/lib/rubocop/cop/layout/indentation_width.rb +8 -4
  25. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +2 -0
  26. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  27. data/lib/rubocop/cop/mixin/hash_alignment.rb +4 -0
  28. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +20 -22
  29. data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
  30. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -1
  31. data/lib/rubocop/cop/style/float_division.rb +94 -0
  32. data/lib/rubocop/cop/style/format_string.rb +7 -3
  33. data/lib/rubocop/cop/style/if_inside_else.rb +42 -0
  34. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -1
  35. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  36. data/lib/rubocop/cop/style/ternary_parentheses.rb +12 -2
  37. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -0
  38. data/lib/rubocop/cop/style/word_array.rb +2 -2
  39. data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
  40. data/lib/rubocop/node_pattern.rb +84 -5
  41. data/lib/rubocop/options.rb +0 -2
  42. data/lib/rubocop/processed_source.rb +5 -1
  43. data/lib/rubocop/rspec/cop_helper.rb +0 -1
  44. data/lib/rubocop/rspec/shared_contexts.rb +0 -17
  45. data/lib/rubocop/rspec/support.rb +0 -1
  46. data/lib/rubocop/runner.rb +6 -7
  47. data/lib/rubocop/version.rb +1 -1
  48. data/lib/rubocop/yaml_duplication_checker.rb +8 -2
  49. metadata +7 -69
  50. data/lib/rubocop/cop/mixin/target_rails_version.rb +0 -16
  51. data/lib/rubocop/cop/rails/action_filter.rb +0 -117
  52. data/lib/rubocop/cop/rails/active_record_aliases.rb +0 -48
  53. data/lib/rubocop/cop/rails/active_record_override.rb +0 -82
  54. data/lib/rubocop/cop/rails/active_support_aliases.rb +0 -69
  55. data/lib/rubocop/cop/rails/application_job.rb +0 -40
  56. data/lib/rubocop/cop/rails/application_record.rb +0 -40
  57. data/lib/rubocop/cop/rails/assert_not.rb +0 -44
  58. data/lib/rubocop/cop/rails/belongs_to.rb +0 -102
  59. data/lib/rubocop/cop/rails/blank.rb +0 -164
  60. data/lib/rubocop/cop/rails/bulk_change_table.rb +0 -289
  61. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +0 -91
  62. data/lib/rubocop/cop/rails/date.rb +0 -161
  63. data/lib/rubocop/cop/rails/delegate.rb +0 -132
  64. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +0 -37
  65. data/lib/rubocop/cop/rails/dynamic_find_by.rb +0 -91
  66. data/lib/rubocop/cop/rails/enum_uniqueness.rb +0 -45
  67. data/lib/rubocop/cop/rails/environment_comparison.rb +0 -68
  68. data/lib/rubocop/cop/rails/exit.rb +0 -67
  69. data/lib/rubocop/cop/rails/file_path.rb +0 -108
  70. data/lib/rubocop/cop/rails/find_by.rb +0 -55
  71. data/lib/rubocop/cop/rails/find_each.rb +0 -51
  72. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +0 -25
  73. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +0 -106
  74. data/lib/rubocop/cop/rails/http_positional_arguments.rb +0 -117
  75. data/lib/rubocop/cop/rails/http_status.rb +0 -179
  76. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +0 -94
  77. data/lib/rubocop/cop/rails/inverse_of.rb +0 -246
  78. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +0 -175
  79. data/lib/rubocop/cop/rails/link_to_blank.rb +0 -98
  80. data/lib/rubocop/cop/rails/not_null_column.rb +0 -67
  81. data/lib/rubocop/cop/rails/output.rb +0 -49
  82. data/lib/rubocop/cop/rails/output_safety.rb +0 -99
  83. data/lib/rubocop/cop/rails/pluralization_grammar.rb +0 -107
  84. data/lib/rubocop/cop/rails/presence.rb +0 -124
  85. data/lib/rubocop/cop/rails/present.rb +0 -153
  86. data/lib/rubocop/cop/rails/read_write_attribute.rb +0 -74
  87. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +0 -111
  88. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +0 -136
  89. data/lib/rubocop/cop/rails/reflection_class_name.rb +0 -37
  90. data/lib/rubocop/cop/rails/refute_methods.rb +0 -76
  91. data/lib/rubocop/cop/rails/relative_date_constant.rb +0 -93
  92. data/lib/rubocop/cop/rails/request_referer.rb +0 -56
  93. data/lib/rubocop/cop/rails/reversible_migration.rb +0 -286
  94. data/lib/rubocop/cop/rails/safe_navigation.rb +0 -87
  95. data/lib/rubocop/cop/rails/save_bang.rb +0 -316
  96. data/lib/rubocop/cop/rails/scope_args.rb +0 -29
  97. data/lib/rubocop/cop/rails/skips_model_validations.rb +0 -87
  98. data/lib/rubocop/cop/rails/time_zone.rb +0 -238
  99. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +0 -105
  100. data/lib/rubocop/cop/rails/unknown_env.rb +0 -63
  101. data/lib/rubocop/cop/rails/validation.rb +0 -109
  102. data/lib/rubocop/rspec/shared_examples.rb +0 -59
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # Checks for overriding built-in Active Record methods instead of using
7
- # callbacks.
8
- #
9
- # @example
10
- # # bad
11
- # class Book < ApplicationRecord
12
- # def save
13
- # self.title = title.upcase!
14
- # super
15
- # end
16
- # end
17
- #
18
- # # good
19
- # class Book < ApplicationRecord
20
- # before_save :upcase_title
21
- #
22
- # def upcase_title
23
- # self.title = title.upcase!
24
- # end
25
- # end
26
- #
27
- class ActiveRecordOverride < Cop
28
- MSG =
29
- 'Use %<prefer>s callbacks instead of overriding the Active Record ' \
30
- 'method `%<bad>s`.'
31
- BAD_METHODS = %i[create destroy save update].freeze
32
- ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base
33
- ActiveRecord::Base].freeze
34
-
35
- def on_def(node)
36
- return unless BAD_METHODS.include?(node.method_name)
37
-
38
- parent_class_name = find_parent_class_name(node)
39
- return unless active_model?(parent_class_name)
40
-
41
- return unless node.descendants.any?(&:zsuper_type?)
42
-
43
- add_offense(node, message: message(node.method_name))
44
- end
45
-
46
- private
47
-
48
- def active_model?(parent_class_name)
49
- ACTIVE_RECORD_CLASSES.include?(parent_class_name)
50
- end
51
-
52
- def callback_names(method_name)
53
- names = %w[before_ around_ after_].map do |prefix|
54
- "`#{prefix}#{method_name}`"
55
- end
56
-
57
- names[-1] = "or #{names.last}"
58
-
59
- names.join(', ')
60
- end
61
-
62
- def message(method_name)
63
- format(MSG, prefer: callback_names(method_name), bad: method_name)
64
- end
65
-
66
- def find_parent_class_name(node)
67
- return nil unless node
68
-
69
- if node.class_type?
70
- parent_class_name = node.node_parts[1]
71
-
72
- return nil if parent_class_name.nil?
73
-
74
- return parent_class_name.source
75
- end
76
-
77
- find_parent_class_name(node.parent)
78
- end
79
- end
80
- end
81
- end
82
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop checks that ActiveSupport aliases to core ruby methods
7
- # are not used.
8
- #
9
- # @example
10
- # # good
11
- # 'some_string'.start_with?('prefix')
12
- # 'some_string'.end_with?('suffix')
13
- # [1, 2, 'a'] << 'b'
14
- # [1, 2, 'a'].unshift('b')
15
- #
16
- # # bad
17
- # 'some_string'.starts_with?('prefix')
18
- # 'some_string'.ends_with?('suffix')
19
- # [1, 2, 'a'].append('b')
20
- # [1, 2, 'a'].prepend('b')
21
- #
22
- class ActiveSupportAliases < Cop
23
- MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
24
-
25
- ALIASES = {
26
- starts_with?: {
27
- original: :start_with?, matcher: '(send str :starts_with? _)'
28
- },
29
- ends_with?: {
30
- original: :end_with?, matcher: '(send str :ends_with? _)'
31
- },
32
- append: { original: :<<, matcher: '(send array :append _)' },
33
- prepend: { original: :unshift, matcher: '(send array :prepend _)' }
34
- }.freeze
35
-
36
- ALIASES.each do |aliased_method, options|
37
- def_node_matcher aliased_method, options[:matcher]
38
- end
39
-
40
- def on_send(node)
41
- ALIASES.each_key do |aliased_method|
42
- register_offense(node, aliased_method) if
43
- public_send(aliased_method, node)
44
- end
45
- end
46
-
47
- def autocorrect(node)
48
- return false if append(node)
49
-
50
- lambda do |corrector|
51
- method_name = node.loc.selector.source
52
- replacement = ALIASES[method_name.to_sym][:original]
53
- corrector.replace(node.loc.selector, replacement.to_s)
54
- end
55
- end
56
-
57
- private
58
-
59
- def register_offense(node, method_name)
60
- add_offense(
61
- node,
62
- message: format(MSG, prefer: ALIASES[method_name][:original],
63
- current: method_name)
64
- )
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop checks that jobs subclass ApplicationJob with Rails 5.0.
7
- #
8
- # @example
9
- #
10
- # # good
11
- # class Rails5Job < ApplicationJob
12
- # # ...
13
- # end
14
- #
15
- # # bad
16
- # class Rails4Job < ActiveJob::Base
17
- # # ...
18
- # end
19
- class ApplicationJob < Cop
20
- extend TargetRailsVersion
21
-
22
- minimum_target_rails_version 5.0
23
-
24
- MSG = 'Jobs should subclass `ApplicationJob`.'
25
- SUPERCLASS = 'ApplicationJob'
26
- BASE_PATTERN = '(const (const nil? :ActiveJob) :Base)'
27
-
28
- # rubocop:disable Layout/ClassStructure
29
- include RuboCop::Cop::EnforceSuperclass
30
- # rubocop:enable Layout/ClassStructure
31
-
32
- def autocorrect(node)
33
- lambda do |corrector|
34
- corrector.replace(node.source_range, self.class::SUPERCLASS)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop checks that models subclass ApplicationRecord with Rails 5.0.
7
- #
8
- # @example
9
- #
10
- # # good
11
- # class Rails5Model < ApplicationRecord
12
- # # ...
13
- # end
14
- #
15
- # # bad
16
- # class Rails4Model < ActiveRecord::Base
17
- # # ...
18
- # end
19
- class ApplicationRecord < Cop
20
- extend TargetRailsVersion
21
-
22
- minimum_target_rails_version 5.0
23
-
24
- MSG = 'Models should subclass `ApplicationRecord`.'
25
- SUPERCLASS = 'ApplicationRecord'
26
- BASE_PATTERN = '(const (const nil? :ActiveRecord) :Base)'
27
-
28
- # rubocop:disable Layout/ClassStructure
29
- include RuboCop::Cop::EnforceSuperclass
30
- # rubocop:enable Layout/ClassStructure
31
-
32
- def autocorrect(node)
33
- lambda do |corrector|
34
- corrector.replace(node.source_range, self.class::SUPERCLASS)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- #
7
- # Use `assert_not` instead of `assert !`.
8
- #
9
- # @example
10
- # # bad
11
- # assert !x
12
- #
13
- # # good
14
- # assert_not x
15
- #
16
- class AssertNot < RuboCop::Cop::Cop
17
- MSG = 'Prefer `assert_not` over `assert !`.'
18
-
19
- def_node_matcher :offensive?, '(send nil? :assert (send ... :!) ...)'
20
-
21
- def on_send(node)
22
- add_offense(node) if offensive?(node)
23
- end
24
-
25
- def autocorrect(node)
26
- expression = node.loc.expression
27
-
28
- lambda do |corrector|
29
- corrector.replace(
30
- expression,
31
- corrected_source(expression.source)
32
- )
33
- end
34
- end
35
-
36
- private
37
-
38
- def corrected_source(source)
39
- source.gsub(/^assert(\(| ) *! */, 'assert_not\\1')
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop looks for belongs_to associations where we control whether the
7
- # association is required via the deprecated `required` option instead.
8
- #
9
- # Since Rails 5, belongs_to associations are required by default and this
10
- # can be controlled through the use of `optional: true`.
11
- #
12
- # From the release notes:
13
- #
14
- # belongs_to will now trigger a validation error by default if the
15
- # association is not present. You can turn this off on a
16
- # per-association basis with optional: true. Also deprecate required
17
- # option in favor of optional for belongs_to. (Pull Request)
18
- #
19
- # In the case that the developer is doing `required: false`, we
20
- # definitely want to autocorrect to `optional: true`.
21
- #
22
- # However, without knowing whether they've set overridden the default
23
- # value of `config.active_record.belongs_to_required_by_default`, we
24
- # can't say whether it's safe to remove `required: true` or whether we
25
- # should replace it with `optional: false` (or, similarly, remove a
26
- # superfluous `optional: false`). Therefore, in the cases we're using
27
- # `required: true`, we'll simply invert it to `optional: false` and the
28
- # user can remove depending on their defaults.
29
- #
30
- # @example
31
- # # bad
32
- # class Post < ApplicationRecord
33
- # belongs_to :blog, required: false
34
- # end
35
- #
36
- # # good
37
- # class Post < ApplicationRecord
38
- # belongs_to :blog, optional: true
39
- # end
40
- #
41
- # # bad
42
- # class Post < ApplicationRecord
43
- # belongs_to :blog, required: true
44
- # end
45
- #
46
- # # good
47
- # class Post < ApplicationRecord
48
- # belongs_to :blog, optional: false
49
- # end
50
- #
51
- # @see https://guides.rubyonrails.org/5_0_release_notes.html
52
- # @see https://github.com/rails/rails/pull/18937
53
- class BelongsTo < Cop
54
- extend TargetRailsVersion
55
-
56
- minimum_target_rails_version 5.0
57
-
58
- SUPERFLOUS_REQUIRE_FALSE_MSG =
59
- 'You specified `required: false`, in Rails > 5.0 the required ' \
60
- 'option is deprecated and you want to use `optional: true`.'
61
-
62
- SUPERFLOUS_REQUIRE_TRUE_MSG =
63
- 'You specified `required: true`, in Rails > 5.0 the required ' \
64
- 'option is deprecated and you want to use `optional: false`. ' \
65
- 'In most configurations, this is the default and you can omit ' \
66
- 'this option altogether'
67
-
68
- def_node_matcher :match_belongs_to_with_options, <<-PATTERN
69
- (send _ :belongs_to _
70
- (hash <$(pair (sym :required) ${true false}) ...>)
71
- )
72
- PATTERN
73
-
74
- def on_send(node)
75
- match_belongs_to_with_options(node) do |_option_node, option_value|
76
- message =
77
- if option_value.true_type?
78
- SUPERFLOUS_REQUIRE_TRUE_MSG
79
- elsif option_value.false_type?
80
- SUPERFLOUS_REQUIRE_FALSE_MSG
81
- end
82
-
83
- add_offense(node, message: message, location: :selector)
84
- end
85
- end
86
-
87
- def autocorrect(node)
88
- option_node, option_value = match_belongs_to_with_options(node)
89
- return unless option_node
90
-
91
- lambda do |corrector|
92
- if option_value.true_type?
93
- corrector.replace(option_node.loc.expression, 'optional: false')
94
- elsif option_value.false_type?
95
- corrector.replace(option_node.loc.expression, 'optional: true')
96
- end
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,164 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Rails
6
- # This cop checks for code that can be written with simpler conditionals
7
- # using `Object#blank?` defined by Active Support.
8
- #
9
- # Interaction with `Style/UnlessElse`:
10
- # The configuration of `NotPresent` will not produce an offense in the
11
- # context of `unless else` if `Style/UnlessElse` is inabled. This is
12
- # to prevent interference between the auto-correction of the two cops.
13
- #
14
- # @example NilOrEmpty: true (default)
15
- # # Converts usages of `nil? || empty?` to `blank?`
16
- #
17
- # # bad
18
- # foo.nil? || foo.empty?
19
- # foo == nil || foo.empty?
20
- #
21
- # # good
22
- # foo.blank?
23
- #
24
- # @example NotPresent: true (default)
25
- # # Converts usages of `!present?` to `blank?`
26
- #
27
- # # bad
28
- # !foo.present?
29
- #
30
- # # good
31
- # foo.blank?
32
- #
33
- # @example UnlessPresent: true (default)
34
- # # Converts usages of `unless present?` to `if blank?`
35
- #
36
- # # bad
37
- # something unless foo.present?
38
- #
39
- # # good
40
- # something if foo.blank?
41
- #
42
- # # bad
43
- # unless foo.present?
44
- # something
45
- # end
46
- #
47
- # # good
48
- # if foo.blank?
49
- # something
50
- # end
51
- #
52
- # # good
53
- # def blank?
54
- # !present?
55
- # end
56
- class Blank < Cop
57
- MSG_NIL_OR_EMPTY = 'Use `%<prefer>s` instead of `%<current>s`.'
58
- MSG_NOT_PRESENT = 'Use `%<prefer>s` instead of `%<current>s`.'
59
- MSG_UNLESS_PRESENT = 'Use `if %<prefer>s` instead of ' \
60
- '`%<current>s`.'
61
-
62
- # `(send nil $_)` is not actually a valid match for an offense. Nodes
63
- # that have a single method call on the left hand side
64
- # (`bar || foo.empty?`) will blow up when checking
65
- # `(send (:nil) :== $_)`.
66
- def_node_matcher :nil_or_empty?, <<-PATTERN
67
- (or
68
- {
69
- (send $_ :!)
70
- (send $_ :nil?)
71
- (send $_ :== nil)
72
- (send nil :== $_)
73
- }
74
- {
75
- (send $_ :empty?)
76
- (send (send (send $_ :empty?) :!) :!)
77
- }
78
- )
79
- PATTERN
80
-
81
- def_node_matcher :not_present?, '(send (send $_ :present?) :!)'
82
-
83
- def_node_matcher :defining_blank?, '(def :blank? (args) ...)'
84
-
85
- def_node_matcher :unless_present?, <<-PATTERN
86
- (:if $(send $_ :present?) {nil? (...)} ...)
87
- PATTERN
88
-
89
- def on_send(node)
90
- return unless cop_config['NotPresent']
91
-
92
- not_present?(node) do |receiver|
93
- # accepts !present? if its in the body of a `blank?` method
94
- next if defining_blank?(node.parent)
95
-
96
- add_offense(node,
97
- message: format(MSG_NOT_PRESENT,
98
- prefer: replacement(receiver),
99
- current: node.source))
100
- end
101
- end
102
-
103
- def on_or(node)
104
- return unless cop_config['NilOrEmpty']
105
-
106
- nil_or_empty?(node) do |var1, var2|
107
- return unless var1 == var2
108
-
109
- add_offense(node,
110
- message: format(MSG_NIL_OR_EMPTY,
111
- prefer: replacement(var1),
112
- current: node.source))
113
- end
114
- end
115
-
116
- def on_if(node)
117
- return unless cop_config['UnlessPresent']
118
- return unless node.unless?
119
- return if node.else? && config.for_cop('Style/UnlessElse')['Enabled']
120
-
121
- unless_present?(node) do |method_call, receiver|
122
- range = unless_condition(node, method_call)
123
-
124
- add_offense(node,
125
- location: range,
126
- message: format(MSG_UNLESS_PRESENT,
127
- prefer: replacement(receiver),
128
- current: range.source))
129
- end
130
- end
131
-
132
- def autocorrect(node)
133
- lambda do |corrector|
134
- method_call, variable1 = unless_present?(node)
135
-
136
- if method_call
137
- corrector.replace(node.loc.keyword, 'if')
138
- range = method_call.loc.expression
139
- else
140
- variable1, _variable2 = nil_or_empty?(node) || not_present?(node)
141
- range = node.loc.expression
142
- end
143
-
144
- corrector.replace(range, replacement(variable1))
145
- end
146
- end
147
-
148
- private
149
-
150
- def unless_condition(node, method_call)
151
- if node.modifier_form?
152
- node.loc.keyword.join(node.loc.expression.end)
153
- else
154
- node.loc.expression.begin.join(method_call.loc.expression)
155
- end
156
- end
157
-
158
- def replacement(node)
159
- node.respond_to?(:source) ? "#{node.source}.blank?" : 'blank?'
160
- end
161
- end
162
- end
163
- end
164
- end