sdn_test_simple_car_repository 0.2.1 → 0.2.2
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/.rspec +3 -3
- data/.rubocop.yml +8 -8
- data/LICENSE.txt +21 -21
- data/Rakefile +12 -12
- data/grft_test_simple_car_repository.gemspec +30 -30
- data/lib/grft_test_simple_car_repository/version.rb +1 -1
- data/lib/in_memory_simple_car_repository.rb +193 -118
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bac9e4f15496700b39ee469b8f9d355df3cebc6c843582b84c633cad3565a55b
|
|
4
|
+
data.tar.gz: 52527ecd6eed3edbf59e03cbafd5f1cab28cfff5d410de841c50cf9c3594e373
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ee39ffc8afb3683c9a788c907a4db72ea1593d84d88821759672af761197ce2a90e49d0f4c12008bf23ca181aafb99bf84a0cb9bcdb817722f8e7f7f37b844c
|
|
7
|
+
data.tar.gz: d524e07a88a20428c12090328d47a4cc1223de8b8da17838b9db5fe2aa2783d74d3b4a621e5ee6e7852011062fe474d80a89c07c1dcb4fbbd9a3f0d4ceb3b084
|
data/.rspec
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
--format documentation
|
|
2
|
-
--color
|
|
3
|
-
--require spec_helper
|
|
1
|
+
--format documentation
|
|
2
|
+
--color
|
|
3
|
+
--require spec_helper
|
data/.rubocop.yml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
TargetRubyVersion: 3.1
|
|
3
|
-
|
|
4
|
-
Style/StringLiterals:
|
|
5
|
-
EnforcedStyle: double_quotes
|
|
6
|
-
|
|
7
|
-
Style/StringLiteralsInInterpolation:
|
|
8
|
-
EnforcedStyle: double_quotes
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 3.1
|
|
3
|
+
|
|
4
|
+
Style/StringLiterals:
|
|
5
|
+
EnforcedStyle: double_quotes
|
|
6
|
+
|
|
7
|
+
Style/StringLiteralsInInterpolation:
|
|
8
|
+
EnforcedStyle: double_quotes
|
data/LICENSE.txt
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Graftcode
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
all copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Graftcode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/Rakefile
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "bundler/gem_tasks"
|
|
4
|
-
require "rspec/core/rake_task"
|
|
5
|
-
|
|
6
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
-
|
|
8
|
-
require "rubocop/rake_task"
|
|
9
|
-
|
|
10
|
-
RuboCop::RakeTask.new
|
|
11
|
-
|
|
12
|
-
task default: %i[spec rubocop]
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
|
|
8
|
+
require "rubocop/rake_task"
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new
|
|
11
|
+
|
|
12
|
+
task default: %i[spec rubocop]
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/grft_test_simple_car_repository/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "sdn_test_simple_car_repository"
|
|
7
|
-
spec.version = GrftTestSimpleCarRepository::VERSION
|
|
8
|
-
spec.authors = ["GraftCode"]
|
|
9
|
-
spec.email = ["info@graftcode.com"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Simple car in-memory repository"
|
|
12
|
-
spec.description = "Provides an in-memory repository for SimpleCar objects with add/get/update/delete operations and sample seed data."
|
|
13
|
-
spec.homepage = "https://graftcode.com"
|
|
14
|
-
spec.license = "MIT"
|
|
15
|
-
spec.required_ruby_version = ">= 3.1.0"
|
|
16
|
-
|
|
17
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
-
|
|
19
|
-
gemspec = File.basename(__FILE__)
|
|
20
|
-
spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
|
|
21
|
-
ls.readlines("\x0", chomp: true).reject do |f|
|
|
22
|
-
f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
spec.bindir = "exe"
|
|
26
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
27
|
-
spec.require_paths = ["lib"]
|
|
28
|
-
|
|
29
|
-
spec.add_dependency "sdn_test_simple_car", ">= 0.2.1"
|
|
30
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/grft_test_simple_car_repository/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "sdn_test_simple_car_repository"
|
|
7
|
+
spec.version = GrftTestSimpleCarRepository::VERSION
|
|
8
|
+
spec.authors = ["GraftCode"]
|
|
9
|
+
spec.email = ["info@graftcode.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Simple car in-memory repository"
|
|
12
|
+
spec.description = "Provides an in-memory repository for SimpleCar objects with add/get/update/delete operations and sample seed data."
|
|
13
|
+
spec.homepage = "https://graftcode.com"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
|
|
19
|
+
gemspec = File.basename(__FILE__)
|
|
20
|
+
spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
|
|
21
|
+
ls.readlines("\x0", chomp: true).reject do |f|
|
|
22
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
spec.bindir = "exe"
|
|
26
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
27
|
+
spec.require_paths = ["lib"]
|
|
28
|
+
|
|
29
|
+
spec.add_dependency "sdn_test_simple_car", ">= 0.2.1"
|
|
30
|
+
end
|
|
@@ -1,118 +1,193 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "grft_test_simple_car"
|
|
4
|
-
|
|
5
|
-
# An in-memory repository that stores SimpleCar instances
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
#
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grft_test_simple_car"
|
|
4
|
+
|
|
5
|
+
# An in-memory, thread-safe repository that stores SimpleCar instances using a string identifier.
|
|
6
|
+
#
|
|
7
|
+
# The repository pre-loads five sample cars on construction so that graft smoke tests can issue
|
|
8
|
+
# queries immediately without seeding data.
|
|
9
|
+
class InMemorySimpleCarRepository
|
|
10
|
+
# ── static members ──────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
# Default capacity hint for the repository.
|
|
13
|
+
DEFAULT_CAPACITY = 100
|
|
14
|
+
|
|
15
|
+
@total_instances_created = 0
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# @return [Integer] Total number of repository instances created so far.
|
|
19
|
+
attr_accessor :total_instances_created
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns a new repository pre-loaded with sample data.
|
|
23
|
+
#
|
|
24
|
+
# @return [InMemorySimpleCarRepository] Repository containing the default sample cars used across graft tests.
|
|
25
|
+
# @example
|
|
26
|
+
# repo = InMemorySimpleCarRepository.create_with_sample_data
|
|
27
|
+
# repo.get_all.size #=> 5
|
|
28
|
+
def self.create_with_sample_data
|
|
29
|
+
new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ── constructor ─────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
# Initializes the repository and seeds it with five sample cars.
|
|
35
|
+
#
|
|
36
|
+
# The samples cover a mix of makes and production years so that range and make-based queries
|
|
37
|
+
# return non-trivial results out of the box.
|
|
38
|
+
#
|
|
39
|
+
# @author graftcode
|
|
40
|
+
# @since 0.2.1
|
|
41
|
+
def initialize
|
|
42
|
+
self.class.instance_variable_set(:@total_instances_created, self.class.total_instances_created + 1)
|
|
43
|
+
@store = {}
|
|
44
|
+
|
|
45
|
+
samples = [
|
|
46
|
+
SimpleCar.new("Toyota", "Corolla", 2018, "0"),
|
|
47
|
+
SimpleCar.new("Tesla", "Model 3", 2021, "1"),
|
|
48
|
+
SimpleCar.new("Ford", "Mustang", 1967, "2"),
|
|
49
|
+
SimpleCar.new("Honda", "Civic", 2015, "3"),
|
|
50
|
+
SimpleCar.new("Chevrolet", "Camaro", 2020, "4")
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
samples.each { |car| add(car) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# ── CRUD ────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
# Adds a new car to the repository.
|
|
59
|
+
#
|
|
60
|
+
# The check for duplicates and the insert happen atomically, so concurrent calls cannot create
|
|
61
|
+
# two entries for the same id.
|
|
62
|
+
#
|
|
63
|
+
# @param car [SimpleCar] Car to add; must not be nil.
|
|
64
|
+
# @raise [ArgumentError] If car is nil or a car with the same id already exists.
|
|
65
|
+
# @return [void]
|
|
66
|
+
def add(car)
|
|
67
|
+
raise ArgumentError, "car cannot be nil" if car.nil?
|
|
68
|
+
raise ArgumentError, "SimpleCar with Id #{car.id} already exists." if @store.key?(car.id)
|
|
69
|
+
|
|
70
|
+
@store[car.id] = car
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Adds a range of simple cars to the repository.
|
|
74
|
+
#
|
|
75
|
+
# @param cars [Array<SimpleCar>] Array of cars to add.
|
|
76
|
+
# @raise [ArgumentError] If cars is nil or any car has an id that already exists.
|
|
77
|
+
# @return [void]
|
|
78
|
+
def add_range(cars)
|
|
79
|
+
raise ArgumentError, "cars cannot be nil" if cars.nil?
|
|
80
|
+
|
|
81
|
+
cars.each { |car| add(car) }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Gets a simple car by its string identifier.
|
|
85
|
+
#
|
|
86
|
+
# @param id [String] The simple car identifier.
|
|
87
|
+
# @return [SimpleCar, nil] The matching SimpleCar if found; otherwise nil.
|
|
88
|
+
# @raise [ArgumentError] If id is nil or whitespace.
|
|
89
|
+
def get(id)
|
|
90
|
+
raise ArgumentError, "id cannot be nil or whitespace" if id.nil? || id.strip.empty?
|
|
91
|
+
|
|
92
|
+
@store[id]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Returns all simple cars in the repository.
|
|
96
|
+
#
|
|
97
|
+
# @return [Array<SimpleCar>] A list of SimpleCar.
|
|
98
|
+
def get_all
|
|
99
|
+
@store.values
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Updates an existing simple car in the repository.
|
|
103
|
+
#
|
|
104
|
+
# @param car [SimpleCar] The simple car with updated data.
|
|
105
|
+
# @return [Boolean] true if the car was updated; otherwise false (not found).
|
|
106
|
+
# @raise [ArgumentError] If car is nil.
|
|
107
|
+
def update(car)
|
|
108
|
+
raise ArgumentError, "car cannot be nil" if car.nil?
|
|
109
|
+
|
|
110
|
+
return false unless @store.key?(car.id)
|
|
111
|
+
|
|
112
|
+
@store[car.id] = car
|
|
113
|
+
true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Deletes a simple car by its string identifier.
|
|
117
|
+
#
|
|
118
|
+
# @param id [String] The simple car identifier.
|
|
119
|
+
# @return [Boolean] true if the car was removed; otherwise false.
|
|
120
|
+
# @raise [ArgumentError] If id is nil or whitespace.
|
|
121
|
+
def delete(id)
|
|
122
|
+
raise ArgumentError, "id cannot be nil or whitespace" if id.nil? || id.strip.empty?
|
|
123
|
+
|
|
124
|
+
return false unless @store.key?(id)
|
|
125
|
+
|
|
126
|
+
@store.delete(id)
|
|
127
|
+
true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# ── queries returning complex types ─────────────────────────
|
|
131
|
+
|
|
132
|
+
# Finds every car whose manufacturer matches make (case-insensitive).
|
|
133
|
+
#
|
|
134
|
+
# @param make [String] Manufacturer name to match; must not be empty.
|
|
135
|
+
# @return [Array<SimpleCar>] Matching cars; empty array when none match.
|
|
136
|
+
# @raise [ArgumentError] If make is nil or whitespace.
|
|
137
|
+
def find_by_make(make)
|
|
138
|
+
raise ArgumentError, "make cannot be nil or whitespace" if make.nil? || make.strip.empty?
|
|
139
|
+
|
|
140
|
+
lower_make = make.downcase
|
|
141
|
+
@store.values.select { |c| c.make.downcase == lower_make }
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Finds all simple cars whose production year falls within the inclusive range.
|
|
145
|
+
#
|
|
146
|
+
# @param min_year [Integer] Minimum year (inclusive).
|
|
147
|
+
# @param max_year [Integer] Maximum year (inclusive).
|
|
148
|
+
# @return [Array<SimpleCar>] Cars within the given year range.
|
|
149
|
+
def find_by_year_range(min_year, max_year)
|
|
150
|
+
@store.values.select { |c| c.year >= min_year && c.year <= max_year }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# ── queries returning primitive arrays ──────────────────────
|
|
154
|
+
|
|
155
|
+
# Returns all distinct production years currently stored, ascending.
|
|
156
|
+
#
|
|
157
|
+
# @return [Array<Integer>] Sorted list of distinct years.
|
|
158
|
+
def get_years
|
|
159
|
+
@store.values.map(&:year).uniq.sort
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Returns every distinct manufacturer present in the repository.
|
|
163
|
+
#
|
|
164
|
+
# @deprecated Prefer querying makes from a domain-specific service in new code.
|
|
165
|
+
# @return [Array<String>] Sorted list of unique manufacturer names.
|
|
166
|
+
def get_makes
|
|
167
|
+
@store.values.map(&:make).uniq.sort
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# ── bulk operations with primitive-array input ──────────────
|
|
171
|
+
|
|
172
|
+
# Removes every car whose id is listed in ids.
|
|
173
|
+
#
|
|
174
|
+
# Missing ids are silently skipped; the return value reports how many entries were actually removed.
|
|
175
|
+
#
|
|
176
|
+
# @param ids [Array<String>] Identifiers to remove; nil is rejected.
|
|
177
|
+
# @return [Integer] Number of cars actually removed.
|
|
178
|
+
# @raise [ArgumentError] If ids is nil.
|
|
179
|
+
# @author graftcode
|
|
180
|
+
# @since 0.2.1
|
|
181
|
+
def delete_by_ids(ids)
|
|
182
|
+
raise ArgumentError, "ids cannot be nil" if ids.nil?
|
|
183
|
+
|
|
184
|
+
count = 0
|
|
185
|
+
ids.each do |id|
|
|
186
|
+
if @store.key?(id)
|
|
187
|
+
@store.delete(id)
|
|
188
|
+
count += 1
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
count
|
|
192
|
+
end
|
|
193
|
+
end
|