cucumber-rails 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -2
- data/HACKING.rdoc +34 -0
- data/History.txt +29 -0
- data/README.rdoc +48 -22
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/config/.gitignore +1 -0
- data/cucumber-rails.gemspec +49 -25
- data/dev_tasks/cucumber.rake +5 -0
- data/{tasks → dev_tasks}/rspec.rake +0 -0
- data/features/rails2.feature +56 -0
- data/features/rails3.feature +52 -0
- data/features/step_definitions/cucumber_rails_steps.rb +7 -0
- data/features/support/env.rb +4 -0
- data/features/support/matchers/files.rb +17 -0
- data/generators/cucumber/cucumber_generator.rb +27 -134
- data/generators/cucumber/templates/step_definitions/web_steps_ja.rb.erb +136 -0
- data/generators/feature/feature_generator.rb +30 -24
- data/lib/cucumber/rails/capybara_javascript_emulation.rb +25 -14
- data/lib/cucumber/rails/rspec.rb +20 -7
- data/lib/cucumber/rails/world.rb +5 -1
- data/lib/cucumber/web/tableish.rb +67 -65
- data/lib/generators/cucumber/feature/USAGE +16 -0
- data/lib/generators/cucumber/feature/feature_base.rb +29 -0
- data/lib/generators/cucumber/feature/feature_generator.rb +37 -0
- data/lib/generators/cucumber/feature/named_arg.rb +17 -0
- data/lib/generators/cucumber/skeleton/USAGE +21 -0
- data/lib/generators/cucumber/skeleton/skeleton_base.rb +202 -0
- data/lib/generators/cucumber/skeleton/skeleton_generator.rb +64 -0
- data/rvm.yml +22 -0
- data/spec/cucumber/web/tableish_spec.rb +2 -0
- data/spec/generators/cucumber/skeleton/skeleton_base_spec.rb +84 -0
- data/spec/spec.opts +2 -0
- data/{generators/feature/templates → templates/feature}/feature.erb +18 -12
- data/{generators/feature/templates → templates/feature}/steps.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/config/cucumber.yml.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/environments/cucumber.rb.erb +2 -2
- data/{generators/cucumber/templates → templates/skeleton}/script/cucumber +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/capybara_steps.rb.erb +18 -8
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/web_steps_cs.rb.erb +0 -0
- data/templates/skeleton/step_definitions/web_steps_da.rb.erb +114 -0
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/web_steps_de.rb.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/web_steps_es.rb.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/web_steps_no.rb.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/web_steps_pt-BR.rb.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/step_definitions/webrat_steps.rb.erb +13 -3
- data/{generators/cucumber/templates → templates/skeleton}/support/_rails_each_run.rb +7 -2
- data/{generators/cucumber/templates → templates/skeleton}/support/_rails_prefork.rb.erb +1 -1
- data/{generators/cucumber/templates → templates/skeleton}/support/capybara.rb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/support/edit_warning.txt +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/support/paths.rb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/support/rails.rb.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/support/rails_spork.rb.erb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/support/webrat.rb +0 -0
- data/{generators/cucumber/templates → templates/skeleton}/tasks/cucumber.rake.erb +1 -1
- metadata +77 -31
@@ -0,0 +1,17 @@
|
|
1
|
+
Spec::Matchers.define :have_files do |expected_files|
|
2
|
+
match do |rails_app|
|
3
|
+
actual_files = rails_app.files
|
4
|
+
@missing_files = expected_files - actual_files
|
5
|
+
@missing_files.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
failure_message_for_should do |expected_files|
|
9
|
+
"Rails app was missing these files:\n" + @missing_files.map { |file| " #{file}" }.join("\n")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Spec::Matchers.define :have_contents do |contents|
|
14
|
+
match do |file|
|
15
|
+
file.read.include?(contents)
|
16
|
+
end
|
17
|
+
end
|
@@ -1,62 +1,30 @@
|
|
1
1
|
require 'rbconfig'
|
2
2
|
require 'cucumber/platform'
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/generators/cucumber/skeleton/skeleton_base'))
|
3
4
|
|
4
5
|
# This generator bootstraps a Rails project for use with Cucumber
|
5
6
|
class CucumberGenerator < Rails::Generator::Base
|
6
|
-
|
7
|
-
|
7
|
+
|
8
|
+
include Cucumber::Generators::SkeletonBase
|
8
9
|
|
9
10
|
attr_accessor :driver
|
10
11
|
attr_accessor :framework
|
11
12
|
attr_reader :language, :template_dir
|
12
|
-
|
13
|
+
|
13
14
|
def initialize(runtime_args, runtime_options = {})
|
14
15
|
super
|
15
16
|
@language = @args.empty? ? 'en' : @args.first
|
16
17
|
end
|
17
|
-
|
18
|
+
|
18
19
|
def manifest
|
19
20
|
record do |m|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
"See upgrading instructions for 0.2.0 in History.txt"
|
28
|
-
exit(1)
|
29
|
-
end
|
30
|
-
|
31
|
-
m.template 'config/cucumber.yml.erb', 'config/cucumber.yml'
|
32
|
-
|
33
|
-
m.template 'environments/cucumber.rb.erb', 'config/environments/cucumber.rb'
|
34
|
-
|
35
|
-
m.file 'script/cucumber', 'script/cucumber', {
|
36
|
-
:chmod => 0755, :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang]
|
37
|
-
}
|
38
|
-
|
39
|
-
m.directory 'features/step_definitions'
|
40
|
-
m.template "step_definitions/#{driver}_steps.rb.erb", 'features/step_definitions/web_steps.rb'
|
41
|
-
if language != 'en'
|
42
|
-
m.template "step_definitions/web_steps_#{language}.rb.erb", "features/step_definitions/web_steps_#{language}.rb"
|
43
|
-
end
|
44
|
-
|
45
|
-
m.directory 'features/support'
|
46
|
-
if spork?
|
47
|
-
m.template 'support/rails_spork.rb.erb', 'features/support/env.rb'
|
48
|
-
else
|
49
|
-
m.template 'support/rails.rb.erb', 'features/support/env.rb'
|
50
|
-
end
|
51
|
-
m.file 'support/paths.rb', 'features/support/paths.rb'
|
52
|
-
|
53
|
-
m.directory 'lib/tasks'
|
54
|
-
m.template 'tasks/cucumber.rake.erb', 'lib/tasks/cucumber.rake'
|
55
|
-
|
56
|
-
m.gsub_file 'config/database.yml', /test:.*\n/, "test: &TEST\n"
|
57
|
-
unless File.read('config/database.yml').include? 'cucumber:'
|
58
|
-
m.gsub_file 'config/database.yml', /\z/, "\ncucumber:\n <<: *TEST"
|
59
|
-
end
|
21
|
+
check_upgrade_limitations
|
22
|
+
create_templates(m, true)
|
23
|
+
create_scripts(m, true)
|
24
|
+
create_step_definitions(m, true)
|
25
|
+
create_feature_support(m, true)
|
26
|
+
create_tasks(m, true)
|
27
|
+
create_database(m, true)
|
60
28
|
end
|
61
29
|
end
|
62
30
|
|
@@ -68,127 +36,52 @@ class CucumberGenerator < Rails::Generator::Base
|
|
68
36
|
options[:driver] ||= detect_current_driver || detect_default_driver
|
69
37
|
end
|
70
38
|
|
71
|
-
def
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
def embed_file(source, indent='')
|
76
|
-
IO.read(File.join(File.dirname(__FILE__), 'templates', source)).gsub(/^/, indent)
|
77
|
-
end
|
78
|
-
|
79
|
-
def embed_template(source, indent='')
|
80
|
-
template = File.join(File.dirname(__FILE__), 'templates', source)
|
81
|
-
ERB.new(IO.read(template), nil, '-').result(binding).gsub(/^/, indent)
|
82
|
-
end
|
83
|
-
|
84
|
-
def version
|
85
|
-
IO.read(File.dirname(__FILE__) + '/../../VERSION').chomp
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def first_loadable(libraries)
|
91
|
-
require 'rubygems'
|
92
|
-
libraries.each do |library|
|
93
|
-
begin
|
94
|
-
require library[0]
|
95
|
-
return library[1]
|
96
|
-
rescue LoadError => ignore
|
97
|
-
end
|
98
|
-
end
|
99
|
-
return nil
|
39
|
+
def cucumber_rails_env
|
40
|
+
'cucumber'
|
100
41
|
end
|
101
42
|
|
102
|
-
def
|
103
|
-
|
43
|
+
def self.gem_root
|
44
|
+
File.expand_path('../../../', __FILE__)
|
104
45
|
end
|
105
46
|
|
106
|
-
def
|
107
|
-
|
108
|
-
raise "I don't know which driver you want. Use --capybara or --webrat, or gem install capybara or webrat." unless @default_driver
|
109
|
-
@default_driver
|
47
|
+
def self.source_root
|
48
|
+
File.join(gem_root, 'templates', 'skeleton')
|
110
49
|
end
|
111
50
|
|
112
|
-
def
|
113
|
-
|
51
|
+
def source_root
|
52
|
+
self.class.source_root
|
114
53
|
end
|
115
54
|
|
116
|
-
|
117
|
-
@default_framework = first_loadable([['spec', :rspec], ['test/unit', :testunit]])
|
118
|
-
raise "I don't know what test framework you want. Use --rspec or --testunit, or gem install rspec or test-unit." unless @default_framework
|
119
|
-
@default_framework
|
120
|
-
end
|
121
|
-
|
122
|
-
def detect_in_env(choices)
|
123
|
-
env = File.file?("features/support/env.rb") ? IO.read("features/support/env.rb") : ''
|
124
|
-
choices.each do |choice|
|
125
|
-
detected = choice[1] if env =~ /#{choice[0]}/n
|
126
|
-
return detected if detected
|
127
|
-
end
|
128
|
-
return nil
|
129
|
-
end
|
55
|
+
private
|
130
56
|
|
131
57
|
def banner
|
132
58
|
"Usage: #{$0} cucumber (language)"
|
133
59
|
end
|
134
60
|
|
135
61
|
def after_generate
|
136
|
-
|
137
|
-
extend Cucumber::Formatter::ANSIColor
|
138
|
-
|
139
|
-
if @default_driver
|
140
|
-
puts <<-WARNING
|
141
|
-
|
142
|
-
#{yellow_cukes(15)}
|
143
|
-
|
144
|
-
#{yellow_cukes(1)} D R I V E R A L E R T #{yellow_cukes(1)}
|
145
|
-
|
146
|
-
You didn't explicitly generate with --capybara or --webrat, so I looked at
|
147
|
-
your gems and saw that you had #{green(@default_driver.to_s)} installed, so I went with that.
|
148
|
-
If you want something else, be specific about it. Otherwise, relax.
|
149
|
-
|
150
|
-
#{yellow_cukes(15)}
|
151
|
-
|
152
|
-
WARNING
|
153
|
-
end
|
154
|
-
|
155
|
-
if @default_framework
|
156
|
-
puts <<-WARNING
|
157
|
-
|
158
|
-
#{yellow_cukes(15)}
|
159
|
-
|
160
|
-
#{yellow_cukes(1)} T E S T F R A M E W O R K A L E R T #{yellow_cukes(1)}
|
161
|
-
|
162
|
-
You didn't explicitly generate with --rspec or --testunit, so I looked at
|
163
|
-
your gems and saw that you had #{green(@default_framework.to_s)} installed, so I went with that.
|
164
|
-
If you want something else, be specific about it. Otherwise, relax.
|
165
|
-
|
166
|
-
#{yellow_cukes(15)}
|
167
|
-
|
168
|
-
WARNING
|
169
|
-
end
|
62
|
+
print_instructions
|
170
63
|
end
|
171
64
|
|
172
65
|
def add_options!(opt)
|
173
66
|
opt.separator ''
|
174
67
|
opt.separator 'Options:'
|
175
|
-
opt.on('--webrat', 'Setup cucumber for use with webrat') do
|
68
|
+
opt.on('--webrat', 'Setup cucumber for use with webrat') do
|
176
69
|
options[:driver] = :webrat
|
177
70
|
end
|
178
71
|
|
179
|
-
opt.on('--capybara', 'Setup cucumber for use with capybara') do
|
72
|
+
opt.on('--capybara', 'Setup cucumber for use with capybara') do
|
180
73
|
options[:driver] = :capybara
|
181
74
|
end
|
182
75
|
|
183
|
-
opt.on('--rspec', "Setup cucumber for use with RSpec") do
|
76
|
+
opt.on('--rspec', "Setup cucumber for use with RSpec") do
|
184
77
|
options[:framework] = :rspec
|
185
78
|
end
|
186
79
|
|
187
|
-
opt.on('--testunit', "Setup cucumber for use with test/unit") do
|
80
|
+
opt.on('--testunit', "Setup cucumber for use with test/unit") do
|
188
81
|
options[:framework] = :testunit
|
189
82
|
end
|
190
83
|
|
191
|
-
opt.on('--spork', 'Setup cucumber for use with Spork') do
|
84
|
+
opt.on('--spork', 'Setup cucumber for use with Spork') do
|
192
85
|
options[:spork] = true
|
193
86
|
end
|
194
87
|
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
<%= embed_file('support/edit_warning.txt') %>
|
3
|
+
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
|
5
|
+
|
6
|
+
Given /^"([^\"]*)"ページを表示している$/ do |page_name|
|
7
|
+
Given %{I am on #{page_name}}
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^"([^\"]*)"ページを表示する$/ do |page_name|
|
11
|
+
Given %{I go to #{page_name}}
|
12
|
+
end
|
13
|
+
|
14
|
+
When /^"([^\"]*)"ボタンをクリックする$/ do |button|
|
15
|
+
When %{I press "#{button}"}
|
16
|
+
end
|
17
|
+
|
18
|
+
When /^"([^\"]*)"リンクをクリックする$/ do |link|
|
19
|
+
When %{I follow "#{link}"}
|
20
|
+
end
|
21
|
+
|
22
|
+
When /^"([^\"]*)"の"([^\"]*)"リンクをクリックする$/ do |parent, link|
|
23
|
+
When %{I follow "#{link}" within "#{parent}"}
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^"([^\"]*)"に"([^\"]*)"と入力する$/ do |field, value|
|
27
|
+
When %{I fill in "#{field}" with "#{value}"}
|
28
|
+
end
|
29
|
+
|
30
|
+
When /^以下の項目を入力する:$/ do |fields|
|
31
|
+
When %{I fill in the following:}, fields
|
32
|
+
end
|
33
|
+
|
34
|
+
When /^"([^\"]*)"から"([^\"]*)"を選択する$/ do |field, value|
|
35
|
+
When %{I select "#{value}" from "#{field}"}
|
36
|
+
end
|
37
|
+
|
38
|
+
When /^日時として"([^\"]*)"を選択する$/ do |time|
|
39
|
+
When %{I select "#{time}" as the date and time}
|
40
|
+
end
|
41
|
+
|
42
|
+
When /^"([^\"]*)"の日時として"([^\"]*)"を選択する$/ do |datetime_label, datetime|
|
43
|
+
When %{I select "#{datetime}" as the "#{datetime_label}" date and time}
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^時間として"([^\"]*)"を選択する$/ do |time|
|
47
|
+
When %{I select "#{time}" as the time}
|
48
|
+
end
|
49
|
+
|
50
|
+
When /^"([^\"]*)"の時間として"([^\"]*)"を選択する$/ do |time_label, time|
|
51
|
+
When %{I select "#{time}" as the "#{time_label}" time}
|
52
|
+
end
|
53
|
+
|
54
|
+
When /^日付として"([^\"]*)"を選択する$/ do |date|
|
55
|
+
When %{I select "#{date}" as the date}
|
56
|
+
end
|
57
|
+
|
58
|
+
When /^"([^\"]*)"の日付として"([^\"]*)"を選択する$/ do |date_label, date|
|
59
|
+
When %{I select "#{date}" as the "#{date_label}" date}
|
60
|
+
end
|
61
|
+
|
62
|
+
When /^"([^\"]*)"をチェックする$/ do |field|
|
63
|
+
When %{I check "#{field}"}
|
64
|
+
end
|
65
|
+
|
66
|
+
When /^"([^\"]*)"のチェックを外す$/ do |field|
|
67
|
+
When %{I uncheck "#{field}"}
|
68
|
+
end
|
69
|
+
|
70
|
+
When /^"([^\"]*)"を選択する$/ do |field|
|
71
|
+
When %{I choose "#{field}"}
|
72
|
+
end
|
73
|
+
|
74
|
+
When /^"([^\"]*)"としてファイル"([^\"]*)"を選択する$/ do |field, path|
|
75
|
+
When %{I attach the file at "#{path}" to "#{field}"}
|
76
|
+
end
|
77
|
+
|
78
|
+
Then /^"([^\"]*)"と表示されていること$/ do |text|
|
79
|
+
Then %{I should see "#{text}"}
|
80
|
+
end
|
81
|
+
|
82
|
+
Then /^"([^\"]*)"に"([^\"]*)"と表示されていること$/ do |selector, text|
|
83
|
+
Then %{I should see "#{text}" within "#{selector}"}
|
84
|
+
end
|
85
|
+
|
86
|
+
Then /^\/([^\/]*)\/と表示されていること$/ do |regexp|
|
87
|
+
Then %{I should see /#{regexp}/}
|
88
|
+
end
|
89
|
+
|
90
|
+
Then /^"([^\"]*)"に\/([^\/]*)\/と表示されていること$/ do |selector, regexp|
|
91
|
+
Then %{I should see \/#{regexp}\/ within "#{selector}"}
|
92
|
+
end
|
93
|
+
|
94
|
+
Then /^"([^\"]*)"と表示されていないこと$/ do |text|
|
95
|
+
Then %{I should not see "#{text}"}
|
96
|
+
end
|
97
|
+
|
98
|
+
Then /^"([^\"]*)"に"([^\"]*)"と表示されていないこと$/ do |selector, text|
|
99
|
+
Then %{I should not see "#{text}" within "#{selector}"}
|
100
|
+
end
|
101
|
+
|
102
|
+
Then /^\/([^\/]*)\/と表示されていないこと$/ do |regexp|
|
103
|
+
Then %{I should not see /#{regexp}/}
|
104
|
+
end
|
105
|
+
|
106
|
+
Then /^"([^\"]*)"に\/([^\/]*)\/と表示されていないこと$/ do |selector, regexp|
|
107
|
+
Then %{I should not see \/#{regexp}\/ within "#{selector}"}
|
108
|
+
end
|
109
|
+
|
110
|
+
Then /^入力項目"([^\"]*)"に"([^\"]*)"と表示されていること$/ do |field, value|
|
111
|
+
Then %{the "#{field}" field should contain "#{value}"}
|
112
|
+
end
|
113
|
+
|
114
|
+
Then /^入力項目"([^\"]*)"に"([^\"]*)"と表示されていないこと$/ do |field, value|
|
115
|
+
Then %{the "#{field}" field should not contain "#{value}"}
|
116
|
+
end
|
117
|
+
|
118
|
+
Then /^"([^\"]*)"がチェックされていること$/ do |label|
|
119
|
+
Then %{the "#{label}" checkbox should be checked}
|
120
|
+
end
|
121
|
+
|
122
|
+
Then /^"([^\"]*)"がチェックされていないこと$/ do |label|
|
123
|
+
Then %{the "#{label}" checkbox should not be checked}
|
124
|
+
end
|
125
|
+
|
126
|
+
Then /^"([^\"]*)"ページを表示していること$/ do |page_name|
|
127
|
+
Then %{I should be on #{page_name}}
|
128
|
+
end
|
129
|
+
|
130
|
+
show_me_the_page = lambda { Then %{show me the page} }
|
131
|
+
Then /^ページを表示する$/, &show_me_the_page
|
132
|
+
Then /^画面を目視$/, &show_me_the_page
|
133
|
+
|
134
|
+
# backword-compat for old japanese translation.
|
135
|
+
Then /^デバッグ(?:のため)?$/, &show_me_the_page
|
136
|
+
|
@@ -1,41 +1,47 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../../lib/generators/cucumber/feature/named_arg')
|
2
|
+
require File.join(File.dirname(__FILE__), '../../lib/generators/cucumber/feature/feature_base')
|
3
|
+
|
1
4
|
# This generator generates a baic feature.
|
2
5
|
class FeatureGenerator < Rails::Generator::NamedBase
|
6
|
+
|
7
|
+
include Cucumber::Generators::FeatureBase
|
8
|
+
|
3
9
|
def manifest
|
4
10
|
record do |m|
|
5
|
-
m
|
6
|
-
m
|
7
|
-
m
|
8
|
-
|
9
|
-
m.gsub_file 'features/support/paths.rb', /'\/'/mi do |match|
|
10
|
-
"#{match}\n when /the new #{singular_name} page/\n new_#{singular_name}_path\n"
|
11
|
-
end
|
11
|
+
create_directory(m, true)
|
12
|
+
create_feature_file(m)
|
13
|
+
create_steps_file(m)
|
14
|
+
create_support_file(m)
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
(n % 2) == 0
|
26
|
-
else
|
27
|
-
"#{@name} #{n}"
|
28
|
-
end
|
29
|
-
end
|
18
|
+
def self.gem_root
|
19
|
+
File.expand_path('../../../', __FILE__)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.source_root
|
23
|
+
File.join(gem_root, 'templates', 'feature')
|
24
|
+
end
|
25
|
+
|
26
|
+
def source_root
|
27
|
+
self.class.source_root
|
30
28
|
end
|
31
29
|
|
32
30
|
def named_args
|
33
|
-
args.map{|arg| NamedArg.new(arg)}
|
31
|
+
args.map { |arg| NamedArg.new(arg) }
|
34
32
|
end
|
35
33
|
|
36
|
-
|
34
|
+
private
|
37
35
|
|
38
36
|
def banner
|
39
37
|
"Usage: #{$0} feature ModelName [field:type, field:type]"
|
40
38
|
end
|
39
|
+
|
40
|
+
def add_options!(opt)
|
41
|
+
opt.separator ''
|
42
|
+
opt.separator 'Options:'
|
43
|
+
opt.on('--capybara=BACKEND', 'Generate a feature that uses a particular Capybara backend') do |backend|
|
44
|
+
options[:capybara] = backend
|
45
|
+
end
|
46
|
+
end
|
41
47
|
end
|