iolite 0.0.3 → 2.0.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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. metadata +17 -122
  3. data/.gitignore +0 -24
  4. data/.rspec +0 -2
  5. data/.travis.yml +0 -5
  6. data/Gemfile +0 -4
  7. data/LICENSE.txt +0 -22
  8. data/README.md +0 -88
  9. data/Rakefile +0 -7
  10. data/docs/iolite.md +0 -314
  11. data/docs/release_note.md +0 -15
  12. data/example/array.rb +0 -17
  13. data/example/compare_lambda_driver.rb +0 -78
  14. data/example/fizzbuzz.rb +0 -15
  15. data/example/hash.rb +0 -14
  16. data/example/lazy_list.rb +0 -14
  17. data/example/minimal_implement.rb +0 -42
  18. data/example/simple.rb +0 -46
  19. data/example/to_lazy.rb +0 -37
  20. data/iolite.gemspec +0 -24
  21. data/lib/iolite/adaptor/all.rb +0 -22
  22. data/lib/iolite/adaptor/apply.rb +0 -10
  23. data/lib/iolite/adaptor/bind.rb +0 -9
  24. data/lib/iolite/adaptor/callable.rb +0 -7
  25. data/lib/iolite/adaptor/define_send_original_methods.rb +0 -12
  26. data/lib/iolite/adaptor/method_missing.rb +0 -10
  27. data/lib/iolite/adaptor/operators.rb +0 -26
  28. data/lib/iolite/adaptor/send.rb +0 -11
  29. data/lib/iolite/adaptor/to_lazy.rb +0 -11
  30. data/lib/iolite/adaptor/to_proc.rb +0 -10
  31. data/lib/iolite/adaptor.rb +0 -2
  32. data/lib/iolite/adaptored/array.rb +0 -12
  33. data/lib/iolite/adaptored/hash.rb +0 -14
  34. data/lib/iolite/adaptored/iolite_lazy_with_hash.rb +0 -7
  35. data/lib/iolite/adaptored/object_with_to_lazy.rb +0 -5
  36. data/lib/iolite/adaptored/proc.rb +0 -5
  37. data/lib/iolite/adaptored/proc_with_callable.rb +0 -5
  38. data/lib/iolite/adaptored/string.rb +0 -21
  39. data/lib/iolite/functinal/bind.rb +0 -12
  40. data/lib/iolite/functinal/define_iolite_functinal_send_method.rb +0 -9
  41. data/lib/iolite/functinal/invoke.rb +0 -11
  42. data/lib/iolite/functinal/send.rb +0 -13
  43. data/lib/iolite/functinal.rb +0 -4
  44. data/lib/iolite/lazy.rb +0 -40
  45. data/lib/iolite/placeholders.rb +0 -30
  46. data/lib/iolite/refinements/array.rb +0 -16
  47. data/lib/iolite/refinements/hash.rb +0 -18
  48. data/lib/iolite/refinements/object_with_to_lazy.rb +0 -9
  49. data/lib/iolite/refinements/proc.rb +0 -9
  50. data/lib/iolite/refinements/string.rb +0 -26
  51. data/lib/iolite/refinements.rb +0 -6
  52. data/lib/iolite/statement/if.rb +0 -50
  53. data/lib/iolite/statement/if_else.rb +0 -12
  54. data/lib/iolite/statement.rb +0 -3
  55. data/lib/iolite/version.rb +0 -3
  56. data/lib/iolite.rb +0 -14
  57. data/spec/iolite_adaptored_spec.rb +0 -105
  58. data/spec/iolite_functinal_spec.rb +0 -87
  59. data/spec/iolite_lazy_spec.rb +0 -92
  60. data/spec/iolite_spec.rb +0 -212
  61. data/spec/spec_helper.rb +0 -2
@@ -1,78 +0,0 @@
1
- # Compare lambda_driver and iolite
2
- # lambda_driver : http://yuroyoro.github.io/lambda_driver/
3
- # http://yuroyoro.hatenablog.com/entry/2013/03/27/190640
4
-
5
- require "iolite"
6
- require "lambda_driver"
7
-
8
- include Iolite::Placeholders
9
- using Iolite::Refinements::ObjectWithToLazy
10
-
11
-
12
- ###########################################################
13
- # default
14
- [:foo, :bar, :baz].map{|s| s.to_s }.map{|s| s.upcase }
15
- # or
16
- [:foo, :bar, :baz].map(&:to_s).map(&:upcase)
17
- # => ["FOO", "BAR", "BAZ"]
18
-
19
- # lambda_driver
20
- [:foo, :bar, :baz].map(&:to_s >> :upcase )
21
-
22
- # iolite
23
- [:foo, :bar, :baz].map &arg1.to_s.upcase
24
-
25
-
26
- ###########################################################
27
- # default
28
- [:foo, :hoge, :bar, :fuga].select{|s| s.to_s.length > 3}
29
- # => [:hoge, :fuga]
30
-
31
- # lambda_driver
32
- [:foo, :hoge, :bar, :fuga].select(&:to_s >> :length >> 3._(:<))
33
-
34
- # iolite
35
- [:foo, :hoge, :bar, :fuga].select &arg1.to_s.length > 3
36
-
37
-
38
- ###########################################################
39
- # default
40
- [:foo, :hoge, :bar, :fuga].select{|s| s.to_s.length > 3}
41
- # => [:hoge, :fuga]
42
-
43
- # lambda_driver
44
- [:foo, :hoge, :bar, :fuga].select(&:to_s >> :length >> 3._(:<))
45
-
46
- # iolite
47
- [:foo, :hoge, :bar, :fuga].select &arg1.to_s.length > 3
48
-
49
-
50
- ###########################################################
51
- # default
52
- (1..10).select { |it| it % 2 == 0 }
53
- # => [2, 4, 6, 8, 10]
54
-
55
- # lambda_driver
56
- (1..10).select &(:% * 2) >> (:== * 0)
57
-
58
- # iolite
59
- (1..10).select &arg1 % 2 == 0
60
-
61
-
62
- ###########################################################
63
- def twice n
64
- n + n
65
- end
66
-
67
- # default
68
- puts twice(10).to_s.length
69
-
70
- # lambda_driver
71
- _.twice >> :to_s >> :length >> _.puts < 10
72
-
73
- # iolite
74
- using Iolite::Refinements::ObjectWithToLazy
75
- to_l.puts(to_l.twice(arg1).to_s.length).call(10)
76
-
77
-
78
-
data/example/fizzbuzz.rb DELETED
@@ -1,15 +0,0 @@
1
- require "iolite"
2
-
3
- include Iolite::Placeholders
4
- include Iolite::Statement
5
-
6
- fizzbuzz = if_else(
7
- arg1 % 15 == 0, "FizzBuzz", if_else(
8
- arg1 % 5 == 0, "Buzz", if_else(
9
- arg1 % 3 == 0, "Fizz",
10
- arg1
11
- )))
12
-
13
- p (1..20).map &fizzbuzz
14
-
15
-
data/example/hash.rb DELETED
@@ -1,14 +0,0 @@
1
- require "iolite"
2
-
3
- # Use require
4
- # define Hash#to_proc
5
- require "iolite/adaptored/hash"
6
-
7
- include Iolite::Placeholders
8
-
9
- p ({arg1 => arg2}).to_proc.call(:name, "homu")
10
- # => {:name=>"homu"}
11
-
12
- p ["homu", "mami", "mado"]. map &({ name: arg1 })
13
- # => [{:name=>"homu"}, {:name=>"mami"}, {:name=>"mado"}]
14
-
data/example/lazy_list.rb DELETED
@@ -1,14 +0,0 @@
1
- require "iolite"
2
-
3
- include Iolite::Placeholders
4
-
5
- # Using Object#to_lazy
6
- using Iolite::Refinements::ObjectWithToLazy
7
-
8
- evens = (1..Float::INFINITY).to_lazy # to lazy list
9
- .first(arg1).select(&arg1 % 2 == 0)
10
-
11
- p evens.call(10)
12
- # => [2, 4, 6, 8, 10]
13
- p evens.call(20)
14
- # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
@@ -1,42 +0,0 @@
1
-
2
- # invoke call function
3
- def invoke func, *args
4
- func.respond_to?(:call) ? func.call(*args) : func
5
- end
6
-
7
- class Proc
8
- # send method
9
- def send symbol, *args_
10
- Proc.new { |*args|
11
- self.call(*args).send(symbol, *args_.map{ |it| invoke(it, *args) })
12
- }
13
- end
14
-
15
- # call any method
16
- def method_missing symbol, *args
17
- send(symbol, *args)
18
- end
19
- end
20
-
21
-
22
- # return args[N]
23
- arg1 = Proc.new { |*args| args[0] }
24
- arg2 = Proc.new { |*args| args[1] }
25
-
26
-
27
- # assemble expr
28
- f = arg1 + arg2
29
-
30
- # apply expr
31
- result = f.call(1, 2)
32
- # => 3
33
-
34
- # call
35
- # 1. (arg1 + arg2).call(1, 2)
36
- # 2. arg1.send(:+, arg2).call(1, 2)
37
- # 3. arg1.call(1, 2).send(invoke(:+, 1, 2), invoke(arg2, 1, 2))
38
- # 4. arg1.call(1, 2).send(:+, arg2.call(1, 2))
39
- # 5. [1, 2][0].send(:+, [1, 2][1])
40
- # 6. 1.send(:+, 2)
41
- # 7. 3
42
-
data/example/simple.rb DELETED
@@ -1,46 +0,0 @@
1
- require "iolite"
2
-
3
-
4
- #######################################
5
- # Using block
6
- #######################################
7
-
8
- p (1..5).map { |it| it + 3 }
9
- # => [4, 5, 6, 7, 8]
10
-
11
- p (1..5).inject { |memo, item| memo + item }
12
- # => 15
13
-
14
- p ["homu", "mami", "an"].inject(0) { |memo, item| memo + item.length }
15
- # => 10
16
-
17
- p [{name: :homu}, {name: :mami}].map { |it| it[:name] }
18
- # => [:homu, :mami]
19
-
20
- p [:homu, :mami, :mado].select { |it| it =~ /^m/ }
21
- # => [:mami, :mado]
22
-
23
-
24
- #######################################
25
- # Using iolite
26
- #######################################
27
-
28
- # using arg1, arg2...
29
- include Iolite::Placeholders
30
-
31
- p (1..5).map &arg1 + 3
32
- # => [4, 5, 6, 7, 8]
33
-
34
- p (1..5).inject &arg1 + arg2
35
- # => 15
36
-
37
- p ["homu", "mami", "an"].inject 0, &arg1 + arg2.length
38
- # => 10
39
-
40
- p [{name: :homu}, {name: :mami}].map &arg1[:name]
41
- # => [:homu, :mami]
42
-
43
- p [:homu, :mami, :mado].select &arg1 =~ /^m/
44
- # => [:mami, :mado]
45
-
46
-
data/example/to_lazy.rb DELETED
@@ -1,37 +0,0 @@
1
- require "iolite"
2
-
3
- require "iolite/refinements/object_with_to_lazy"
4
- using Iolite::Refinements::ObjectWithToLazy
5
-
6
- # Using 1.9.x
7
- # require "iolite/adaptored/object_with_to_lazy"
8
-
9
-
10
- include Iolite::Placeholders
11
-
12
-
13
- class X
14
- def plus a, b
15
- a + b
16
- end
17
- end
18
-
19
- x = X.new
20
-
21
- # To to_lazy object
22
- # to_lazy return "Iolite.lazy { |*args| self }"
23
- to_lazy_x = x.to_lazy
24
-
25
- # To to_lazy function
26
- to_lazy_f = to_lazy_x.plus(arg1, arg2)
27
-
28
- puts to_lazy_f.call(1, 2)
29
- # => 3
30
-
31
-
32
- str = "saya."
33
- ["homu", "mami", "mado"].each &str.to_lazy.concat(arg1 + ".")
34
- puts str
35
- # => saya.homu.mami.mado.
36
-
37
-
data/iolite.gemspec DELETED
@@ -1,24 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'iolite/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "iolite"
8
- spec.version = Iolite::VERSION
9
- spec.authors = ["manga_osyo"]
10
- spec.email = ["manga.osyo@gmail.com"]
11
- spec.summary = %q{unblockable library}
12
- spec.description = %q{unblockable library}
13
- spec.homepage = ""
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake"
23
- spec.add_development_dependency "rspec"
24
- end
@@ -1,22 +0,0 @@
1
- require "iolite/adaptor/define_send_original_methods"
2
- require "iolite/adaptor/callable"
3
- require "iolite/adaptor/bind"
4
- require "iolite/adaptor/send"
5
- require "iolite/adaptor/to_proc"
6
- require "iolite/adaptor/apply"
7
- require "iolite/adaptor/operators"
8
- require "iolite/adaptor/method_missing"
9
- require "iolite/adaptor/to_lazy"
10
-
11
- module Iolite module Adaptor
12
- module All
13
- include Callable
14
- include Bind
15
- include Send
16
- include MethodMissing
17
- include ToProc
18
- include Apply
19
- include Operators
20
- include ToLazy
21
- end
22
- end end
@@ -1,10 +0,0 @@
1
- require "iolite/functinal/bind"
2
-
3
- module Iolite module Adaptor
4
- module Apply
5
- def apply *args, &block
6
- Functinal.bind(self, *args, &block)
7
- end
8
- alias_method :iolite_apply, :apply
9
- end
10
- end end
@@ -1,9 +0,0 @@
1
- require "iolite/functinal/bind"
2
-
3
- module Iolite module Adaptor
4
- module Bind
5
- def bind *args
6
- Functinal.bind(Iolite.lazy { |*args| self }, *args)
7
- end
8
- end
9
- end end
@@ -1,7 +0,0 @@
1
- module Iolite module Adaptor
2
- module Callable
3
- def iolite_functinal_invoke_call(*args)
4
- call(*args)
5
- end
6
- end
7
- end end
@@ -1,12 +0,0 @@
1
- require "iolite/functinal/send"
2
-
3
- class Module
4
- def iolite_define_send_original_methods prefix = "_"
5
- instance_methods.each{ |method|
6
- next if method !~ /\w/
7
- define_method("#{prefix + method.to_s}"){ |*args|
8
- Iolite::Functinal.send(self, method, *args)
9
- }
10
- }
11
- end
12
- end
@@ -1,10 +0,0 @@
1
- require "iolite/functinal/send"
2
-
3
- module Iolite module Adaptor
4
- module MethodMissing
5
- def method_missing name, *args, &block
6
- Functinal.send(self, name, *args, &block)
7
- end
8
- module_function :method_missing
9
- end
10
- end end
@@ -1,26 +0,0 @@
1
- require "iolite/functinal/define_iolite_functinal_send_method"
2
-
3
- module Iolite module Adaptor
4
- module Operators
5
- define_iolite_functinal_send_method :==
6
- define_iolite_functinal_send_method :=~
7
- define_iolite_functinal_send_method :!
8
- define_iolite_functinal_send_method :!=
9
- define_iolite_functinal_send_method :!~
10
- define_iolite_functinal_send_method :===
11
-
12
- # &&
13
- def product rhs
14
- Lazy.new { |*args|
15
- Functinal.invoke(self, *args) && Functinal.invoke(rhs, *args)
16
- }
17
- end
18
-
19
- # ||
20
- def disjunction rhs
21
- Lazy.new { |*args|
22
- Functinal.invoke(self, *args) || Functinal.invoke(rhs, *args)
23
- }
24
- end
25
- end
26
- end end
@@ -1,11 +0,0 @@
1
- require "iolite/functinal/send"
2
- require "iolite/functinal/invoke"
3
-
4
- module Iolite module Adaptor
5
- module Send
6
- def send *args, &block
7
- Functinal.send(self, *args, &block)
8
- end
9
- alias_method :iolite_send, :send
10
- end
11
- end end
@@ -1,11 +0,0 @@
1
- # require "iolite/lazy"
2
-
3
- module Iolite module Adaptor
4
- module ToLazy
5
- def to_lazy
6
- Iolite.lazy { |*args| self }
7
- end
8
- alias_method :iolite_to_lazy, :to_lazy
9
- alias_method :to_l, :to_lazy
10
- end
11
- end end
@@ -1,10 +0,0 @@
1
- module Iolite module Adaptor
2
- module ToProc
3
- def to_proc
4
- Proc.new { |*args|
5
- self.call(*args)
6
- }
7
- end
8
- alias_method :iolite_to_proc, :to_proc
9
- end
10
- end end
@@ -1,2 +0,0 @@
1
- require "iolite/adaptor/all"
2
-
@@ -1,12 +0,0 @@
1
- require "iolite/adaptor/all"
2
- require "iolite/functinal/invoke"
3
-
4
- class Array
5
- include Iolite::Adaptor::ToProc
6
- include Iolite::Adaptor::Bind
7
- include Iolite::Adaptor::Apply
8
- include Iolite::Adaptor::Callable
9
- def call *args
10
- Iolite::Functinal.invoke_a(self, *args)
11
- end
12
- end
@@ -1,14 +0,0 @@
1
- require "iolite/adaptor/all"
2
- require "iolite/adaptored/iolite_lazy_with_hash"
3
-
4
- class Hash
5
- include Iolite::Adaptor::ToProc
6
- include Iolite::Adaptor::Bind
7
- include Iolite::Adaptor::Apply
8
- include Iolite::Adaptor::Callable
9
- def call *args
10
- Hash[ self.map { |key, value|
11
- Iolite::Functinal.invoke_a([key, value], *args)
12
- } ]
13
- end
14
- end
@@ -1,7 +0,0 @@
1
- module Iolite
2
- class Lazy
3
- def hash
4
- __id__
5
- end
6
- end
7
- end
@@ -1,5 +0,0 @@
1
- require "iolite/adaptor/to_lazy"
2
-
3
- class Object
4
- include Iolite::Adaptor::ToLazy
5
- end
@@ -1,5 +0,0 @@
1
- require "iolite/adaptor/all"
2
-
3
- class Proc
4
- include Iolite::Adaptor::All
5
- end
@@ -1,5 +0,0 @@
1
- require "iolite/adaptor/callable"
2
-
3
- class Proc
4
- include Iolite::Adaptor::Callable
5
- end
@@ -1,21 +0,0 @@
1
- require "iolite/placeholders"
2
-
3
- class String
4
- include Iolite::Adaptor::ToProc
5
- include Iolite::Adaptor::Callable
6
- def call *args
7
- result = self.clone
8
- args.each_with_index { |it, i|
9
- result.gsub! "#{Iolite::Placeholders.const_get("ARG#{i+1}")}", it.to_s
10
- }
11
- result
12
- end
13
-
14
- def to_call_by_eval binding = nil
15
- Iolite.lazy { |*args|
16
- gsub(/#{'#{(.*?)}'}/) {
17
- eval($1, binding).call(*args)
18
- }
19
- }
20
- end
21
- end
@@ -1,12 +0,0 @@
1
- require "iolite/functinal/invoke"
2
-
3
- module Iolite module Functinal
4
- def bind func, *args_
5
- Iolite.lazy { |*args|
6
- # func.call(*invoke_a(args_, *args))
7
- invoke(func, *args).call(*invoke_a(args_, *args))
8
- # func.call(*args).call(*invoke_a(args_, *args))
9
- }
10
- end
11
- module_function :bind
12
- end end
@@ -1,9 +0,0 @@
1
- require "iolite/functinal/send"
2
-
3
- class Module
4
- def define_iolite_functinal_send_method send_name, define_name = send_name
5
- define_method(define_name) { |*args|
6
- Iolite::Functinal.send(self, send_name, *args)
7
- }
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- module Iolite module Functinal
2
- def invoke func, *args
3
- func.respond_to?(:iolite_functinal_invoke_call) ? func.iolite_functinal_invoke_call(*args) : func
4
- end
5
- module_function :invoke
6
-
7
- def invoke_a funcs, *args
8
- funcs.map{ |it| invoke(it, *args) }
9
- end
10
- module_function :invoke_a
11
- end end
@@ -1,13 +0,0 @@
1
- require "iolite/functinal/invoke"
2
-
3
- module Iolite module Functinal
4
- def send func, method, *args_, &block
5
- Lazy.new { |*args|
6
- # block = invoke(block, *args) if block
7
- invoke(func, *args).send(method, *invoke_a(args_, *args), &block)
8
- # invoke(func, *args).send(method, *invoke_a(args_, *args), &block)
9
- # func.call(*args).send(method, *invoke_a(args_, *args), &block)
10
- }
11
- end
12
- module_function :send
13
- end end
@@ -1,4 +0,0 @@
1
- require "iolite/functinal/invoke"
2
- require "iolite/functinal/send"
3
- require "iolite/functinal/bind"
4
- require "iolite/functinal/define_iolite_functinal_send_method"
data/lib/iolite/lazy.rb DELETED
@@ -1,40 +0,0 @@
1
- require "iolite/adaptor"
2
-
3
- module Iolite
4
- class Lazy < BasicObject
5
- # include ::Iolite::Adaptor::All
6
- include ::Iolite::Adaptor::Callable
7
- include ::Iolite::Adaptor::Bind
8
- include ::Iolite::Adaptor::Send
9
- include ::Iolite::Adaptor::MethodMissing
10
- include ::Iolite::Adaptor::ToProc
11
- include ::Iolite::Adaptor::Apply
12
- include ::Iolite::Adaptor::Operators
13
- include ::Iolite::Adaptor::ToLazy
14
-
15
- def initialize &block
16
- @block = block
17
- end
18
-
19
- def call *args
20
- @block.call(*args)
21
- end
22
-
23
- # iolite_define_send_original_methods
24
- end
25
-
26
- def lazy &block
27
- Iolite::Lazy.new &block
28
- end
29
- module_function :lazy
30
-
31
- # def wrap value
32
- # Iolite.lazy { |*args| value }
33
- # end
34
- # module_function :wrap
35
- #
36
- # def lazy_func func
37
- # Iolite.lazy { |*args| func.call(*args) }
38
- # end
39
- # module_function :wrap
40
- end
@@ -1,30 +0,0 @@
1
- require "iolite/lazy"
2
-
3
- module Iolite module Placeholders
4
- def args
5
- Lazy.new { |*args|
6
- args
7
- }
8
- end
9
- module_function :args
10
-
11
- def argument index
12
- Lazy.new { |*args|
13
- args[index-1]
14
- }
15
- end
16
- module_function :argument
17
-
18
- def prepare n
19
- 1.upto(n).each { |i|
20
- const_set("ARG#{i}", argument(i))
21
- define_method("arg#{i}") do
22
- Placeholders.const_get("ARG#{i}")
23
- end
24
- module_function "arg#{i}"
25
- alias_method "_#{i}", "arg#{i}"
26
- }
27
- end
28
- module_function :prepare
29
- prepare(10)
30
- end end
@@ -1,16 +0,0 @@
1
- require "iolite/adaptor/all"
2
- require "iolite/functinal/invoke"
3
-
4
- module Iolite module Refinements
5
- module Array
6
- refine ::Array do
7
- include Iolite::Adaptor::ToProc
8
- include Iolite::Adaptor::Bind
9
- include Iolite::Adaptor::Apply
10
- include Iolite::Adaptor::Callable
11
- def call *args
12
- Iolite::Functinal.invoke_a(self, *args)
13
- end
14
- end
15
- end
16
- end end
@@ -1,18 +0,0 @@
1
- require "iolite/adaptor/all"
2
- require "iolite/functinal/invoke"
3
-
4
- module Iolite module Refinements
5
- module Hash
6
- refine ::Hash do
7
- include Iolite::Adaptor::ToProc
8
- include Iolite::Adaptor::Bind
9
- include Iolite::Adaptor::Apply
10
- include Iolite::Adaptor::Callable
11
- def call *args
12
- Hash[ self.map { |key, value|
13
- Iolite::Functinal.invoke_a([key, value], *args)
14
- } ]
15
- end
16
- end
17
- end
18
- end end