dry-container 0.7.0 → 0.9.0
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/CHANGELOG.md +76 -27
- data/LICENSE +1 -1
- data/README.md +20 -14
- data/dry-container.gemspec +35 -22
- data/lib/dry/container/error.rb +2 -0
- data/lib/dry/container/item/callable.rb +3 -8
- data/lib/dry/container/item/factory.rb +4 -2
- data/lib/dry/container/item/memoizable.rb +5 -5
- data/lib/dry/container/item.rb +23 -0
- data/lib/dry/container/mixin.rb +44 -17
- data/lib/dry/container/namespace.rb +2 -0
- data/lib/dry/container/namespace_dsl.rb +3 -1
- data/lib/dry/container/registry.rb +3 -1
- data/lib/dry/container/resolver.rb +13 -3
- data/lib/dry/container/stub.rb +3 -1
- data/lib/dry/container/version.rb +3 -1
- data/lib/dry/container.rb +10 -8
- data/lib/dry-container.rb +3 -1
- metadata +30 -45
- data/.codeclimate.yml +0 -32
- data/.gitignore +0 -9
- data/.rspec +0 -2
- data/.rubocop.yml +0 -24
- data/.rubocop_todo.yml +0 -6
- data/.travis.yml +0 -27
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -19
- data/Rakefile +0 -12
- data/rakelib/rubocop.rake +0 -18
- data/spec/integration/container_spec.rb +0 -18
- data/spec/integration/mixin_spec.rb +0 -32
- data/spec/spec_helper.rb +0 -102
- data/spec/support/shared_examples/container.rb +0 -577
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a2d2d74bfa80e0afcee1e54dd79e10a7c21548e0c634c99c2c7af17d97f34166
|
|
4
|
+
data.tar.gz: 62b18ac8bd11c5b56b8637fa4a0bc90da69f61ac84a1b02d01e6b0739d2f166c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b0f906601ede92930ad8c12621a5f68ea1ce6a8ce1e126c967632e51b4e79b8d20d49b682d273b6ca32ebdcd87d8201c3edcae007504ef74b5ac888dd4da0cb1
|
|
7
|
+
data.tar.gz: 92fff5321a53a6e44644f82b56f1cf53a890c6c3b2ab4158bbb2caedbbd0538040165c650cb490e9d204bf585cf7121b61a8361cf895b588989b9e547cece0a4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,24 +1,59 @@
|
|
|
1
|
-
|
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.9.0 2021-09-12
|
|
4
4
|
|
|
5
|
-
* [BREAKING] Now only Ruby 2.3 and above is supported ([flash-gordon](https://github.com/flash-gordon))
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
### Changed
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
* Stubbing keys not present in container will raise an error ([flash-gordon](https://github.com/flash-gordon))
|
|
8
|
+
- [internal] Upgraded to new `setting` API provided in dry-configurable 0.13.0 (@timriley in #77)
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
[Compare v0.8.0...v0.9.0](https://github.com/dry-rb/dry-container/compare/v0.8.0...v0.9.0)
|
|
11
|
+
|
|
12
|
+
## 0.8.0 2021-06-06
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- [BREAKING] Support for 2.4 and 2.5 was dropped
|
|
18
|
+
|
|
19
|
+
[Compare v0.7.2...v0.8.0](https://github.com/dry-rb/dry-container/compare/v0.7.2...v0.8.0)
|
|
20
|
+
|
|
21
|
+
## 0.7.2 2019-07-09
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- `.resolve` accepts an optional fallback block, similar to how `Hash#fetch` works ([flash-gordon](https://github.com/flash-gordon))
|
|
27
|
+
```ruby
|
|
28
|
+
container.resolve('missing_key') { :fallback } # => :fallback
|
|
13
29
|
```
|
|
14
|
-
|
|
30
|
+
- `.decorate` can (again) work with static values. Also, it can take a block instead of `with` ([flash-gordon](https://github.com/flash-gordon))
|
|
31
|
+
```ruby
|
|
32
|
+
container.register('key', 'value')
|
|
33
|
+
container.decorate('key') { |v| "<'#{v}'>" }
|
|
34
|
+
container.resolve('key') # => "<'value'>"
|
|
15
35
|
```
|
|
16
|
-
Be sure you register dependencies before using them. The new behavior will likely save quite a bit of time when debugging ill-configured container setups.
|
|
17
36
|
|
|
18
|
-
## Added
|
|
19
37
|
|
|
20
|
-
|
|
21
|
-
|
|
38
|
+
[Compare v0.7.1...v0.7.2](https://github.com/dry-rb/dry-container/compare/v0.7.1...v0.7.2)
|
|
39
|
+
|
|
40
|
+
## 0.7.1 2019-06-07
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- Added `Mixin#dup` and `Mixin#clone`, now copies don't share underlying containers (flash-gordon)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
[Compare v0.7.0...v0.7.1](https://github.com/dry-rb/dry-container/compare/v0.7.0...v0.7.1)
|
|
49
|
+
|
|
50
|
+
## 0.7.0 2019-02-05
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- Namespace DSL resolves keys relative to the current namespace, see the corresponding [changes](https://github.com/dry-rb/dry-container/pull/47) ([yuszuv](https://github.com/yuszuv))
|
|
56
|
+
- Registered objects can be decorated with the following API ([igor-alexandrov](https://github.com/igor-alexandrov))
|
|
22
57
|
|
|
23
58
|
```ruby
|
|
24
59
|
class CreateUser
|
|
@@ -34,34 +69,48 @@
|
|
|
34
69
|
container.resolve('create_user')
|
|
35
70
|
# => #<ShinyLogger @obj=#<CreateUser:0x...>]>
|
|
36
71
|
```
|
|
37
|
-
|
|
72
|
+
- Freezing a container now prevents further registrations ([flash-gordon](https://github.com/flash-gordon))
|
|
73
|
+
- ## Internal
|
|
74
|
+
- Handling container items was generalized in [#34](https://github.com/dry-rb/dry-container/pull/34) ([GabrielMalakias](https://github.com/GabrielMalakias))
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- Symbols are now coerced to strings when resolving stubbed dependencies ([cthulhu666](https://github.com/cthulhu666))
|
|
79
|
+
- Stubbing keys not present in container will raise an error ([flash-gordon](https://github.com/flash-gordon))
|
|
80
|
+
|
|
81
|
+
This means after upgrading you may see errors like this
|
|
82
|
+
```
|
|
83
|
+
ArgumentError (cannot stub "something" - no such key in container)
|
|
84
|
+
```
|
|
85
|
+
Be sure you register dependencies before using them. The new behavior will likely save quite a bit of time when debugging ill-configured container setups.
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
|
|
89
|
+
- [BREAKING] Now only Ruby 2.3 and above is supported ([flash-gordon](https://github.com/flash-gordon))
|
|
38
90
|
|
|
39
|
-
|
|
91
|
+
[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-container/compare/v0.6.0...v0.7.0)
|
|
40
92
|
|
|
41
|
-
|
|
93
|
+
## 0.6.0 2016-12-09
|
|
42
94
|
|
|
43
|
-
[Compare v0.6.0...HEAD](https://github.com/dry-rb/dry-container/compare/v0.6.0...v0.7.0)
|
|
44
95
|
|
|
45
|
-
|
|
96
|
+
### Added
|
|
46
97
|
|
|
47
|
-
|
|
98
|
+
- `Dry::Container::Mixin#each` - provides a means of seeing what all is registered in the container ([jeremyf](https://github.com/jeremyf))
|
|
48
99
|
|
|
49
|
-
|
|
100
|
+
### Fixed
|
|
50
101
|
|
|
51
|
-
|
|
102
|
+
- Including mixin into a class with a custom initializer ([maltoe](https://github.com/maltoe))
|
|
52
103
|
|
|
53
|
-
* Including mixin into a class with a custom initializer ([maltoe](https://github.com/maltoe))
|
|
54
104
|
|
|
55
105
|
[Compare v0.5.0...v0.6.0](https://github.com/dry-rb/dry-container/compare/v0.5.0...v0.6.0)
|
|
56
106
|
|
|
57
|
-
##
|
|
107
|
+
## 0.5.0 2016-08-31
|
|
58
108
|
|
|
59
|
-
## Added
|
|
60
109
|
|
|
61
|
-
|
|
110
|
+
### Added
|
|
62
111
|
|
|
63
|
-
|
|
112
|
+
- `memoize` option to `#register` - memoizes items on first resolve ([ivoanjo](https://github.com/ivoanjo))
|
|
64
113
|
|
|
65
|
-
|
|
114
|
+
### Fixed
|
|
66
115
|
|
|
67
|
-
|
|
116
|
+
- `required_ruby_version` set to `>= 2.0.0` ([artofhuman](https://github.com/artofhuman))
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
<!--- this file is synced from dry-rb/template-gem project -->
|
|
2
2
|
[gem]: https://rubygems.org/gems/dry-container
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
6
|
-
[
|
|
3
|
+
[actions]: https://github.com/dry-rb/dry-container/actions
|
|
4
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-container
|
|
5
|
+
[chat]: https://dry-rb.zulipchat.com
|
|
6
|
+
[inchpages]: http://inch-ci.org/github/dry-rb/dry-container
|
|
7
7
|
|
|
8
|
-
# dry-container [][chat]
|
|
9
9
|
|
|
10
|
-
[][gem]
|
|
11
|
+
[][actions]
|
|
12
|
+
[][codacy]
|
|
13
|
+
[][codacy]
|
|
14
|
+
[][inchpages]
|
|
17
15
|
|
|
18
16
|
## Links
|
|
19
17
|
|
|
20
|
-
[
|
|
18
|
+
* [User documentation](https://dry-rb.org/gems/dry-container)
|
|
19
|
+
* [API documentation](http://rubydoc.info/gems/dry-container)
|
|
20
|
+
|
|
21
|
+
## Supported Ruby versions
|
|
22
|
+
|
|
23
|
+
This library officially supports the following Ruby versions:
|
|
24
|
+
|
|
25
|
+
* MRI `>= 2.6.0`
|
|
26
|
+
* ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
|
|
21
27
|
|
|
22
28
|
## License
|
|
23
29
|
|
data/dry-container.gemspec
CHANGED
|
@@ -1,25 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# this file is synced from dry-rb/template-gem project
|
|
4
|
+
|
|
5
|
+
lib = File.expand_path("lib", __dir__)
|
|
6
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
7
|
+
require "dry/container/version"
|
|
2
8
|
|
|
3
9
|
Gem::Specification.new do |spec|
|
|
4
|
-
spec.name =
|
|
5
|
-
spec.
|
|
6
|
-
spec.
|
|
7
|
-
spec.
|
|
8
|
-
spec.
|
|
9
|
-
|
|
10
|
-
spec.
|
|
11
|
-
|
|
12
|
-
spec.
|
|
13
|
-
spec.
|
|
14
|
-
spec.
|
|
15
|
-
spec.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
spec.
|
|
20
|
-
spec.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
spec.
|
|
24
|
-
|
|
10
|
+
spec.name = "dry-container"
|
|
11
|
+
spec.authors = ["Andy Holland"]
|
|
12
|
+
spec.email = ["andyholland1991@aol.com"]
|
|
13
|
+
spec.license = "MIT"
|
|
14
|
+
spec.version = Dry::Container::VERSION.dup
|
|
15
|
+
|
|
16
|
+
spec.summary = "A simple, configurable object container implemented in Ruby"
|
|
17
|
+
spec.description = spec.summary
|
|
18
|
+
spec.homepage = "https://dry-rb.org/gems/dry-container"
|
|
19
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-container.gemspec", "lib/**/*"]
|
|
20
|
+
spec.bindir = "bin"
|
|
21
|
+
spec.executables = []
|
|
22
|
+
spec.require_paths = ["lib"]
|
|
23
|
+
|
|
24
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
25
|
+
spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-container/blob/master/CHANGELOG.md"
|
|
26
|
+
spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-container"
|
|
27
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-container/issues"
|
|
28
|
+
|
|
29
|
+
spec.required_ruby_version = ">= 2.6.0"
|
|
30
|
+
|
|
31
|
+
# to update dependencies edit project.yml
|
|
32
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
|
33
|
+
spec.add_runtime_dependency "dry-configurable", "~> 0.13", ">= 0.13.0"
|
|
34
|
+
|
|
35
|
+
spec.add_development_dependency "bundler"
|
|
36
|
+
spec.add_development_dependency "rake"
|
|
37
|
+
spec.add_development_dependency "rspec"
|
|
25
38
|
end
|
data/lib/dry/container/error.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/container/item"
|
|
2
4
|
|
|
3
5
|
module Dry
|
|
4
6
|
class Container
|
|
@@ -14,13 +16,6 @@ module Dry
|
|
|
14
16
|
def call
|
|
15
17
|
callable? ? item.call : item
|
|
16
18
|
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
# @private
|
|
21
|
-
def callable?
|
|
22
|
-
options[:call]
|
|
23
|
-
end
|
|
24
19
|
end
|
|
25
20
|
end
|
|
26
21
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry/container/item"
|
|
2
4
|
|
|
3
5
|
module Dry
|
|
4
6
|
class Container
|
|
@@ -21,7 +23,7 @@ module Dry
|
|
|
21
23
|
# @return [Dry::Container::Item::Base]
|
|
22
24
|
def initialize(item, options = {})
|
|
23
25
|
super
|
|
24
|
-
raise_not_supported_error unless
|
|
26
|
+
raise_not_supported_error unless callable?
|
|
25
27
|
|
|
26
28
|
@memoize_mutex = ::Mutex.new
|
|
27
29
|
end
|
|
@@ -39,11 +41,9 @@ module Dry
|
|
|
39
41
|
|
|
40
42
|
# @private
|
|
41
43
|
def raise_not_supported_error
|
|
42
|
-
raise ::Dry::Container::Error,
|
|
44
|
+
raise ::Dry::Container::Error, "Memoize only supported for a block or a proc".freeze
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
|
-
|
|
49
|
-
|
data/lib/dry/container/item.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Dry
|
|
2
4
|
class Container
|
|
3
5
|
# Base class to abstract Memoizable and Callable implementations
|
|
@@ -23,6 +25,27 @@ module Dry
|
|
|
23
25
|
def call
|
|
24
26
|
raise NotImplementedError
|
|
25
27
|
end
|
|
28
|
+
|
|
29
|
+
# @private
|
|
30
|
+
def value?
|
|
31
|
+
!callable?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @private
|
|
35
|
+
def callable?
|
|
36
|
+
options[:call]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Build a new item with transformation applied
|
|
40
|
+
#
|
|
41
|
+
# @private
|
|
42
|
+
def map(func)
|
|
43
|
+
if callable?
|
|
44
|
+
self.class.new(-> { func.(item.call) }, options)
|
|
45
|
+
else
|
|
46
|
+
self.class.new(func.(item), options)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
26
49
|
end
|
|
27
50
|
end
|
|
28
51
|
end
|
data/lib/dry/container/mixin.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
|
-
require
|
|
3
|
+
require "concurrent/hash"
|
|
3
4
|
|
|
4
5
|
module Dry
|
|
5
6
|
class Container
|
|
6
7
|
PREFIX_NAMESPACE = lambda do |namespace, key, config|
|
|
7
8
|
[namespace, key].join(config.namespace_separator)
|
|
8
9
|
end
|
|
10
|
+
|
|
11
|
+
EMPTY_HASH = {}.freeze
|
|
12
|
+
|
|
9
13
|
# Mixin to expose Inversion of Control (IoC) container behaviour
|
|
10
14
|
#
|
|
11
15
|
# @example
|
|
@@ -43,9 +47,9 @@ module Dry
|
|
|
43
47
|
extend ::Dry::Configurable
|
|
44
48
|
extend hooks_mod
|
|
45
49
|
|
|
46
|
-
setting :registry,
|
|
47
|
-
setting :resolver,
|
|
48
|
-
setting :namespace_separator,
|
|
50
|
+
setting :registry, default: Dry::Container::Registry.new
|
|
51
|
+
setting :resolver, default: Dry::Container::Resolver.new
|
|
52
|
+
setting :namespace_separator, default: "."
|
|
49
53
|
|
|
50
54
|
@_container = ::Concurrent::Hash.new
|
|
51
55
|
end
|
|
@@ -65,9 +69,9 @@ module Dry
|
|
|
65
69
|
extend ::Dry::Configurable
|
|
66
70
|
prepend Initializer
|
|
67
71
|
|
|
68
|
-
setting :registry,
|
|
69
|
-
setting :resolver,
|
|
70
|
-
setting :namespace_separator,
|
|
72
|
+
setting :registry, default: Dry::Container::Registry.new
|
|
73
|
+
setting :resolver, default: Dry::Container::Resolver.new
|
|
74
|
+
setting :namespace_separator, default: "."
|
|
71
75
|
|
|
72
76
|
def config
|
|
73
77
|
self.class.config
|
|
@@ -90,7 +94,7 @@ module Dry
|
|
|
90
94
|
# @return [Dry::Container::Mixin] self
|
|
91
95
|
#
|
|
92
96
|
# @api public
|
|
93
|
-
def register(key, contents = nil, options =
|
|
97
|
+
def register(key, contents = nil, options = EMPTY_HASH, &block)
|
|
94
98
|
if block_given?
|
|
95
99
|
item = block
|
|
96
100
|
options = contents if contents.is_a?(::Hash)
|
|
@@ -107,12 +111,15 @@ module Dry
|
|
|
107
111
|
#
|
|
108
112
|
# @param [Mixed] key
|
|
109
113
|
# The key for the item you wish to resolve
|
|
114
|
+
# @yield
|
|
115
|
+
# Fallback block to call when a key is missing. Its result will be returned
|
|
116
|
+
# @yieldparam [Mixed] key Missing key
|
|
110
117
|
#
|
|
111
118
|
# @return [Mixed]
|
|
112
119
|
#
|
|
113
120
|
# @api public
|
|
114
|
-
def resolve(key)
|
|
115
|
-
config.resolver.call(_container, key)
|
|
121
|
+
def resolve(key, &block)
|
|
122
|
+
config.resolver.call(_container, key, &block)
|
|
116
123
|
end
|
|
117
124
|
|
|
118
125
|
# Resolve an item from the container
|
|
@@ -205,18 +212,22 @@ module Dry
|
|
|
205
212
|
# @return [Dry::Container::Mixin] self
|
|
206
213
|
#
|
|
207
214
|
# @api public
|
|
208
|
-
def decorate(key, with:)
|
|
209
|
-
|
|
215
|
+
def decorate(key, with: nil, &block)
|
|
216
|
+
key = key.to_s
|
|
217
|
+
original = _container.delete(key) do
|
|
210
218
|
raise Error, "Nothing registered with the key #{key.inspect}"
|
|
211
219
|
end
|
|
212
220
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
221
|
+
if with.is_a?(Class)
|
|
222
|
+
decorator = with.method(:new)
|
|
223
|
+
elsif block.nil? && !with.respond_to?(:call)
|
|
224
|
+
raise Error, "Decorator needs to be a Class, block, or respond to the `call` method"
|
|
217
225
|
else
|
|
218
|
-
|
|
226
|
+
decorator = with || block
|
|
219
227
|
end
|
|
228
|
+
|
|
229
|
+
_container[key] = original.map(decorator)
|
|
230
|
+
self
|
|
220
231
|
end
|
|
221
232
|
|
|
222
233
|
# Evaluate block and register items in namespace
|
|
@@ -265,6 +276,22 @@ module Dry
|
|
|
265
276
|
def _container
|
|
266
277
|
@_container
|
|
267
278
|
end
|
|
279
|
+
|
|
280
|
+
# @api public
|
|
281
|
+
def dup
|
|
282
|
+
copy = super
|
|
283
|
+
copy.instance_variable_set(:@_container, _container.dup)
|
|
284
|
+
copy
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# @api public
|
|
288
|
+
def clone
|
|
289
|
+
copy = super
|
|
290
|
+
unless copy.frozen?
|
|
291
|
+
copy.instance_variable_set(:@_container, _container.dup)
|
|
292
|
+
end
|
|
293
|
+
copy
|
|
294
|
+
end
|
|
268
295
|
end
|
|
269
296
|
end
|
|
270
297
|
end
|