darthjee-core_ext 1.7.3 → 1.7.4
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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +19 -8
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +7 -3
- data/Dockerfile +9 -0
- data/README.md +5 -6
- data/Rakefile +2 -0
- data/config/yardstick.rb +13 -0
- data/config/yardstick.yml +35 -0
- data/core_ext.gemspec +9 -7
- data/docker-compose.yml +3 -6
- data/lib/darthjee/core_ext/array.rb +2 -2
- data/lib/darthjee/core_ext/class.rb +90 -4
- data/lib/darthjee/core_ext/enumerable.rb +5 -1
- data/lib/darthjee/core_ext/hash.rb +30 -0
- data/lib/darthjee/core_ext/hash/cameliazable.rb +91 -0
- data/lib/darthjee/core_ext/hash/chain_fetcher.rb +10 -0
- data/lib/darthjee/core_ext/hash/key_changeable.rb +85 -53
- data/lib/darthjee/core_ext/hash/key_changer.rb +41 -31
- data/lib/darthjee/core_ext/hash/value_changer.rb +128 -11
- data/lib/darthjee/core_ext/version.rb +1 -1
- data/spec/integration/yard/{array → darthjee/core_ext/array}/hash_builder_spec.rb +3 -3
- data/spec/integration/yard/{array_spec.rb → darthjee/core_ext/array_spec.rb} +0 -0
- data/spec/integration/yard/darthjee/core_ext/class/default_value_spec.rb +143 -0
- data/spec/integration/yard/{date → darthjee/core_ext/date}/days_between_spec.rb +6 -6
- data/spec/integration/yard/{enumerable_spec.rb → darthjee/core_ext/enumerable_spec.rb} +0 -0
- data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +34 -0
- data/spec/integration/yard/darthjee/core_ext/hash/chain_fetcher_spec.rb +51 -0
- data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +48 -0
- data/spec/integration/yard/{hash → darthjee/core_ext/hash}/transformable_spec.rb +7 -3
- data/spec/integration/yard/darthjee/core_ext/hash/value_changer_spec.rb +66 -0
- data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +42 -0
- data/spec/lib/array_spec.rb +27 -17
- data/spec/lib/class_spec.rb +108 -7
- data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +1 -1
- data/spec/lib/darthjee/core_ext/hash/key_changer_spec.rb +8 -8
- data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +1 -0
- data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +1 -0
- data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +246 -0
- data/spec/lib/date_spec.rb +5 -4
- data/spec/lib/hash_spec.rb +45 -32
- data/spec/lib/math_spec.rb +1 -0
- data/spec/lib/numeric_spec.rb +39 -17
- data/spec/lib/object_spec.rb +7 -7
- data/spec/lib/symbol_spec.rb +2 -2
- data/spec/lib/time_spec.rb +5 -4
- data/spec/support/models/default_reader_model.rb +8 -0
- data/spec/support/models/default_value_model.rb +2 -0
- data/spec/support/models/dummy_iterator.rb +15 -0
- data/spec/support/models/dummy_transformer.rb +15 -0
- data/spec/support/shared_examples/array/array_random.rb +2 -1
- data/spec/support/shared_examples/clean.rb +20 -20
- data/spec/support/shared_examples/date.rb +18 -13
- data/spec/support/shared_examples/hash/chain_fetch.rb +4 -3
- data/spec/support/shared_examples/hash/chain_hash_keys_changer.rb +14 -7
- data/spec/support/shared_examples/hash/hash_keys_changer.rb +10 -4
- data/spec/support/shared_examples/hash/hash_transpose.rb +1 -1
- data/spec/support/shared_examples/hash/keys_appender.rb +14 -4
- data/spec/support/shared_examples/hash/keys_camelizer.rb +7 -7
- data/spec/support/shared_examples/hash/keys_sorter.rb +3 -3
- data/spec/support/shared_examples/hash/keys_underscorer.rb +2 -2
- data/spec/support/shared_examples/hash/map_to_hash.rb +14 -12
- data/spec/support/shared_examples/hash/remap.rb +4 -4
- data/spec/support/shared_examples/hash/value_changer.rb +40 -33
- metadata +70 -20
- data/spec/integration/yard/class/default_value_spec.rb +0 -58
@@ -3,6 +3,11 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# Class responsible for running ::Hash#chain_fetch
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
#
|
10
|
+
# @see Darthjee::CoreExt::Hash#chain_fetch
|
6
11
|
class ChainFetcher
|
7
12
|
def initialize(hash, *keys, &block)
|
8
13
|
@hash = hash
|
@@ -10,6 +15,11 @@ module Darthjee
|
|
10
15
|
@block = block
|
11
16
|
end
|
12
17
|
|
18
|
+
# Crawls through the hash fetching the keys in chain
|
19
|
+
#
|
20
|
+
# @example (see Darthjee::CoreExt::Hash#chain_fetch)
|
21
|
+
#
|
22
|
+
# @return [Object] value fetched from array
|
13
23
|
def fetch
|
14
24
|
block.present? ? fetch_with_block : fetch_without_block
|
15
25
|
end
|
@@ -3,73 +3,85 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# Module holding methods responsible for
|
7
|
+
# changing / transforming keys of a Hash
|
8
|
+
#
|
9
|
+
# @api public
|
6
10
|
module KeyChangeable
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
camelize_keys!(options)
|
23
|
-
end
|
24
|
-
|
25
|
-
def camelize_keys(options = {})
|
26
|
-
dup.camelize_keys!(options)
|
27
|
-
end
|
28
|
-
|
29
|
-
def camelize_keys!(options = {})
|
30
|
-
Hash::KeyChanger.new(self).camelize_keys(options)
|
11
|
+
# Change all keys by publically sending methods to the keys without
|
12
|
+
# changing the original hash
|
13
|
+
#
|
14
|
+
# @return [::Hash] New hash with the resulting keys
|
15
|
+
# @param [::Array<Symbol>] calls methods to be called form the key`
|
16
|
+
#
|
17
|
+
# @see #change_keys
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# hash = { first: 1, second: 2 }
|
21
|
+
# resut = hash.chain_change_keys(:to_s, :size, :to_s, :to_sym)
|
22
|
+
# result # returns { :'5' => 1, :'6' => 2 }
|
23
|
+
def chain_change_keys(*calls)
|
24
|
+
deep_dup.chain_change_keys!(*calls)
|
31
25
|
end
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
# Change all keys by publically sending methods to the keys
|
28
|
+
# changing the original hash
|
29
|
+
#
|
30
|
+
# @return [::Hash] New hash with the resulting keys
|
31
|
+
# @param [::Array<Symbol>] calls methods to be called form the key`
|
32
|
+
#
|
33
|
+
# @see #chain_change_keys
|
34
|
+
#
|
35
|
+
# @example (see #chain_change_keys)
|
36
|
+
def chain_change_keys!(*calls)
|
37
|
+
options = calls.extract_options!
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
calls.inject(self) do |h, m|
|
40
|
+
h.change_keys!(options, &m)
|
41
|
+
end
|
39
42
|
end
|
40
43
|
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
+
# Change all keys returning the new hash
|
45
|
+
#
|
46
|
+
# @return new Hash with modified keys
|
47
|
+
# @param [::Hash] options options to passed to KeyChanger
|
48
|
+
# @option options [Boolean] recursive: flag defining the
|
49
|
+
# change to happen also
|
50
|
+
# on inner hashes (defaults to: true)
|
51
|
+
#
|
52
|
+
# @see Hash::KeyChanger#change_keys
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# hash = { '1' => 1, '2' => { '3' => 2} }
|
56
|
+
#
|
57
|
+
# result = hash.change_keys do |k|
|
58
|
+
# (k.to_i + 1).to_s.to_sym
|
59
|
+
# end
|
60
|
+
# result # returns { :'2' => 1, :'3' => { :'4' => 2 } }
|
61
|
+
#
|
62
|
+
# result = hash.change_keys(recursive:false) do |k|
|
63
|
+
# (k.to_i + 1).to_s.to_sym
|
64
|
+
# end
|
65
|
+
# result # returns { :'2' => 1, :'3' => { '3' => 2 } }
|
44
66
|
def change_keys(options = {}, &block)
|
45
67
|
deep_dup.change_keys!(options, &block)
|
46
68
|
end
|
47
69
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
70
|
+
# Change all keys modifying and returning the hash
|
71
|
+
#
|
72
|
+
# @return self
|
73
|
+
# @param [::Hash] options options to passed to KeyChanger
|
74
|
+
# @option options [Boolean] recursive: flag defining the
|
75
|
+
# change to happen also
|
76
|
+
# on inner hashes (defaults to: true)
|
77
|
+
#
|
78
|
+
# @see Hash::KeyChanger#change_keys
|
79
|
+
#
|
80
|
+
# @example (see #change_keys)
|
51
81
|
def change_keys!(options = {}, &block)
|
52
82
|
Hash::KeyChanger.new(self).change_keys(options, &block)
|
53
83
|
end
|
54
84
|
|
55
|
-
# change all publicaly sending method calls
|
56
|
-
# options: { recursive: true }
|
57
|
-
# ex: { a: 1 }.chain_change_keys(:to_s, :upcase) == { "A" =>1 }
|
58
|
-
def chain_change_keys(*calls)
|
59
|
-
deep_dup.chain_change_keys!(*calls)
|
60
|
-
end
|
61
|
-
|
62
|
-
# change all publicaly sending method calls
|
63
|
-
# options: { recursive: true }
|
64
|
-
# ex: { a: 1 }.chain_change_keys(:to_s, :upcase) == { "A" =>1 }
|
65
|
-
def chain_change_keys!(*calls)
|
66
|
-
options = calls.extract_options!
|
67
|
-
|
68
|
-
calls.inject(self) do |h, m|
|
69
|
-
h.change_keys!(options, &m)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
85
|
# prepend a string to all keys
|
74
86
|
# options {
|
75
87
|
# recursive: true,
|
@@ -125,6 +137,26 @@ module Darthjee
|
|
125
137
|
Hash::ValueChanger.new(options, &block).change(self)
|
126
138
|
end
|
127
139
|
|
140
|
+
# Changes the key of the hash without changing it
|
141
|
+
#
|
142
|
+
# @return [::Hash] new hash
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# hash = { a: 1, b: 2 }
|
146
|
+
# hash.remap_keys(a: :b, b: :c) # returns { b: 1, c: 2 }
|
147
|
+
def remap_keys(remap)
|
148
|
+
dup.remap_keys!(remap)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Changes the key of the hash changing the original
|
152
|
+
#
|
153
|
+
# @return [::Hash] self
|
154
|
+
#
|
155
|
+
# @example (see #remap_keys)
|
156
|
+
def remap_keys!(keys_map)
|
157
|
+
KeyChanger.new(self).remap(keys_map)
|
158
|
+
end
|
159
|
+
|
128
160
|
private
|
129
161
|
|
130
162
|
# changes the text of the keys
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# @api private
|
6
7
|
class KeyChanger
|
7
8
|
def initialize(hash)
|
8
9
|
@hash = hash
|
@@ -16,10 +17,20 @@ module Darthjee
|
|
16
17
|
hash.merge! new_hash
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# Change the keys of the given hash returning the new hash
|
21
|
+
#
|
22
|
+
# @return New hash after keys tranformation
|
23
|
+
#
|
24
|
+
# @param [::Hash] options options for transformation
|
25
|
+
# @option options [Boolean] recursive: flag defining
|
26
|
+
# the change to happen also
|
27
|
+
# on inner hashes (defaults to: true)
|
28
|
+
#
|
29
|
+
# @example (see Hash#change_keys)
|
30
|
+
def change_keys(options = {}, &block)
|
31
|
+
options = {
|
32
|
+
recursive: true
|
33
|
+
}.merge!(options)
|
23
34
|
|
24
35
|
if options[:recursive]
|
25
36
|
hash.deep_transform_keys!(&block)
|
@@ -28,31 +39,37 @@ module Darthjee
|
|
28
39
|
end
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
42
|
+
# Performs camelization of the keys of the hash
|
43
|
+
#
|
44
|
+
# @return [::Hash] the given hash with it's keys changed
|
45
|
+
# @param [::Hash] options options
|
46
|
+
# @option options [::Boolean] uppercase_first_letter: flag
|
47
|
+
# defining the type of CamelCase
|
48
|
+
#
|
49
|
+
# @example (see Hash#camelize_keys)
|
50
|
+
def camelize_keys(options = {})
|
51
|
+
options = {
|
52
|
+
uppercase_first_letter: true
|
53
|
+
}.merge!(options)
|
35
54
|
|
36
55
|
type = options[:uppercase_first_letter] ? :upper : :lower
|
37
56
|
|
38
|
-
change_keys do |k|
|
57
|
+
change_keys(options) do |k|
|
39
58
|
k.camelize(type)
|
40
59
|
end
|
41
60
|
end
|
42
61
|
|
43
|
-
def underscore_keys(
|
44
|
-
|
45
|
-
|
46
|
-
change_keys(&:underscore)
|
62
|
+
def underscore_keys(options = {})
|
63
|
+
change_keys(options, &:underscore)
|
47
64
|
end
|
48
65
|
|
49
66
|
def change_text(options = {})
|
50
|
-
|
51
|
-
|
52
|
-
|
67
|
+
options = {
|
68
|
+
type: :keep
|
69
|
+
}.merge!(options)
|
53
70
|
|
54
|
-
change_keys do |key|
|
55
|
-
cast_new_key yield(key), key.class
|
71
|
+
change_keys(options) do |key|
|
72
|
+
cast_new_key yield(key), key.class, options
|
56
73
|
end
|
57
74
|
end
|
58
75
|
|
@@ -60,16 +77,8 @@ module Darthjee
|
|
60
77
|
|
61
78
|
attr_reader :hash
|
62
79
|
|
63
|
-
def
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
def options
|
68
|
-
@options ||= {}
|
69
|
-
end
|
70
|
-
|
71
|
-
def cast_new_key(key, old_clazz)
|
72
|
-
case class_cast(old_clazz)
|
80
|
+
def cast_new_key(key, old_clazz, options)
|
81
|
+
case class_cast(old_clazz, options)
|
73
82
|
when :symbol then
|
74
83
|
key.to_sym
|
75
84
|
when :string then
|
@@ -77,12 +86,13 @@ module Darthjee
|
|
77
86
|
end
|
78
87
|
end
|
79
88
|
|
80
|
-
def keep_class?
|
89
|
+
def keep_class?(options)
|
81
90
|
options[:type] == :keep
|
82
91
|
end
|
83
92
|
|
84
|
-
def class_cast(old_clazz)
|
85
|
-
keep_class? && old_clazz.to_s.downcase.to_sym
|
93
|
+
def class_cast(old_clazz, options)
|
94
|
+
klass = keep_class?(options) && old_clazz.to_s.downcase.to_sym
|
95
|
+
klass || options[:type]
|
86
96
|
end
|
87
97
|
end
|
88
98
|
end
|
@@ -3,37 +3,136 @@
|
|
3
3
|
module Darthjee
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
|
+
# Class responsible for changing values on a hash
|
7
|
+
#
|
8
|
+
# @attribute [Boolean] recursive
|
9
|
+
# flag telling to apply transformation recursively
|
10
|
+
# @attribute [Boolean] skip_inner
|
11
|
+
# flag telling to not apply change block call to inner hashes
|
12
|
+
# @attribute [::Proc] block
|
13
|
+
# block to be called when changing the values
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# (see initialize)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# (see #change)
|
6
20
|
class ValueChanger
|
7
|
-
attr_accessor :
|
21
|
+
attr_accessor :recursive, :skip_inner, :block
|
8
22
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
23
|
+
# @param [Boolean] recursive
|
24
|
+
# flag telling to apply transformation recursively
|
25
|
+
# @param [Boolean] skip_inner
|
26
|
+
# flag telling to not apply change block call to inner hashes
|
27
|
+
# @param [::Proc] block
|
28
|
+
# block to be called when changing the values
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new(
|
33
|
+
# recursive: false,
|
34
|
+
# skip_inner: false,
|
35
|
+
# &:class
|
36
|
+
# )
|
37
|
+
#
|
38
|
+
# hash = { a: 1, b: { c: 2 }, d: [{ e: 1 }] }
|
39
|
+
# changer.change(hash) # {
|
40
|
+
# # a: Integer,
|
41
|
+
# # b: Hash,
|
42
|
+
# # d: Array
|
43
|
+
# # }
|
44
|
+
def initialize(recursive: true, skip_inner: true, &block)
|
45
|
+
@recursive = recursive
|
46
|
+
@skip_inner = skip_inner
|
14
47
|
|
15
48
|
@block = block
|
16
49
|
end
|
17
50
|
|
51
|
+
# Change the given object
|
52
|
+
#
|
53
|
+
# @return the resulting object (hash or array)
|
54
|
+
# with it`s values changed
|
55
|
+
# @param [::Hash/::Array] object
|
56
|
+
# object to have it's values changed
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new do |value|
|
60
|
+
# value.to_s.size
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# hash = { a: 15, b: { c: 2 }, d: [{ e: 100 }] }
|
64
|
+
# changer.change(hash) # {
|
65
|
+
# # a: 2,
|
66
|
+
# # b: { c: 1 },
|
67
|
+
# # d: [{ e: 3 }]
|
68
|
+
# # }
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new(
|
72
|
+
# skip_inner: true
|
73
|
+
# ) do |value|
|
74
|
+
# value.to_s.size
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# hash = { a: 15, b: { c: 2 }, d: [{ e: 100 }] }
|
78
|
+
# changer.change(hash) # {
|
79
|
+
# # a: 2,
|
80
|
+
# # b: 11,
|
81
|
+
# # d: 7
|
82
|
+
# # }
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new(
|
86
|
+
# recursive: true
|
87
|
+
# ) do |value|
|
88
|
+
# value.to_s.size
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# hash = { a: 15, b: { c: 2 }, d: [{ e: 100 }] }
|
92
|
+
# changer.change(hash) # {
|
93
|
+
# # a: 2,
|
94
|
+
# # b: { c: 1 },
|
95
|
+
# # d: [{ e: 3 }]
|
96
|
+
# # }
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# changer = Darthjee::CoreExt::Hash::ValueChanger.new do |value|
|
100
|
+
# value.to_s.size
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# array = [15, { c: 2 }, [{ e: 100 }]]
|
104
|
+
#
|
105
|
+
# changer.change(array) # [
|
106
|
+
# # 2,
|
107
|
+
# # { c: 1 },
|
108
|
+
# # [{ e: 3 }]
|
109
|
+
# # ]
|
18
110
|
def change(object)
|
19
111
|
if object.respond_to?(:change_values)
|
20
112
|
change_hash(object)
|
21
113
|
elsif iterable?(object)
|
22
114
|
change_array(object)
|
115
|
+
else
|
116
|
+
object
|
23
117
|
end
|
24
118
|
end
|
25
119
|
|
26
120
|
private
|
27
121
|
|
122
|
+
# Apply change logic to hash object
|
123
|
+
#
|
124
|
+
# @private
|
28
125
|
def change_hash(original_hash)
|
29
126
|
original_hash.tap do |hash|
|
30
127
|
original_hash.each do |key, value|
|
31
|
-
|
32
|
-
hash[key] = value
|
128
|
+
hash[key] = new_value(value)
|
33
129
|
end
|
34
130
|
end
|
35
131
|
end
|
36
132
|
|
133
|
+
# Apply change logic to iterator
|
134
|
+
#
|
135
|
+
# @private
|
37
136
|
def change_array(array)
|
38
137
|
method = %w[map! map].find { |m| array.respond_to? m }
|
39
138
|
|
@@ -48,8 +147,16 @@ module Darthjee
|
|
48
147
|
end
|
49
148
|
end
|
50
149
|
|
150
|
+
# check wehether block should be called over
|
151
|
+
# value or not
|
152
|
+
#
|
153
|
+
# when the block is not iterable (not Array or Hash)
|
154
|
+
# or when skip_inner option is set to be false,
|
155
|
+
# then block should be called
|
156
|
+
#
|
157
|
+
# @private
|
51
158
|
def change_value?(value)
|
52
|
-
!iterable?(value) || !
|
159
|
+
!iterable?(value) || !skip_inner
|
53
160
|
end
|
54
161
|
|
55
162
|
def iterable?(value)
|
@@ -58,11 +165,21 @@ module Darthjee
|
|
58
165
|
|
59
166
|
def new_value(value)
|
60
167
|
value = block.call(value) if change_value?(value)
|
61
|
-
|
168
|
+
|
169
|
+
return value unless apply_recursion?(value)
|
170
|
+
|
171
|
+
change(value)
|
62
172
|
end
|
63
173
|
|
64
174
|
def apply_recursion?(value)
|
65
|
-
iterable?(value) &&
|
175
|
+
iterable?(value) && recursive
|
176
|
+
end
|
177
|
+
|
178
|
+
def options
|
179
|
+
@options ||= {
|
180
|
+
recursive: recursive,
|
181
|
+
skip_inner: skip_inner
|
182
|
+
}
|
66
183
|
end
|
67
184
|
end
|
68
185
|
end
|