capybara 0.3.0 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/Manifest.txt +4 -0
  2. data/README.rdoc +45 -5
  3. data/lib/capybara.rb +11 -4
  4. data/lib/capybara/driver/base.rb +3 -0
  5. data/lib/capybara/driver/celerity_driver.rb +44 -9
  6. data/lib/capybara/driver/rack_test_driver.rb +80 -16
  7. data/lib/capybara/driver/selenium_driver.rb +41 -9
  8. data/lib/capybara/dsl.rb +4 -10
  9. data/lib/capybara/node.rb +8 -0
  10. data/lib/capybara/rails.rb +8 -2
  11. data/lib/capybara/save_and_open_page.rb +5 -1
  12. data/lib/capybara/searchable.rb +17 -9
  13. data/lib/capybara/server.rb +35 -23
  14. data/lib/capybara/session.rb +91 -22
  15. data/lib/capybara/xpath.rb +66 -27
  16. data/spec/driver/celerity_driver_spec.rb +2 -2
  17. data/spec/driver/culerity_driver_spec.rb +1 -2
  18. data/spec/driver/rack_test_driver_spec.rb +0 -1
  19. data/spec/driver/remote_culerity_driver_spec.rb +9 -5
  20. data/spec/driver/selenium_driver_spec.rb +0 -1
  21. data/spec/drivers_spec.rb +24 -32
  22. data/spec/dsl/all_spec.rb +56 -25
  23. data/spec/dsl/attach_file_spec.rb +49 -51
  24. data/spec/dsl/check_spec.rb +12 -1
  25. data/spec/dsl/choose_spec.rb +19 -21
  26. data/spec/dsl/click_button_spec.rb +140 -87
  27. data/spec/dsl/click_link_spec.rb +88 -68
  28. data/spec/dsl/click_spec.rb +20 -22
  29. data/spec/dsl/current_url_spec.rb +6 -8
  30. data/spec/dsl/fill_in_spec.rb +75 -67
  31. data/spec/dsl/find_button_spec.rb +12 -14
  32. data/spec/dsl/find_by_id_spec.rb +16 -0
  33. data/spec/dsl/find_field_spec.rb +17 -19
  34. data/spec/dsl/find_link_spec.rb +13 -15
  35. data/spec/dsl/find_spec.rb +44 -23
  36. data/spec/dsl/has_button_spec.rb +32 -0
  37. data/spec/dsl/has_content_spec.rb +79 -81
  38. data/spec/dsl/has_css_spec.rb +81 -83
  39. data/spec/dsl/has_field_spec.rb +96 -0
  40. data/spec/dsl/has_link_spec.rb +33 -0
  41. data/spec/dsl/has_xpath_spec.rb +97 -89
  42. data/spec/dsl/locate_spec.rb +47 -26
  43. data/spec/dsl/select_spec.rb +61 -17
  44. data/spec/dsl/uncheck_spec.rb +17 -25
  45. data/spec/dsl/within_spec.rb +112 -104
  46. data/spec/public/test.js +3 -0
  47. data/spec/searchable_spec.rb +1 -1
  48. data/spec/server_spec.rb +7 -7
  49. data/spec/session/celerity_session_spec.rb +2 -2
  50. data/spec/session/culerity_session_spec.rb +1 -1
  51. data/spec/session_spec.rb +7 -0
  52. data/spec/session_with_javascript_support_spec.rb +139 -120
  53. data/spec/spec_helper.rb +7 -2
  54. data/spec/test_app.rb +8 -4
  55. data/spec/views/form.erb +50 -2
  56. data/spec/views/tables.erb +61 -1
  57. data/spec/views/with_html.erb +8 -2
  58. data/spec/views/with_js.erb +4 -0
  59. data/spec/xpath_spec.rb +17 -0
  60. metadata +6 -2
@@ -0,0 +1,96 @@
1
+ shared_examples_for "has_field" do
2
+ describe '#has_field' do
3
+ before { @session.visit('/form') }
4
+
5
+ it "should be true if the field is on the page" do
6
+ @session.should have_field('Dog')
7
+ @session.should have_field('form_description')
8
+ @session.should have_field('Region')
9
+ end
10
+
11
+ it "should be false if the field is not on the page" do
12
+ @session.should_not have_field('Monkey')
13
+ end
14
+
15
+ context 'with value' do
16
+ it "should be true if a field with the given value is on the page" do
17
+ @session.should have_field('First Name', :with => 'John')
18
+ @session.should have_field('Phone', :with => '+1 555 7021')
19
+ @session.should have_field('Street', :with => 'Sesame street 66')
20
+ @session.should have_field('Description', :with => 'Descriptive text goes here')
21
+ end
22
+
23
+ it "should be false if the given field is not on the page" do
24
+ @session.should_not have_field('First Name', :with => 'Peter')
25
+ @session.should_not have_field('Wrong Name', :with => 'John')
26
+ @session.should_not have_field('Description', :with => 'Monkey')
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#has_no_field' do
32
+ before { @session.visit('/form') }
33
+
34
+ it "should be false if the field is on the page" do
35
+ @session.should_not have_no_field('Dog')
36
+ @session.should_not have_no_field('form_description')
37
+ @session.should_not have_no_field('Region')
38
+ end
39
+
40
+ it "should be true if the field is not on the page" do
41
+ @session.should have_no_field('Monkey')
42
+ end
43
+
44
+ context 'with value' do
45
+ it "should be flase if a field with the given value is on the page" do
46
+ @session.should_not have_no_field('First Name', :with => 'John')
47
+ @session.should_not have_no_field('Phone', :with => '+1 555 7021')
48
+ @session.should_not have_no_field('Street', :with => 'Sesame street 66')
49
+ @session.should_not have_no_field('Description', :with => 'Descriptive text goes here')
50
+ end
51
+
52
+ it "should be true if the given field is not on the page" do
53
+ @session.should have_no_field('First Name', :with => 'Peter')
54
+ @session.should have_no_field('Wrong Name', :with => 'John')
55
+ @session.should have_no_field('Description', :with => 'Monkey')
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '#has_checked_field?' do
61
+ before { @session.visit('/form') }
62
+
63
+ it "should be true if a checked field is on the page" do
64
+ @session.should have_checked_field('gender_female')
65
+ @session.should have_checked_field('Hamster')
66
+ end
67
+
68
+ it "should be false if an unchecked field is on the page" do
69
+ @session.should_not have_checked_field('form_pets_cat')
70
+ @session.should_not have_checked_field('Male')
71
+ end
72
+
73
+ it "should be false if no field is on the page" do
74
+ @session.should_not have_checked_field('Does Not Exist')
75
+ end
76
+ end
77
+
78
+ describe '#has_unchecked_field?' do
79
+ before { @session.visit('/form') }
80
+
81
+ it "should be false if a checked field is on the page" do
82
+ @session.should_not have_unchecked_field('gender_female')
83
+ @session.should_not have_unchecked_field('Hamster')
84
+ end
85
+
86
+ it "should be true if an unchecked field is on the page" do
87
+ @session.should have_unchecked_field('form_pets_cat')
88
+ @session.should have_unchecked_field('Male')
89
+ end
90
+
91
+ it "should be false if no field is on the page" do
92
+ @session.should_not have_unchecked_field('Does Not Exist')
93
+ end
94
+ end
95
+ end
96
+
@@ -0,0 +1,33 @@
1
+ shared_examples_for "has_link" do
2
+
3
+ describe '#has_link?' do
4
+ before do
5
+ @session.visit('/with_html')
6
+ end
7
+
8
+ it "should be true if the given link is on the page" do
9
+ @session.should have_link('foo')
10
+ @session.should have_link('awesome title')
11
+ end
12
+
13
+ it "should be false if the given link is not on the page" do
14
+ @session.should_not have_link('monkey')
15
+ end
16
+ end
17
+
18
+ describe '#has_no_link?' do
19
+ before do
20
+ @session.visit('/with_html')
21
+ end
22
+
23
+ it "should be false if the given link is on the page" do
24
+ @session.should_not have_no_link('foo')
25
+ @session.should_not have_no_link('awesome title')
26
+ end
27
+
28
+ it "should be true if the given link is not on the page" do
29
+ @session.should have_no_link('monkey')
30
+ end
31
+ end
32
+ end
33
+
@@ -1,115 +1,123 @@
1
- module HasXpathSpec
2
- shared_examples_for "has_xpath" do
3
- describe '#has_xpath?' do
4
- before do
5
- @session.visit('/with_html')
6
- end
1
+ shared_examples_for "has_xpath" do
2
+ describe '#has_xpath?' do
3
+ before do
4
+ @session.visit('/with_html')
5
+ end
6
+
7
+ it "should be true if the given selector is on the page" do
8
+ @session.should have_xpath("//p")
9
+ @session.should have_xpath("//p//a[@id='foo']")
10
+ @session.should have_xpath("//p[contains(.,'est')]")
11
+ end
12
+
13
+ it "should be false if the given selector is not on the page" do
14
+ @session.should_not have_xpath("//abbr")
15
+ @session.should_not have_xpath("//p//a[@id='doesnotexist']")
16
+ @session.should_not have_xpath("//p[contains(.,'thisstringisnotonpage')]")
17
+ end
7
18
 
8
- it "should be true if the given selector is on the page" do
9
- @session.should have_xpath("//p")
10
- @session.should have_xpath("//p//a[@id='foo']")
11
- @session.should have_xpath("//p[contains(.,'est')]")
19
+ it "should use xpath even if default selector is CSS" do
20
+ Capybara.default_selector = :css
21
+ @session.should_not have_xpath("//p//a[@id='doesnotexist']")
22
+ end
23
+
24
+ it "should respect scopes" do
25
+ @session.within "//p[@id='first']" do
26
+ @session.should have_xpath("//a[@id='foo']")
27
+ @session.should_not have_xpath("//a[@id='red']")
12
28
  end
29
+ end
13
30
 
14
- it "should be false if the given selector is not on the page" do
15
- @session.should_not have_xpath("//abbr")
16
- @session.should_not have_xpath("//p//a[@id='doesnotexist']")
17
- @session.should_not have_xpath("//p[contains(.,'thisstringisnotonpage')]")
31
+ context "with count" do
32
+ it "should be true if the content is on the page the given number of times" do
33
+ @session.should have_xpath("//p", :count => 3)
34
+ @session.should have_xpath("//p//a[@id='foo']", :count => 1)
35
+ @session.should have_xpath("//p[contains(.,'est')]", :count => 1)
18
36
  end
19
37
 
20
- it "should respect scopes" do
21
- @session.within "//p[@id='first']" do
22
- @session.should have_xpath("//a[@id='foo']")
23
- @session.should_not have_xpath("//a[@id='red']")
24
- end
38
+ it "should be false if the content is on the page the given number of times" do
39
+ @session.should_not have_xpath("//p", :count => 6)
40
+ @session.should_not have_xpath("//p//a[@id='foo']", :count => 2)
41
+ @session.should_not have_xpath("//p[contains(.,'est')]", :count => 5)
25
42
  end
26
43
 
27
- context "with count" do
28
- it "should be true if the content is on the page the given number of times" do
29
- @session.should have_xpath("//p", :count => 3)
30
- @session.should have_xpath("//p//a[@id='foo']", :count => 1)
31
- @session.should have_xpath("//p[contains(.,'est')]", :count => 1)
32
- end
33
-
34
- it "should be false if the content is on the page the given number of times" do
35
- @session.should_not have_xpath("//p", :count => 6)
36
- @session.should_not have_xpath("//p//a[@id='foo']", :count => 2)
37
- @session.should_not have_xpath("//p[contains(.,'est')]", :count => 5)
38
- end
39
-
40
- it "should be false if the content isn't on the page at all" do
41
- @session.should_not have_xpath("//abbr", :count => 2)
42
- @session.should_not have_xpath("//p//a[@id='doesnotexist']", :count => 1)
43
- end
44
+ it "should be false if the content isn't on the page at all" do
45
+ @session.should_not have_xpath("//abbr", :count => 2)
46
+ @session.should_not have_xpath("//p//a[@id='doesnotexist']", :count => 1)
44
47
  end
48
+ end
45
49
 
46
- context "with text" do
47
- it "should discard all matches where the given string is not contained" do
48
- @session.should have_xpath("//p//a", :text => "Redirect", :count => 1)
49
- @session.should_not have_xpath("//p", :text => "Doesnotexist")
50
- end
50
+ context "with text" do
51
+ it "should discard all matches where the given string is not contained" do
52
+ @session.should have_xpath("//p//a", :text => "Redirect", :count => 1)
53
+ @session.should_not have_xpath("//p", :text => "Doesnotexist")
54
+ end
51
55
 
52
- it "should discard all matches where the given regexp is not matched" do
53
- @session.should have_xpath("//p//a", :text => /re[dab]i/i, :count => 1)
54
- @session.should_not have_xpath("//p//a", :text => /Red$/)
55
- end
56
+ it "should discard all matches where the given regexp is not matched" do
57
+ @session.should have_xpath("//p//a", :text => /re[dab]i/i, :count => 1)
58
+ @session.should_not have_xpath("//p//a", :text => /Red$/)
56
59
  end
57
60
  end
61
+ end
58
62
 
59
- describe '#has_no_xpath?' do
60
- before do
61
- @session.visit('/with_html')
62
- end
63
+ describe '#has_no_xpath?' do
64
+ before do
65
+ @session.visit('/with_html')
66
+ end
67
+
68
+ it "should be false if the given selector is on the page" do
69
+ @session.should_not have_no_xpath("//p")
70
+ @session.should_not have_no_xpath("//p//a[@id='foo']")
71
+ @session.should_not have_no_xpath("//p[contains(.,'est')]")
72
+ end
73
+
74
+ it "should be true if the given selector is not on the page" do
75
+ @session.should have_no_xpath("//abbr")
76
+ @session.should have_no_xpath("//p//a[@id='doesnotexist']")
77
+ @session.should have_no_xpath("//p[contains(.,'thisstringisnotonpage')]")
78
+ end
63
79
 
64
- it "should be false if the given selector is on the page" do
65
- @session.should_not have_no_xpath("//p")
66
- @session.should_not have_no_xpath("//p//a[@id='foo']")
67
- @session.should_not have_no_xpath("//p[contains(.,'est')]")
80
+ it "should use xpath even if default selector is CSS" do
81
+ Capybara.default_selector = :css
82
+ @session.should have_no_xpath("//p//a[@id='doesnotexist']")
83
+ end
84
+
85
+ it "should respect scopes" do
86
+ @session.within "//p[@id='first']" do
87
+ @session.should_not have_no_xpath("//a[@id='foo']")
88
+ @session.should have_no_xpath("//a[@id='red']")
68
89
  end
90
+ end
69
91
 
70
- it "should be true if the given selector is not on the page" do
71
- @session.should have_no_xpath("//abbr")
72
- @session.should have_no_xpath("//p//a[@id='doesnotexist']")
73
- @session.should have_no_xpath("//p[contains(.,'thisstringisnotonpage')]")
92
+ context "with count" do
93
+ it "should be false if the content is on the page the given number of times" do
94
+ @session.should_not have_no_xpath("//p", :count => 3)
95
+ @session.should_not have_no_xpath("//p//a[@id='foo']", :count => 1)
96
+ @session.should_not have_no_xpath("//p[contains(.,'est')]", :count => 1)
74
97
  end
75
98
 
76
- it "should respect scopes" do
77
- @session.within "//p[@id='first']" do
78
- @session.should_not have_no_xpath("//a[@id='foo']")
79
- @session.should have_no_xpath("//a[@id='red']")
80
- end
99
+ it "should be true if the content is on the page the wrong number of times" do
100
+ @session.should have_no_xpath("//p", :count => 6)
101
+ @session.should have_no_xpath("//p//a[@id='foo']", :count => 2)
102
+ @session.should have_no_xpath("//p[contains(.,'est')]", :count => 5)
81
103
  end
82
104
 
83
- context "with count" do
84
- it "should be false if the content is on the page the given number of times" do
85
- @session.should_not have_no_xpath("//p", :count => 3)
86
- @session.should_not have_no_xpath("//p//a[@id='foo']", :count => 1)
87
- @session.should_not have_no_xpath("//p[contains(.,'est')]", :count => 1)
88
- end
89
-
90
- it "should be true if the content is on the page the wrong number of times" do
91
- @session.should have_no_xpath("//p", :count => 6)
92
- @session.should have_no_xpath("//p//a[@id='foo']", :count => 2)
93
- @session.should have_no_xpath("//p[contains(.,'est')]", :count => 5)
94
- end
95
-
96
- it "should be true if the content isn't on the page at all" do
97
- @session.should have_no_xpath("//abbr", :count => 2)
98
- @session.should have_no_xpath("//p//a[@id='doesnotexist']", :count => 1)
99
- end
105
+ it "should be true if the content isn't on the page at all" do
106
+ @session.should have_no_xpath("//abbr", :count => 2)
107
+ @session.should have_no_xpath("//p//a[@id='doesnotexist']", :count => 1)
100
108
  end
109
+ end
101
110
 
102
- context "with text" do
103
- it "should discard all matches where the given string is contained" do
104
- @session.should_not have_no_xpath("//p//a", :text => "Redirect", :count => 1)
105
- @session.should have_no_xpath("//p", :text => "Doesnotexist")
106
- end
111
+ context "with text" do
112
+ it "should discard all matches where the given string is contained" do
113
+ @session.should_not have_no_xpath("//p//a", :text => "Redirect", :count => 1)
114
+ @session.should have_no_xpath("//p", :text => "Doesnotexist")
115
+ end
107
116
 
108
- it "should discard all matches where the given regexp is matched" do
109
- @session.should_not have_no_xpath("//p//a", :text => /re[dab]i/i, :count => 1)
110
- @session.should have_no_xpath("//p//a", :text => /Red$/)
111
- end
117
+ it "should discard all matches where the given regexp is matched" do
118
+ @session.should_not have_no_xpath("//p//a", :text => /re[dab]i/i, :count => 1)
119
+ @session.should have_no_xpath("//p//a", :text => /Red$/)
112
120
  end
113
121
  end
114
122
  end
115
- end
123
+ end
@@ -1,38 +1,59 @@
1
- module LocateSpec
2
- shared_examples_for "locate" do
3
- describe '#locate' do
4
- before do
5
- @session.visit('/with_html')
6
- end
1
+ shared_examples_for "locate" do
2
+ describe '#locate' do
3
+ before do
4
+ @session.visit('/with_html')
5
+ end
6
+
7
+ it "should find the first element using the given locator" do
8
+ @session.locate('//h1').text.should == 'This is a test'
9
+ @session.locate("//input[@id='test_field']")[:value].should == 'monkey'
10
+ end
7
11
 
12
+ context "with css selectors" do
8
13
  it "should find the first element using the given locator" do
9
- @session.locate('//h1').text.should == 'This is a test'
10
- @session.locate("//input[@id='test_field']")[:value].should == 'monkey'
14
+ @session.locate(:css, 'h1').text.should == 'This is a test'
15
+ @session.locate(:css, "input[id='test_field']")[:value].should == 'monkey'
11
16
  end
17
+ end
12
18
 
13
- it "should raise ElementNotFound with specified fail message if nothing was found" do
14
- running do
15
- @session.locate('//div[@id="nosuchthing"]', 'arghh').should be_nil
16
- end.should raise_error(Capybara::ElementNotFound, "arghh")
19
+ context "with xpath selectors" do
20
+ it "should find the first element using the given locator" do
21
+ @session.locate(:xpath, '//h1').text.should == 'This is a test'
22
+ @session.locate(:xpath, "//input[@id='test_field']")[:value].should == 'monkey'
17
23
  end
24
+ end
18
25
 
19
- it "should accept an XPath instance and respect the order of paths" do
20
- @session.visit('/form')
21
- @xpath = Capybara::XPath.text_field('Name')
22
- @session.locate(@xpath).value.should == 'John Smith'
26
+ context "with css as default selector" do
27
+ before { Capybara.default_selector = :css }
28
+ it "should find the first element using the given locator" do
29
+ @session.locate('h1').text.should == 'This is a test'
30
+ @session.locate("input[id='test_field']")[:value].should == 'monkey'
23
31
  end
32
+ after { Capybara.default_selector = :xpath }
33
+ end
34
+
35
+ it "should raise ElementNotFound with specified fail message if nothing was found" do
36
+ running do
37
+ @session.locate(:xpath, '//div[@id="nosuchthing"]', 'arghh').should be_nil
38
+ end.should raise_error(Capybara::ElementNotFound, "arghh")
39
+ end
40
+
41
+ it "should accept an XPath instance and respect the order of paths" do
42
+ @session.visit('/form')
43
+ @xpath = Capybara::XPath.text_field('Name')
44
+ @session.locate(@xpath).value.should == 'John Smith'
45
+ end
24
46
 
25
- context "within a scope" do
26
- before do
27
- @session.visit('/with_scope')
28
- end
47
+ context "within a scope" do
48
+ before do
49
+ @session.visit('/with_scope')
50
+ end
29
51
 
30
- it "should find the first element using the given locator" do
31
- @session.within(:xpath, "//div[@id='for_bar']") do
32
- @session.locate('//li').text.should =~ /With Simple HTML/
33
- end
34
- end
52
+ it "should find the first element using the given locator" do
53
+ @session.within(:xpath, "//div[@id='for_bar']") do
54
+ @session.locate('//li').text.should =~ /With Simple HTML/
55
+ end
35
56
  end
36
57
  end
37
58
  end
38
- end
59
+ end
@@ -1,27 +1,71 @@
1
- module SelectSpec
2
- shared_examples_for "select" do
3
- describe "#select" do
4
- before do
5
- @session.visit('/form')
1
+ shared_examples_for "select" do
2
+ describe "#select" do
3
+ before do
4
+ @session.visit('/form')
5
+ end
6
+
7
+ it "should return value of the first option" do
8
+ @session.find_field('Title').value.should == 'Mrs'
9
+ end
10
+
11
+ it "should return value of the selected option" do
12
+ @session.select("Miss", :from => 'Title')
13
+ @session.find_field('Title').value.should == 'Miss'
14
+ end
15
+
16
+ it "should select an option from a select box by id" do
17
+ @session.select("Finish", :from => 'form_locale')
18
+ @session.click_button('awesome')
19
+ extract_results(@session)['locale'].should == 'fi'
20
+ end
21
+
22
+ it "should select an option from a select box by label" do
23
+ @session.select("Finish", :from => 'Locale')
24
+ @session.click_button('awesome')
25
+ extract_results(@session)['locale'].should == 'fi'
26
+ end
27
+
28
+ it "should favour exact matches to option labels" do
29
+ @session.select("Mr", :from => 'Title')
30
+ @session.click_button('awesome')
31
+ extract_results(@session)['title'].should == 'Mr'
32
+ end
33
+
34
+ context "with a locator that doesn't exist" do
35
+ it "should raise an error" do
36
+ running { @session.select('foo', :from => 'does not exist') }.should raise_error(Capybara::ElementNotFound)
6
37
  end
38
+ end
7
39
 
8
- it "should select an option from a select box by id" do
9
- @session.select("Finish", :from => 'form_locale')
10
- @session.click_button('awesome')
11
- extract_results(@session)['locale'].should == 'fi'
40
+ context "with an option that doesn't exist" do
41
+ it "should raise an error" do
42
+ running { @session.select('Does not Exist', :from => 'form_locale') }.should raise_error(Capybara::OptionNotFound)
12
43
  end
44
+ end
13
45
 
14
- it "should select an option from a select box by label" do
15
- @session.select("Finish", :from => 'Locale')
46
+ context "with multiple select" do
47
+ it "should return an empty value" do
48
+ @session.find_field('Language').value.should == []
49
+ end
50
+
51
+ it "should return value of the selected options" do
52
+ @session.select("Ruby", :from => 'Language')
53
+ @session.select("Javascript", :from => 'Language')
54
+ @session.find_field('Language').value.should include('Ruby', 'Javascript')
55
+ end
56
+
57
+ it "should select one option" do
58
+ @session.select("Ruby", :from => 'Language')
16
59
  @session.click_button('awesome')
17
- extract_results(@session)['locale'].should == 'fi'
60
+ extract_results(@session)['languages'].should == ['Ruby']
18
61
  end
19
62
 
20
- context "with a locator that doesn't exist" do
21
- it "should raise an error" do
22
- running { @session.select('foo', :from => 'does not exist') }.should raise_error(Capybara::ElementNotFound)
23
- end
63
+ it "should select multiple options" do
64
+ @session.select("Ruby", :from => 'Language')
65
+ @session.select("Javascript", :from => 'Language')
66
+ @session.click_button('awesome')
67
+ extract_results(@session)['languages'].should include('Ruby', 'Javascript')
24
68
  end
25
69
  end
26
70
  end
27
- end
71
+ end