rroonga 1.0.1 → 1.0.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.
Files changed (135) hide show
  1. data/NEWS.ja.rdoc +46 -0
  2. data/NEWS.rdoc +46 -0
  3. data/README.ja.rdoc +2 -2
  4. data/README.rdoc +2 -3
  5. data/Rakefile +148 -11
  6. data/example/bookmark.rb +94 -91
  7. data/ext/groonga/extconf.rb +25 -25
  8. data/ext/groonga/groonga.def +2 -0
  9. data/ext/groonga/mkmf.log +7 -7
  10. data/ext/groonga/rb-grn-column.c +66 -0
  11. data/ext/groonga/rb-grn-context.c +92 -5
  12. data/ext/groonga/rb-grn-database.c +24 -1
  13. data/ext/groonga/rb-grn-exception.c +15 -0
  14. data/ext/groonga/rb-grn-hash.c +2 -2
  15. data/ext/groonga/rb-grn-index-column.c +8 -4
  16. data/ext/groonga/rb-grn-object.c +4 -2
  17. data/ext/groonga/rb-grn-patricia-trie.c +2 -2
  18. data/ext/groonga/rb-grn-snippet.c +1 -0
  19. data/ext/groonga/rb-grn-table-key-support.c +22 -19
  20. data/ext/groonga/rb-grn-table.c +63 -5
  21. data/ext/groonga/rb-grn.h +1 -1
  22. data/ext/groonga/rb-groonga.c +1 -0
  23. data/extconf.rb +1 -1
  24. data/html/developer.html +8 -2
  25. data/html/favicon.ico +0 -0
  26. data/html/favicon.svg +591 -0
  27. data/html/index.html +71 -8
  28. data/html/logo.svg +612 -0
  29. data/html/ranguba.css +92 -7
  30. data/html/readme.svg +256 -0
  31. data/lib/groonga/expression-builder.rb +8 -4
  32. data/lib/groonga/record.rb +77 -7
  33. data/lib/groonga/schema.rb +429 -100
  34. data/rroonga-build.rb +1 -1
  35. data/test/run-test.rb +1 -1
  36. data/test/test-array.rb +4 -0
  37. data/test/test-context.rb +8 -0
  38. data/test/test-database.rb +8 -1
  39. data/test/test-expression-builder.rb +14 -0
  40. data/test/test-fix-size-column.rb +4 -0
  41. data/test/test-hash.rb +10 -4
  42. data/test/test-index-column.rb +11 -0
  43. data/test/test-patricia-trie.rb +7 -1
  44. data/test/test-record.rb +14 -0
  45. data/test/test-remote.rb +3 -2
  46. data/test/test-schema-create-table.rb +32 -2
  47. data/test/test-schema.rb +108 -11
  48. data/test/test-table-select-normalize.rb +7 -3
  49. data/test/test-table-select.rb +12 -0
  50. data/test/test-table.rb +7 -0
  51. data/test/test-variable-size-column.rb +4 -0
  52. data/test-unit/Rakefile +40 -0
  53. data/test-unit/TODO +5 -0
  54. data/test-unit/bin/testrb +5 -0
  55. data/test-unit/html/classic.html +15 -0
  56. data/test-unit/html/index.html +25 -0
  57. data/test-unit/html/index.html.ja +27 -0
  58. data/test-unit/lib/test/unit/assertionfailederror.rb +25 -0
  59. data/test-unit/lib/test/unit/assertions.rb +1230 -0
  60. data/test-unit/lib/test/unit/attribute.rb +125 -0
  61. data/test-unit/lib/test/unit/autorunner.rb +360 -0
  62. data/test-unit/lib/test/unit/collector/descendant.rb +23 -0
  63. data/test-unit/lib/test/unit/collector/dir.rb +108 -0
  64. data/test-unit/lib/test/unit/collector/load.rb +144 -0
  65. data/test-unit/lib/test/unit/collector/objectspace.rb +34 -0
  66. data/test-unit/lib/test/unit/collector.rb +36 -0
  67. data/test-unit/lib/test/unit/color-scheme.rb +102 -0
  68. data/test-unit/lib/test/unit/color.rb +96 -0
  69. data/test-unit/lib/test/unit/diff.rb +724 -0
  70. data/test-unit/lib/test/unit/error.rb +130 -0
  71. data/test-unit/lib/test/unit/exceptionhandler.rb +39 -0
  72. data/test-unit/lib/test/unit/failure.rb +136 -0
  73. data/test-unit/lib/test/unit/fixture.rb +176 -0
  74. data/test-unit/lib/test/unit/notification.rb +129 -0
  75. data/test-unit/lib/test/unit/omission.rb +191 -0
  76. data/test-unit/lib/test/unit/pending.rb +150 -0
  77. data/test-unit/lib/test/unit/priority.rb +180 -0
  78. data/test-unit/lib/test/unit/runner/console.rb +52 -0
  79. data/test-unit/lib/test/unit/runner/emacs.rb +8 -0
  80. data/test-unit/lib/test/unit/runner/tap.rb +8 -0
  81. data/test-unit/lib/test/unit/testcase.rb +476 -0
  82. data/test-unit/lib/test/unit/testresult.rb +89 -0
  83. data/test-unit/lib/test/unit/testsuite.rb +110 -0
  84. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +14 -0
  85. data/test-unit/lib/test/unit/ui/console/testrunner.rb +466 -0
  86. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +63 -0
  87. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +92 -0
  88. data/test-unit/lib/test/unit/ui/testrunner.rb +28 -0
  89. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +77 -0
  90. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +41 -0
  91. data/test-unit/lib/test/unit/util/backtracefilter.rb +41 -0
  92. data/test-unit/lib/test/unit/util/method-owner-finder.rb +28 -0
  93. data/test-unit/lib/test/unit/util/observable.rb +90 -0
  94. data/test-unit/lib/test/unit/util/procwrapper.rb +48 -0
  95. data/test-unit/lib/test/unit/version.rb +7 -0
  96. data/test-unit/lib/test/unit.rb +323 -0
  97. data/test-unit/sample/adder.rb +13 -0
  98. data/test-unit/sample/subtracter.rb +12 -0
  99. data/test-unit/sample/test_adder.rb +20 -0
  100. data/test-unit/sample/test_subtracter.rb +20 -0
  101. data/test-unit/sample/test_user.rb +23 -0
  102. data/test-unit/test/collector/test-descendant.rb +133 -0
  103. data/test-unit/test/collector/test-load.rb +442 -0
  104. data/test-unit/test/collector/test_dir.rb +406 -0
  105. data/test-unit/test/collector/test_objectspace.rb +100 -0
  106. data/test-unit/test/run-test.rb +15 -0
  107. data/test-unit/test/test-attribute.rb +86 -0
  108. data/test-unit/test/test-color-scheme.rb +67 -0
  109. data/test-unit/test/test-color.rb +47 -0
  110. data/test-unit/test/test-diff.rb +518 -0
  111. data/test-unit/test/test-emacs-runner.rb +60 -0
  112. data/test-unit/test/test-fixture.rb +287 -0
  113. data/test-unit/test/test-notification.rb +33 -0
  114. data/test-unit/test/test-omission.rb +81 -0
  115. data/test-unit/test/test-pending.rb +70 -0
  116. data/test-unit/test/test-priority.rb +119 -0
  117. data/test-unit/test/test-testcase.rb +544 -0
  118. data/test-unit/test/test_assertions.rb +1151 -0
  119. data/test-unit/test/test_error.rb +26 -0
  120. data/test-unit/test/test_failure.rb +33 -0
  121. data/test-unit/test/test_testresult.rb +113 -0
  122. data/test-unit/test/test_testsuite.rb +129 -0
  123. data/test-unit/test/testunit-test-util.rb +14 -0
  124. data/test-unit/test/ui/test_testrunmediator.rb +20 -0
  125. data/test-unit/test/util/test-method-owner-finder.rb +38 -0
  126. data/test-unit/test/util/test_backtracefilter.rb +41 -0
  127. data/test-unit/test/util/test_observable.rb +102 -0
  128. data/test-unit/test/util/test_procwrapper.rb +36 -0
  129. data/text/{TUTORIAL.ja.rdoc → tutorial.ja.rdoc} +165 -126
  130. metadata +106 -16
  131. data/html/favicon.xcf +0 -0
  132. data/html/logo.xcf +0 -0
  133. data/license/GPL +0 -340
  134. data/license/RUBY +0 -59
  135. data/pkg-config.rb +0 -333
@@ -0,0 +1,191 @@
1
+ require 'test/unit/util/backtracefilter'
2
+
3
+ module Test
4
+ module Unit
5
+ class Omission
6
+ include Util::BacktraceFilter
7
+ attr_reader :test_name, :location, :message
8
+
9
+ SINGLE_CHARACTER = 'O'
10
+ LABEL = "Omission"
11
+
12
+ # Creates a new Omission with the given location and
13
+ # message.
14
+ def initialize(test_name, location, message)
15
+ @test_name = test_name
16
+ @location = location
17
+ @message = message
18
+ end
19
+
20
+ # Returns a single character representation of a omission.
21
+ def single_character_display
22
+ SINGLE_CHARACTER
23
+ end
24
+
25
+ def label
26
+ LABEL
27
+ end
28
+
29
+ # Returns a brief version of the error description.
30
+ def short_display
31
+ "#{@test_name}: #{@message.split("\n")[0]}"
32
+ end
33
+
34
+ # Returns a verbose version of the error description.
35
+ def long_display
36
+ backtrace = filter_backtrace(location).join("\n")
37
+ "#{label}: #{@message}\n#{@test_name}\n#{backtrace}"
38
+ end
39
+
40
+ # Overridden to return long_display.
41
+ def to_s
42
+ long_display
43
+ end
44
+
45
+ def critical?
46
+ true
47
+ end
48
+ end
49
+
50
+ class OmittedError < StandardError
51
+ end
52
+
53
+
54
+ module TestCaseOmissionSupport
55
+ class << self
56
+ def included(base)
57
+ base.class_eval do
58
+ include OmissionHandler
59
+ end
60
+ end
61
+ end
62
+
63
+ # Omit the test or part of the test.
64
+ #
65
+ # Example:
66
+ # def test_omission
67
+ # omit
68
+ # # Not reached here
69
+ # end
70
+ #
71
+ # def test_omission_with_here
72
+ # omit do
73
+ # # Not ran here
74
+ # end
75
+ # # Reached here
76
+ # end
77
+ def omit(message=nil, &block)
78
+ message ||= "omitted."
79
+ if block_given?
80
+ omission = Omission.new(name, filter_backtrace(caller), message)
81
+ add_omission(omission)
82
+ else
83
+ raise OmittedError.new(message)
84
+ end
85
+ end
86
+
87
+ # Omit the test or part of the test if _condition_ is
88
+ # true.
89
+ #
90
+ # Example:
91
+ # def test_omission
92
+ # omit_if("".empty?)
93
+ # # Not reached here
94
+ # end
95
+ #
96
+ # def test_omission_with_here
97
+ # omit_if(true) do
98
+ # # Not ran here
99
+ # end
100
+ # omit_if(false) do
101
+ # # Reached here
102
+ # end
103
+ # # Reached here too
104
+ # end
105
+ def omit_if(condition, *args, &block)
106
+ if condition
107
+ omit(*args, &block)
108
+ else
109
+ block.call if block
110
+ end
111
+ end
112
+
113
+ # Omit the test or part of the test if _condition_ is
114
+ # not true.
115
+ #
116
+ # Example:
117
+ # def test_omission
118
+ # omit_unless("string".empty?)
119
+ # # Not reached here
120
+ # end
121
+ #
122
+ # def test_omission_with_here
123
+ # omit_unless(true) do
124
+ # # Reached here
125
+ # end
126
+ # omit_unless(false) do
127
+ # # Not ran here
128
+ # end
129
+ # # Reached here too
130
+ # end
131
+ def omit_unless(condition, *args, &block)
132
+ if condition
133
+ block.call if block
134
+ else
135
+ omit(*args, &block)
136
+ end
137
+ end
138
+
139
+ private
140
+ def add_omission(omission)
141
+ current_result.add_omission(omission)
142
+ end
143
+ end
144
+
145
+ module OmissionHandler
146
+ class << self
147
+ def included(base)
148
+ base.exception_handler(:handle_omitted_error)
149
+ end
150
+ end
151
+
152
+ private
153
+ def handle_omitted_error(exception)
154
+ return false unless exception.is_a?(OmittedError)
155
+ omission = Omission.new(name,
156
+ filter_backtrace(exception.backtrace),
157
+ exception.message)
158
+ add_omission(omission)
159
+ true
160
+ end
161
+ end
162
+
163
+ module TestResultOmissionSupport
164
+ attr_reader :omissions
165
+
166
+ # Records a Test::Unit::Omission.
167
+ def add_omission(omission)
168
+ @omissions << omission
169
+ notify_fault(omission)
170
+ notify_changed
171
+ end
172
+
173
+ # Returns the number of omissions this TestResult has
174
+ # recorded.
175
+ def omission_count
176
+ @omissions.size
177
+ end
178
+
179
+ private
180
+ def initialize_containers
181
+ super
182
+ @omissions = []
183
+ @summary_generators << :omission_summary
184
+ end
185
+
186
+ def omission_summary
187
+ "#{omission_count} omissions"
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,150 @@
1
+ require 'test/unit/util/backtracefilter'
2
+
3
+ module Test
4
+ module Unit
5
+ class Pending
6
+ include Util::BacktraceFilter
7
+ attr_reader :test_name, :location, :message
8
+
9
+ SINGLE_CHARACTER = 'P'
10
+ LABEL = "Pending"
11
+
12
+ # Creates a new Pending with the given location and
13
+ # message.
14
+ def initialize(test_name, location, message)
15
+ @test_name = test_name
16
+ @location = location
17
+ @message = message
18
+ end
19
+
20
+ # Returns a single character representation of a pending.
21
+ def single_character_display
22
+ SINGLE_CHARACTER
23
+ end
24
+
25
+ def label
26
+ LABEL
27
+ end
28
+
29
+ # Returns a brief version of the error description.
30
+ def short_display
31
+ "#{@test_name}: #{@message.split("\n")[0]}"
32
+ end
33
+
34
+ # Returns a verbose version of the error description.
35
+ def long_display
36
+ backtrace = filter_backtrace(location).join("\n")
37
+ "#{label}: #{@message}\n#{@test_name}\n#{backtrace}"
38
+ end
39
+
40
+ # Overridden to return long_display.
41
+ def to_s
42
+ long_display
43
+ end
44
+
45
+ def critical?
46
+ true
47
+ end
48
+ end
49
+
50
+ class PendedError < StandardError
51
+ end
52
+
53
+
54
+ module TestCasePendingSupport
55
+ class << self
56
+ def included(base)
57
+ base.class_eval do
58
+ include PendingHandler
59
+ end
60
+ end
61
+ end
62
+
63
+ # Marks the test or part of the test is pending.
64
+ #
65
+ # Example:
66
+ # def test_pending
67
+ # pend
68
+ # # Not reached here
69
+ # end
70
+ #
71
+ # def test_pending_with_here
72
+ # pend do
73
+ # # Ran here
74
+ # # Fails if the block doesn't raise any error.
75
+ # # Because it means the block is passed unexpectedly.
76
+ # end
77
+ # # Reached here
78
+ # end
79
+ def pend(message=nil, &block)
80
+ message ||= "pended."
81
+ if block_given?
82
+ pending = nil
83
+ begin
84
+ yield
85
+ rescue Exception
86
+ pending = Pending.new(name, filter_backtrace(caller), message)
87
+ add_pending(pending)
88
+ end
89
+ unless pending
90
+ flunk("Pending block should not be passed: #{message}")
91
+ end
92
+ else
93
+ raise PendedError.new(message)
94
+ end
95
+ end
96
+
97
+ private
98
+ def add_pending(pending)
99
+ problem_occurred
100
+ current_result.add_pending(pending)
101
+ end
102
+ end
103
+
104
+ module PendingHandler
105
+ class << self
106
+ def included(base)
107
+ base.exception_handler(:handle_pended_error)
108
+ end
109
+ end
110
+
111
+ private
112
+ def handle_pended_error(exception)
113
+ return false unless exception.is_a?(PendedError)
114
+ pending = Pending.new(name,
115
+ filter_backtrace(exception.backtrace),
116
+ exception.message)
117
+ add_pending(pending)
118
+ true
119
+ end
120
+ end
121
+
122
+ module TestResultPendingSupport
123
+ attr_reader :pendings
124
+
125
+ # Records a Test::Unit::Pending.
126
+ def add_pending(pending)
127
+ @pendings << pending
128
+ notify_fault(pending)
129
+ notify_changed
130
+ end
131
+
132
+ # Returns the number of pendings this TestResult has
133
+ # recorded.
134
+ def pending_count
135
+ @pendings.size
136
+ end
137
+
138
+ private
139
+ def initialize_containers
140
+ super
141
+ @pendings = []
142
+ @summary_generators << :pending_summary
143
+ end
144
+
145
+ def pending_summary
146
+ "#{pending_count} pendings"
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,180 @@
1
+ module Test
2
+ module Unit
3
+ module Priority
4
+ class << self
5
+ def included(base)
6
+ base.extend(ClassMethods)
7
+
8
+ base.class_eval do
9
+ setup :priority_setup, :before => :prepend
10
+ teardown :priority_teardown, :after => :append
11
+ end
12
+ end
13
+
14
+ @@enabled = false
15
+ def enabled?
16
+ @@enabled
17
+ end
18
+
19
+ def enable
20
+ require "fileutils"
21
+ require "tmpdir"
22
+ @@enabled = true
23
+ end
24
+
25
+ def disable
26
+ @@enabled = false
27
+ end
28
+
29
+ @@default = :normal
30
+ def default
31
+ @@default || :normal
32
+ end
33
+
34
+ def default=(default)
35
+ @@default = default
36
+ end
37
+
38
+ def available_values
39
+ Checker.available_priorities
40
+ end
41
+ end
42
+
43
+ class Checker
44
+ class << self
45
+ def have_priority?(name)
46
+ singleton_class = (class << self; self; end)
47
+ singleton_class.method_defined?(priority_check_method_name(name))
48
+ end
49
+
50
+ def need_to_run?(test)
51
+ priority = test[:priority] || Priority.default
52
+ if have_priority?(priority)
53
+ send(priority_check_method_name(priority), test)
54
+ else
55
+ true
56
+ end
57
+ end
58
+
59
+ def available_priorities
60
+ methods(false).collect do |name|
61
+ /\Arun_priority_(.+)\?\z/ =~ name.to_s
62
+ $1
63
+ end.compact
64
+ end
65
+
66
+ def run_priority_must?(test)
67
+ true
68
+ end
69
+
70
+ def run_priority_important?(test)
71
+ rand > 0.1
72
+ end
73
+
74
+ def run_priority_high?(test)
75
+ rand > 0.3
76
+ end
77
+
78
+ def run_priority_normal?(test)
79
+ rand > 0.5
80
+ end
81
+
82
+ def run_priority_low?(test)
83
+ rand > 0.75
84
+ end
85
+
86
+ def run_priority_never?(test)
87
+ false
88
+ end
89
+
90
+ private
91
+ def priority_check_method_name(priority_name)
92
+ "run_priority_#{priority_name}?"
93
+ end
94
+ end
95
+
96
+ attr_reader :test
97
+ def initialize(test)
98
+ @test = test
99
+ end
100
+
101
+ def setup
102
+ FileUtils.rm_f(passed_file)
103
+ end
104
+
105
+ def teardown
106
+ if @test.send(:passed?)
107
+ FileUtils.touch(passed_file)
108
+ else
109
+ FileUtils.rm_f(passed_file)
110
+ end
111
+ end
112
+
113
+ def need_to_run?
114
+ !previous_test_success? or self.class.need_to_run?(@test)
115
+ end
116
+
117
+ private
118
+ def previous_test_success?
119
+ File.exist?(passed_file)
120
+ end
121
+
122
+ def result_dir
123
+ components = [".test-result",
124
+ @test.class.name || "AnonymousTestCase",
125
+ escaped_method_name]
126
+ parent_directories = [File.dirname($0), Dir.pwd]
127
+ if Process.respond_to?(:uid)
128
+ parent_directories << File.join(Dir.tmpdir, Process.uid.to_s)
129
+ end
130
+ parent_directories.each do |parent_directory|
131
+ dir = File.expand_path(File.join(parent_directory, *components))
132
+ begin
133
+ FileUtils.mkdir_p(dir)
134
+ return dir
135
+ rescue Errno::EACCES
136
+ end
137
+ end
138
+
139
+ raise Errno::EACCES, parent_directories.join(", ")
140
+ end
141
+
142
+ def passed_file
143
+ File.join(result_dir, "passed")
144
+ end
145
+
146
+ def escaped_method_name
147
+ @test.method_name.to_s.gsub(/[!?=]$/) do |matched|
148
+ case matched
149
+ when "!"
150
+ ".destructive"
151
+ when "?"
152
+ ".predicate"
153
+ when "="
154
+ ".equal"
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ module ClassMethods
161
+ def priority(name, *tests)
162
+ unless Checker.have_priority?(name)
163
+ raise ArgumentError, "unknown priority: #{name}"
164
+ end
165
+ attribute(:priority, name, {:keep => true}, *tests)
166
+ end
167
+ end
168
+
169
+ def priority_setup
170
+ return unless Priority.enabled?
171
+ Checker.new(self).setup
172
+ end
173
+
174
+ def priority_teardown
175
+ return unless Priority.enabled?
176
+ Checker.new(self).teardown
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,52 @@
1
+ module Test
2
+ module Unit
3
+ AutoRunner.register_runner(:console) do |auto_runner|
4
+ require 'test/unit/ui/console/testrunner'
5
+ Test::Unit::UI::Console::TestRunner
6
+ end
7
+
8
+ AutoRunner.setup_option do |auto_runner, opts|
9
+ require 'test/unit/ui/console/outputlevel'
10
+
11
+ output_levels = [
12
+ [:silent, UI::Console::OutputLevel::SILENT],
13
+ [:progress, UI::Console::OutputLevel::PROGRESS_ONLY],
14
+ [:normal, UI::Console::OutputLevel::NORMAL],
15
+ [:verbose, UI::Console::OutputLevel::VERBOSE],
16
+ ]
17
+ opts.on('-v', '--verbose=[LEVEL]', output_levels,
18
+ "Set the output level (default is verbose).",
19
+ "(#{auto_runner.keyword_display(output_levels)})") do |level|
20
+ level ||= output_levels.assoc(:verbose)[1]
21
+ auto_runner.runner_options[:output_level] = level
22
+ end
23
+
24
+ use_color_options = [
25
+ [:auto, :auto],
26
+ ["-", false],
27
+ ["no", false],
28
+ ["false", false],
29
+ ["+", true],
30
+ ["yes", true],
31
+ ["true", true],
32
+ ]
33
+ opts.on("--[no-]use-color=[auto]", use_color_options,
34
+ "Uses color output",
35
+ "(default is auto)") do |use_color|
36
+ case use_color
37
+ when nil
38
+ use_color = true
39
+ when :auto
40
+ use_color = nil
41
+ end
42
+ auto_runner.runner_options[:use_color] = use_color
43
+ end
44
+
45
+ opts.on("--progress-row-max=MAX", Integer,
46
+ "Uses MAX as max terminal width for progress mark",
47
+ "(default is auto)") do |max|
48
+ auto_runner.runner_options[:progress_row_max] = max
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,8 @@
1
+ module Test
2
+ module Unit
3
+ AutoRunner.register_runner(:emacs) do |auto_runner|
4
+ require 'test/unit/ui/emacs/testrunner'
5
+ Test::Unit::UI::Emacs::TestRunner
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Test
2
+ module Unit
3
+ AutoRunner.register_runner(:tap) do |auto_runner|
4
+ require 'test/unit/ui/tap/testrunner'
5
+ Test::Unit::UI::Tap::TestRunner
6
+ end
7
+ end
8
+ end