watir-webdriver 0.6.4 → 0.6.5
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/CHANGES.md +78 -126
- data/LICENSE +3 -1
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/lib/watir-webdriver.rb +15 -1
- data/lib/watir-webdriver/browser.rb +2 -1
- data/lib/watir-webdriver/cookies.rb +35 -7
- data/lib/watir-webdriver/elements/area.rb +13 -0
- data/lib/watir-webdriver/elements/element.rb +3 -3
- data/lib/watir-webdriver/elements/generated.rb +94 -55
- data/lib/watir-webdriver/elements/{frame.rb → iframe.rb} +41 -28
- data/lib/watir-webdriver/elements/input.rb +0 -16
- data/lib/watir-webdriver/elements/link.rb +13 -1
- data/lib/watir-webdriver/elements/text_area.rb +17 -0
- data/lib/watir-webdriver/html/generator.rb +2 -2
- data/lib/watir-webdriver/html/spec_extractor.rb +31 -4
- data/lib/watir-webdriver/html/visitor.rb +12 -4
- data/lib/watir-webdriver/locators/button_locator.rb +7 -13
- data/lib/watir-webdriver/locators/element_locator.rb +9 -5
- data/lib/watir-webdriver/locators/text_area_locator.rb +20 -0
- data/lib/watir-webdriver/locators/text_field_locator.rb +8 -0
- data/lib/watir-webdriver/version.rb +1 -1
- data/lib/watir-webdriver/wait.rb +23 -11
- data/spec/browser_spec.rb +18 -18
- data/spec/click_spec.rb +5 -5
- data/spec/container_spec.rb +5 -11
- data/spec/element_locator_spec.rb +32 -26
- data/spec/element_spec.rb +9 -9
- data/spec/implementation.rb +6 -2
- data/spec/input_spec.rb +11 -5
- data/spec/locator_spec_helper.rb +3 -3
- data/spec/special_chars_spec.rb +1 -1
- data/support/travis.sh +19 -5
- data/watir-webdriver.gemspec +1 -0
- metadata +37 -38
- data/spec/html/wait.html +0 -28
- data/spec/wait_spec.rb +0 -118
data/spec/browser_spec.rb
CHANGED
@@ -9,14 +9,13 @@ describe Watir::Browser do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it "takes a Driver instance as argument" do
|
12
|
-
mock_driver =
|
12
|
+
mock_driver = double(Selenium::WebDriver::Driver)
|
13
13
|
Selenium::WebDriver::Driver.should_receive(:===).with(mock_driver).and_return(true)
|
14
|
-
|
15
|
-
lambda { Watir::Browser.new(mock_driver) }.should_not raise_error
|
14
|
+
expect { Watir::Browser.new(mock_driver) }.to_not raise_error
|
16
15
|
end
|
17
16
|
|
18
17
|
it "raises ArgumentError for invalid args" do
|
19
|
-
|
18
|
+
expect { Watir::Browser.new(Object.new) }.to raise_error(ArgumentError)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
@@ -25,25 +24,25 @@ describe Watir::Browser do
|
|
25
24
|
|
26
25
|
it "wraps elements as Watir objects" do
|
27
26
|
returned = browser.execute_script("return document.body")
|
28
|
-
returned.
|
27
|
+
expect(returned).to be_kind_of(Watir::Body)
|
29
28
|
end
|
30
29
|
|
31
30
|
it "wraps elements in an array" do
|
32
31
|
list = browser.execute_script("return [document.body];")
|
33
32
|
list.size.should == 1
|
34
|
-
list.first.
|
33
|
+
expect(list.first).to be_kind_of(Watir::Body)
|
35
34
|
end
|
36
35
|
|
37
36
|
it "wraps elements in a Hash" do
|
38
37
|
hash = browser.execute_script("return {element: document.body};")
|
39
|
-
hash['element'].
|
38
|
+
expect(hash['element']).to be_kind_of(Watir::Body)
|
40
39
|
end
|
41
40
|
|
42
41
|
it "wraps elements in a deep object" do
|
43
42
|
hash = browser.execute_script("return {elements: [document.body], body: {element: document.body }}")
|
44
43
|
|
45
44
|
hash['elements'].first.should be_kind_of(Watir::Body)
|
46
|
-
hash['body']['element'].
|
45
|
+
expect(hash['body']['element']).to be_kind_of(Watir::Body)
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
@@ -52,7 +51,7 @@ describe Watir::Browser do
|
|
52
51
|
browser.goto WatirSpec.url_for "forms_with_input_elements.html"
|
53
52
|
|
54
53
|
browser.send_keys "hello"
|
55
|
-
browser.text_field(:id => "new_user_first_name").value.
|
54
|
+
expect(browser.text_field(:id => "new_user_first_name").value).to eq "hello"
|
56
55
|
end
|
57
56
|
|
58
57
|
it "sends keys to a frame" do
|
@@ -62,7 +61,7 @@ describe Watir::Browser do
|
|
62
61
|
|
63
62
|
browser.frame.send_keys "hello"
|
64
63
|
|
65
|
-
tf.value.
|
64
|
+
expect(tf.value).to eq "hello"
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|
@@ -71,7 +70,7 @@ describe Watir::Browser do
|
|
71
70
|
b.goto WatirSpec.url_for "definition_lists.html"
|
72
71
|
b.close
|
73
72
|
|
74
|
-
|
73
|
+
expect { b.dl(:id => "experience-list").id }.to raise_error(Error, "browser was closed")
|
75
74
|
end
|
76
75
|
|
77
76
|
describe "#wait_while" do
|
@@ -81,7 +80,7 @@ describe Watir::Browser do
|
|
81
80
|
called = false
|
82
81
|
browser.wait_while(3, "foo") { called = true }
|
83
82
|
|
84
|
-
called.
|
83
|
+
expect(called).to be_true
|
85
84
|
end
|
86
85
|
end
|
87
86
|
|
@@ -92,14 +91,14 @@ describe Watir::Browser do
|
|
92
91
|
called = false
|
93
92
|
browser.wait_until(3, "foo") { called = true }
|
94
93
|
|
95
|
-
called.
|
94
|
+
expect(called).to be_true
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
99
98
|
describe "#wait" do
|
100
99
|
it "waits until document.readyState == 'complete'" do
|
101
|
-
browser.
|
102
|
-
browser.
|
100
|
+
expect(browser).to receive(:ready_state).and_return('incomplete')
|
101
|
+
expect(browser).to receive(:ready_state).and_return('complete')
|
103
102
|
|
104
103
|
browser.wait
|
105
104
|
end
|
@@ -107,7 +106,8 @@ describe Watir::Browser do
|
|
107
106
|
|
108
107
|
describe "#ready_state" do
|
109
108
|
it "gets the document's readyState property" do
|
110
|
-
browser.should_receive(:execute_script).with('return document.readyState')
|
109
|
+
#browser.should_receive(:execute_script).with('return document.readyState')
|
110
|
+
expect(browser).to receive(:execute_script).with('return document.readyState')
|
111
111
|
browser.ready_state
|
112
112
|
end
|
113
113
|
end
|
@@ -115,13 +115,13 @@ describe Watir::Browser do
|
|
115
115
|
describe "#inspect" do
|
116
116
|
it "works even if browser is closed" do
|
117
117
|
browser.should_receive(:url).and_raise(Errno::ECONNREFUSED)
|
118
|
-
|
118
|
+
expect(browser.inspect).to_not raise_error
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
122
|
describe '#screenshot' do
|
123
123
|
it 'returns an instance of of Watir::Screenshot' do
|
124
|
-
browser.screenshot.
|
124
|
+
expect(browser.screenshot).to be_kind_of(Watir::Screenshot)
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
data/spec/click_spec.rb
CHANGED
@@ -10,25 +10,25 @@ describe Watir::Element do
|
|
10
10
|
let(:log) { browser.element(:id => "log").ps.map { |e| e.text } }
|
11
11
|
|
12
12
|
# TODO: make guards more flexible, in reality this currently only works on linux with native events
|
13
|
-
compliant_on [:webdriver, :firefox, :native_events] do
|
13
|
+
compliant_on [:webdriver, :firefox, :native_events] do
|
14
14
|
it "should perform a click with no modifier keys" do
|
15
15
|
clicker.click
|
16
|
-
log.
|
16
|
+
expect(log).to eq ["shift=false alt=false"]
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should perform a click with the shift key pressed" do
|
20
20
|
clicker.click(:shift)
|
21
|
-
log.
|
21
|
+
expect(log).to eq ["shift=true alt=false"]
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should perform a click with the alt key pressed" do
|
25
25
|
clicker.click(:alt)
|
26
|
-
log.
|
26
|
+
expect(log).to eq ["shift=false alt=true"]
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should perform a click with the shift and alt keys pressed" do
|
30
30
|
clicker.click(:shift, :alt)
|
31
|
-
log.
|
31
|
+
expect(log).to eq ["shift=true alt=true"]
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
data/spec/container_spec.rb
CHANGED
@@ -11,29 +11,23 @@ describe Watir::Container do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "converts 2-arg selector into a hash" do
|
14
|
-
@container.public_extract_selector([:how, 'what']).
|
15
|
-
should == { :how => 'what' }
|
14
|
+
expect(@container.public_extract_selector([:how, 'what'])).to eq Hash[:how => 'what']
|
16
15
|
end
|
17
16
|
|
18
17
|
it "returns the hash given" do
|
19
|
-
@container.public_extract_selector([:how => "what"]).
|
20
|
-
should == { :how => "what" }
|
18
|
+
expect(@container.public_extract_selector([:how => "what"])).to eq Hash[:how => "what"]
|
21
19
|
end
|
22
20
|
|
23
21
|
it "returns an empty hash if given no args" do
|
24
|
-
@container.public_extract_selector([]).
|
22
|
+
expect(@container.public_extract_selector([])).to eq Hash[]
|
25
23
|
end
|
26
24
|
|
27
25
|
it "raises ArgumentError if given 1 arg which is not a Hash" do
|
28
|
-
|
29
|
-
@container.public_extract_selector([:how])
|
30
|
-
}.should raise_error(ArgumentError)
|
26
|
+
expect {@container.public_extract_selector([:how])}.to raise_error(ArgumentError)
|
31
27
|
end
|
32
28
|
|
33
29
|
it "raises ArgumentError if given > 2 args" do
|
34
|
-
|
35
|
-
@container.public_extract_selector([:how, 'what', 'value'])
|
36
|
-
}.should raise_error(ArgumentError)
|
30
|
+
expect {@container.public_extract_selector([:how, 'what', 'value'])}.to raise_error(ArgumentError)
|
37
31
|
end
|
38
32
|
|
39
33
|
end
|
@@ -106,6 +106,17 @@ describe Watir::ElementLocator do
|
|
106
106
|
:data_name => "foo"
|
107
107
|
end
|
108
108
|
|
109
|
+
it "handles aria-* attributes" do
|
110
|
+
if Watir.prefer_css?
|
111
|
+
expect_one :css, 'div[aria-label="foo"]'
|
112
|
+
else
|
113
|
+
expect_one :xpath, ".//div[@aria-label='foo']"
|
114
|
+
end
|
115
|
+
|
116
|
+
locate_one :tag_name => "div",
|
117
|
+
:aria_label => "foo"
|
118
|
+
end
|
119
|
+
|
109
120
|
it "normalizes space for the :href attribute" do
|
110
121
|
if Watir.prefer_css?
|
111
122
|
expect_one :css, 'a[href~="foo"]'
|
@@ -146,11 +157,11 @@ describe Watir::ElementLocator do
|
|
146
157
|
locate_one selector, Watir::Input.attributes
|
147
158
|
end
|
148
159
|
|
149
|
-
it "
|
160
|
+
it "uses label attribute if it is valid for element" do
|
150
161
|
expect_one :xpath, ".//option[@label='foo']"
|
151
162
|
|
152
|
-
|
153
|
-
|
163
|
+
selector = { :tag_name => "option", :label => "foo" }
|
164
|
+
locate_one selector, Watir::Option.attributes
|
154
165
|
end
|
155
166
|
|
156
167
|
it "translates ruby attribute names to content attribute names" do
|
@@ -184,7 +195,7 @@ describe Watir::ElementLocator do
|
|
184
195
|
expect_all(:xpath, ".//div").and_return(elements)
|
185
196
|
end
|
186
197
|
|
187
|
-
locate_one(:tag_name => "div", :class => /oob/).
|
198
|
+
expect(locate_one(:tag_name => "div", :class => /oob/)).to eq elements[1]
|
188
199
|
end
|
189
200
|
|
190
201
|
it "handles :tag_name, :index and a single regexp attribute" do
|
@@ -205,7 +216,7 @@ describe Watir::ElementLocator do
|
|
205
216
|
:index => 1
|
206
217
|
}
|
207
218
|
|
208
|
-
locate_one(selector).
|
219
|
+
expect(locate_one(selector)).to eq elements[1]
|
209
220
|
end
|
210
221
|
|
211
222
|
it "handles mix of string and regexp attributes" do
|
@@ -227,7 +238,7 @@ describe Watir::ElementLocator do
|
|
227
238
|
:title => /baz/
|
228
239
|
}
|
229
240
|
|
230
|
-
locate_one(selector).
|
241
|
+
expect(locate_one(selector)).to eq elements[1]
|
231
242
|
end
|
232
243
|
|
233
244
|
it "handles data-* attributes with regexp" do
|
@@ -248,7 +259,7 @@ describe Watir::ElementLocator do
|
|
248
259
|
:data_automation_id => /bar/
|
249
260
|
}
|
250
261
|
|
251
|
-
locate_one(selector).
|
262
|
+
expect(locate_one(selector)).to eq elements[1]
|
252
263
|
end
|
253
264
|
|
254
265
|
it "handles :label => /regexp/ selector" do
|
@@ -266,12 +277,12 @@ describe Watir::ElementLocator do
|
|
266
277
|
expect_all(:xpath, ".//div[@id='baz']").ordered.and_return(div_elements)
|
267
278
|
end
|
268
279
|
|
269
|
-
locate_one(:tag_name => "div", :label => /oob/).
|
280
|
+
expect(locate_one(:tag_name => "div", :label => /oob/)).to eq div_elements.first
|
270
281
|
end
|
271
282
|
|
272
283
|
it "returns nil when no label matching the regexp is found" do
|
273
284
|
expect_all(:tag_name, "label").and_return([])
|
274
|
-
locate_one(:tag_name => "div", :label => /foo/).
|
285
|
+
expect(locate_one(:tag_name => "div", :label => /foo/)).to be_nil
|
275
286
|
end
|
276
287
|
|
277
288
|
end
|
@@ -295,7 +306,7 @@ describe Watir::ElementLocator do
|
|
295
306
|
:index => 1
|
296
307
|
}
|
297
308
|
|
298
|
-
locate_one(selector).
|
309
|
+
expect(locate_one(selector)).to eq elements[1]
|
299
310
|
end
|
300
311
|
|
301
312
|
it "returns nil if found element didn't match the selector tag_name" do
|
@@ -306,29 +317,26 @@ describe Watir::ElementLocator do
|
|
306
317
|
:xpath => "//div"
|
307
318
|
}
|
308
319
|
|
309
|
-
locate_one(selector, Watir::Input.attributes).
|
320
|
+
expect(locate_one(selector, Watir::Input.attributes)).to be_nil
|
310
321
|
end
|
311
322
|
|
312
323
|
describe "errors" do
|
313
324
|
it "raises a TypeError if :index is not a Fixnum" do
|
314
|
-
|
315
|
-
|
316
|
-
}.should raise_error(TypeError, %[expected Fixnum, got "bar":String])
|
325
|
+
expect { locate_one(:tag_name => "div", :index => "bar") }.to \
|
326
|
+
raise_error(TypeError, %[expected Fixnum, got "bar":String])
|
317
327
|
end
|
318
328
|
|
319
329
|
it "raises a TypeError if selector value is not a String or Regexp" do
|
320
|
-
|
321
|
-
|
322
|
-
}.should raise_error(TypeError, %[expected one of [String, Regexp], got 123:Fixnum])
|
330
|
+
expect { locate_one(:tag_name => 123) }.to \
|
331
|
+
raise_error(TypeError, %[expected one of [String, Regexp], got 123:Fixnum])
|
323
332
|
end
|
324
333
|
|
325
334
|
it "raises a MissingWayOfFindingObjectException if the attribute is not valid" do
|
326
335
|
bad_selector = {:tag_name => "input", :href => "foo"}
|
327
336
|
valid_attributes = Watir::Input.attributes
|
328
337
|
|
329
|
-
|
330
|
-
|
331
|
-
}.should raise_error(MissingWayOfFindingObjectException, "invalid attribute: :href")
|
338
|
+
expect { locate_one(bad_selector, valid_attributes) }.to \
|
339
|
+
raise_error(MissingWayOfFindingObjectException, "invalid attribute: :href")
|
332
340
|
end
|
333
341
|
end
|
334
342
|
end
|
@@ -383,8 +391,7 @@ describe Watir::ElementLocator do
|
|
383
391
|
expect_all(:xpath, ".//div").and_return(elements)
|
384
392
|
end
|
385
393
|
|
386
|
-
|
387
|
-
locate_all(:tag_name => "div", :class => /oob/).should == elements.last(3)
|
394
|
+
expect(locate_all(:tag_name => "div", :class => /oob/)).to eq elements.last(3)
|
388
395
|
end
|
389
396
|
|
390
397
|
it "handles mix of string and regexp attributes" do
|
@@ -406,15 +413,14 @@ describe Watir::ElementLocator do
|
|
406
413
|
:title => /baz/
|
407
414
|
}
|
408
415
|
|
409
|
-
locate_all(selector).
|
416
|
+
expect(locate_all(selector)).to eq elements.last(2)
|
410
417
|
end
|
411
418
|
end
|
412
419
|
|
413
420
|
describe "errors" do
|
414
421
|
it "raises ArgumentError if :index is given" do
|
415
|
-
|
416
|
-
|
417
|
-
}.should raise_error(ArgumentError, "can't locate all elements by :index")
|
422
|
+
expect { locate_all(:tag_name => "div", :index => 1) }.to \
|
423
|
+
raise_error(ArgumentError, "can't locate all elements by :index")
|
418
424
|
end
|
419
425
|
end
|
420
426
|
end
|
data/spec/element_spec.rb
CHANGED
@@ -8,25 +8,25 @@ describe Watir::Element do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'returns true if the element exists and is visible' do
|
11
|
-
browser.div(:id, 'foo').
|
11
|
+
expect(browser.div(:id, 'foo')).to be_present
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'returns false if the element exists but is not visible' do
|
15
|
-
browser.div(:id, 'bar').
|
15
|
+
expect(browser.div(:id, 'bar')).to_not be_present
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'returns false if the element does not exist' do
|
19
|
-
browser.div(:id, 'should-not-exist').
|
19
|
+
expect(browser.div(:id, 'should-not-exist')).to_not be_present
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe "#reset!" do
|
24
24
|
it "successfully relocates collection elements after a reset!" do
|
25
25
|
element = browser.divs(:id, 'foo').to_a.first
|
26
|
-
element.
|
26
|
+
expect(element).to_not be_nil
|
27
27
|
|
28
28
|
element.send :reset!
|
29
|
-
element.
|
29
|
+
expect(element).to exist
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -37,9 +37,9 @@ describe Watir::Element do
|
|
37
37
|
button = browser.button(:id => "remove-button")
|
38
38
|
element = browser.div(:id => "text")
|
39
39
|
|
40
|
-
element.
|
40
|
+
expect(element).to exist
|
41
41
|
button.click
|
42
|
-
element.
|
42
|
+
expect(element).to_not exist
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -52,9 +52,9 @@ describe Watir::Element do
|
|
52
52
|
browser.goto WatirSpec.url_for('hover.html', :needs_server => true)
|
53
53
|
link = browser.a
|
54
54
|
|
55
|
-
link.style("font-size").
|
55
|
+
expect(link.style("font-size")).to eq "10px"
|
56
56
|
link.hover
|
57
|
-
link.style("font-size").
|
57
|
+
expect(link.style("font-size")).to eq "20px"
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
data/spec/implementation.rb
CHANGED
@@ -107,7 +107,7 @@ class ImplementationConfig
|
|
107
107
|
|
108
108
|
def chrome_args
|
109
109
|
opts = {
|
110
|
-
:
|
110
|
+
:args => ["--disable-translate"],
|
111
111
|
:native_events => native_events?
|
112
112
|
}
|
113
113
|
|
@@ -123,11 +123,15 @@ class ImplementationConfig
|
|
123
123
|
Selenium::WebDriver::Chrome.path = path
|
124
124
|
end
|
125
125
|
|
126
|
+
if ENV['TRAVIS']
|
127
|
+
opts[:args] << "--no-sandbox" # https://github.com/travis-ci/travis-ci/issues/938
|
128
|
+
end
|
129
|
+
|
126
130
|
[:chrome, opts]
|
127
131
|
end
|
128
132
|
|
129
133
|
def remote_args
|
130
|
-
[:remote, {:url => ENV["WATIR_WEBDRIVER_REMOTE_URL"] || "http://127.0.0.1:8080"}]
|
134
|
+
[:remote, {:url => ENV["WATIR_WEBDRIVER_REMOTE_URL"] || "http://127.0.0.1:8080"}]
|
131
135
|
end
|
132
136
|
|
133
137
|
def add_html_routes
|
data/spec/input_spec.rb
CHANGED
@@ -9,12 +9,12 @@ describe Watir::Input do
|
|
9
9
|
describe "#to_subtype" do
|
10
10
|
it "returns a CheckBox instance" do
|
11
11
|
e = browser.input(:xpath => "//input[@type='checkbox']").to_subtype
|
12
|
-
e.
|
12
|
+
expect(e).to be_kind_of(Watir::CheckBox)
|
13
13
|
end
|
14
14
|
|
15
15
|
it "returns a Radio instance" do
|
16
16
|
e = browser.input(:xpath => "//input[@type='radio']").to_subtype
|
17
|
-
e.
|
17
|
+
expect(e).to be_kind_of(Watir::Radio)
|
18
18
|
end
|
19
19
|
|
20
20
|
it "returns a Button instance" do
|
@@ -23,17 +23,23 @@ describe Watir::Input do
|
|
23
23
|
browser.input(:xpath => "//input[@type='submit']").to_subtype
|
24
24
|
]
|
25
25
|
|
26
|
-
es.all? { |e| e.
|
26
|
+
es.all? { |e| expect(e).to be_kind_of(Watir::Button) }
|
27
27
|
end
|
28
28
|
|
29
29
|
it "returns a TextField instance" do
|
30
30
|
e = browser.input(:xpath => "//input[@type='text']").to_subtype
|
31
|
-
e.
|
31
|
+
expect(e).to be_kind_of(Watir::TextField)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "returns a TextField instance" do
|
35
35
|
e = browser.input(:xpath => "//input[@type='file']").to_subtype
|
36
|
-
e.
|
36
|
+
expect(e).to be_kind_of(Watir::FileField)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#type" do
|
41
|
+
it "returns an email type" do
|
42
|
+
expect(browser.input(:name => "html5_email").type).to eq 'email'
|
37
43
|
end
|
38
44
|
end
|
39
45
|
end
|