cf 1.1.3.rc1 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/lib/cf/cli.rb +2 -7
  2. data/lib/cf/cli/organization/delete.rb +4 -6
  3. data/lib/cf/cli/service/create.rb +23 -17
  4. data/lib/cf/cli/space/create.rb +43 -41
  5. data/lib/cf/cli/space/space.rb +49 -46
  6. data/lib/cf/version.rb +1 -1
  7. data/lib/console/console.rb +1 -1
  8. data/spec/cf/cli/app/delete_spec.rb +16 -28
  9. data/spec/cf/cli/app/instances_spec.rb +4 -5
  10. data/spec/cf/cli/app/push/create_spec.rb +362 -373
  11. data/spec/cf/cli/app/push_spec.rb +216 -215
  12. data/spec/cf/cli/app/rename_spec.rb +28 -31
  13. data/spec/cf/cli/app/scale_spec.rb +44 -41
  14. data/spec/cf/cli/app/start_spec.rb +194 -193
  15. data/spec/cf/cli/app/stats_spec.rb +55 -56
  16. data/spec/cf/cli/domain/map_spec.rb +105 -102
  17. data/spec/cf/cli/domain/unmap_spec.rb +60 -56
  18. data/spec/cf/cli/organization/delete_spec.rb +85 -84
  19. data/spec/cf/cli/organization/orgs_spec.rb +80 -83
  20. data/spec/cf/cli/organization/rename_spec.rb +90 -89
  21. data/spec/cf/cli/populators/organization_spec.rb +117 -119
  22. data/spec/cf/cli/populators/space_spec.rb +107 -108
  23. data/spec/cf/cli/populators/target_spec.rb +17 -12
  24. data/spec/cf/cli/route/delete_spec.rb +4 -4
  25. data/spec/cf/cli/route/map_spec.rb +106 -102
  26. data/spec/cf/cli/route/unmap_spec.rb +5 -5
  27. data/spec/cf/cli/service/create_spec.rb +74 -46
  28. data/spec/cf/cli/service/rename_spec.rb +29 -33
  29. data/spec/cf/cli/service/services_spec.rb +48 -48
  30. data/spec/cf/cli/space/base_spec.rb +39 -32
  31. data/spec/cf/cli/space/create_spec.rb +52 -53
  32. data/spec/cf/cli/space/delete_spec.rb +84 -85
  33. data/spec/cf/cli/space/rename_spec.rb +93 -94
  34. data/spec/cf/cli/space/space_spec.rb +60 -60
  35. data/spec/cf/cli/space/spaces_spec.rb +75 -80
  36. data/spec/cf/cli/space/switch_space_spec.rb +45 -48
  37. data/spec/cf/cli/start/info_spec.rb +4 -6
  38. data/spec/cf/cli/start/login_spec.rb +18 -20
  39. data/spec/cf/cli/start/logout_spec.rb +36 -37
  40. data/spec/cf/cli/start/target_spec.rb +86 -89
  41. data/spec/cf/cli/user/create_spec.rb +83 -84
  42. data/spec/cf/cli/user/passwd_spec.rb +87 -86
  43. data/spec/cf/cli/user/register_spec.rb +109 -108
  44. data/spec/cf/cli_spec.rb +305 -310
  45. data/spec/console/console_spec.rb +58 -58
  46. data/spec/factories/cfoundry/v2/domain_factory.rb +8 -0
  47. data/spec/factories/cfoundry/v2/route_factory.rb +8 -0
  48. data/spec/factories/cfoundry/v2/user_factory.rb +7 -0
  49. data/spec/features/org_spec.rb +11 -11
  50. data/spec/manifests/manifests_spec.rb +21 -21
  51. data/spec/manifests/plugin_spec.rb +34 -34
  52. data/spec/spec_helper.rb +1 -2
  53. data/spec/support/cli_helper.rb +5 -14
  54. data/spec/support/factory_girl.rb +6 -0
  55. data/spec/support/interact_helper.rb +5 -15
  56. data/spec/support/shared_examples/errors.rb +1 -1
  57. data/spec/tunnel/plugin_spec.rb +2 -2
  58. data/spec/tunnel/tunnel_spec.rb +5 -5
  59. metadata +36 -28
@@ -1,92 +1,93 @@
1
- require 'spec_helper'
2
- require "cf/cli/organization/delete"
1
+ require "spec_helper"
3
2
 
4
- describe CF::Organization::Delete do
5
- describe 'metadata' do
6
- let(:command) { Mothership.commands[:delete_org] }
3
+ module CF
4
+ module Organization
5
+ describe Delete do
6
+ describe "metadata" do
7
+ let(:command) { Mothership.commands[:delete_org] }
7
8
 
8
- describe 'command' do
9
- subject { command }
10
- it { expect(Mothership::Help.group(:organizations)).to include(subject) }
11
- end
12
-
13
- include_examples 'inputs must have descriptions'
14
- end
15
-
16
- describe "running the command" do
17
- let(:organization) { fake(:organization, :name => "MyOrg") }
18
- let(:organizations) { [organization] }
19
-
20
- let(:client) { fake_client(:current_organization => organization, :organizations => organizations) }
21
-
22
- subject { capture_output { cf %W[delete-org MyOrg --quiet --force] } }
23
-
24
- before do
25
- any_instance_of described_class do |cli|
26
- stub(cli).client { client }
27
-
28
- stub(cli).check_logged_in
29
- stub(cli).check_target
30
- any_instance_of(CF::Populators::Organization, :populate_and_save! => organization)
31
- end
32
- stub(organization).delete!
33
- end
34
-
35
- context "without the force parameter" do
36
- subject { cf %W[delete-org MyOrg --quiet] }
37
- it "confirms deletion of the organization and deletes it" do
38
- mock(organization).delete!
39
- mock_ask("Really delete #{organization.name}?", {:default => false}) { true }
40
-
41
- subject
42
- end
43
- end
44
-
45
- context "when deleting the last organization" do
46
- it "warns the user what they've done" do
47
- subject
48
- expect(output).to say("There are no longer any organizations.")
49
- end
50
- end
51
-
52
- context "when deleting the current organization" do
53
- let(:organizations) { [organization, fake(:organization)] }
54
- it "invalidates the old target / client" do
55
- any_instance_of(described_class) { |cli| mock(cli).invalidate_client }
56
- subject
57
- end
9
+ describe "command" do
10
+ subject { command }
11
+ it { expect(Mothership::Help.group(:organizations)).to include(subject) }
12
+ end
58
13
 
59
- it "invokes the target command" do
60
- mock_invoke :target
61
- subject
14
+ include_examples "inputs must have descriptions"
62
15
  end
63
- end
64
-
65
- context "when an org fails to delete" do
66
- before do
67
- stub(organization).delete! { raise CFoundry::AssociationNotEmpty.new("We don't delete children.", 10006) }
68
- subject
69
- end
70
-
71
- it "shows the error message" do
72
- expect(output).to say "We don't delete children."
73
- end
74
-
75
- it "informs the user of how to recursively delete" do
76
- expect(output).to say "If you want to delete the organization along with all dependent objects, rerun the command with the '--recursive' flag."
77
- end
78
-
79
- it "returns a non-zero exit code" do
80
- @status.should_not == 0
81
- end
82
- end
83
-
84
- context "when deleting with --recursive" do
85
- subject { cf %W[delete-org MyOrg --recursive --force] }
86
16
 
87
- it "sends recursive true in its delete request" do
88
- mock(organization).delete!(:recursive => true)
89
- subject
17
+ describe "running the command" do
18
+ let(:organization) { fake(:organization, :name => "MyOrg") }
19
+ let(:organizations) { [organization] }
20
+
21
+ let(:client) { fake_client(:current_organization => organization, :organizations => organizations) }
22
+
23
+ subject { capture_output { cf %W[delete-org MyOrg --quiet --force] } }
24
+
25
+ before do
26
+ described_class.any_instance.stub(:client) { client }
27
+ described_class.any_instance.stub(:check_logged_in)
28
+ described_class.any_instance.stub(:check_target)
29
+ CF::Populators::Organization.any_instance.stub(:populate_and_save!).and_return(organization)
30
+ organization.stub(:delete!).and_return(true)
31
+ end
32
+
33
+ context "without the force parameter" do
34
+ subject { cf %W[delete-org MyOrg --quiet] }
35
+
36
+ it "confirms deletion of the organization and deletes it" do
37
+ organization.should_receive(:delete!).with(:recursive => false) { true }
38
+ mock_ask("Really delete #{organization.name}?", {:default => false}) { true }
39
+
40
+ subject
41
+ end
42
+ end
43
+
44
+ context "when deleting the last organization" do
45
+ it "warns the user what they've done" do
46
+ subject
47
+ expect(output).to say("There are no longer any organizations.")
48
+ end
49
+ end
50
+
51
+ context "when deleting the current organization" do
52
+ let(:organizations) { [organization, fake(:organization)] }
53
+ it "invalidates the old target / client" do
54
+ described_class.any_instance.should_receive(:invalidate_client)
55
+ subject
56
+ end
57
+
58
+ it "invokes the target command" do
59
+ mock_invoke :target
60
+ subject
61
+ end
62
+ end
63
+
64
+ context "when an org fails to delete" do
65
+ before do
66
+ organization.stub(:delete!) { raise CFoundry::AssociationNotEmpty.new("We don't delete children.", 10006) }
67
+ subject
68
+ end
69
+
70
+ it "shows the error message" do
71
+ expect(output).to say "We don't delete children."
72
+ end
73
+
74
+ it "informs the user of how to recursively delete" do
75
+ expect(output).to say "If you want to delete the organization along with all dependent objects, rerun the command with the '--recursive' flag."
76
+ end
77
+
78
+ it "returns a non-zero exit code" do
79
+ @status.should_not == 0
80
+ end
81
+ end
82
+
83
+ context "when deleting with --recursive" do
84
+ subject { cf %W[delete-org MyOrg --recursive --force] }
85
+
86
+ it "sends recursive true in its delete request" do
87
+ organization.should_receive(:delete!).with(:recursive => true)
88
+ subject
89
+ end
90
+ end
90
91
  end
91
92
  end
92
93
  end
@@ -1,107 +1,104 @@
1
- require 'spec_helper'
2
- require 'stringio'
3
-
4
- describe CF::Organization::Orgs do
5
- let(:global) { { :color => false } }
6
- let(:inputs) { {} }
7
- let(:given) { {} }
8
- let(:output) { StringIO.new }
9
-
10
- let(:client) { fake_client(:organizations => organizations) }
11
- let!(:org_1) { fake(:organization, :name => "bb_second", :spaces => fake_list(:space, 2), :domains => [fake(:domain)]) }
12
- let!(:org_2) { fake(:organization, :name => "aa_first", :spaces => [fake(:space)], :domains => fake_list(:domain, 3)) }
13
- let!(:org_3) { fake(:organization, :name => "cc_last", :spaces => fake_list(:space, 2), :domains => fake_list(:domain, 2)) }
14
- let(:organizations) { [org_1, org_2, org_3]}
15
-
16
- before do
17
- any_instance_of(CF::CLI) do |cli|
18
- stub(cli).client { client }
19
- stub(cli).precondition { nil }
20
- end
21
- end
22
-
23
- subject do
24
- capture_output { Mothership.new.invoke(:orgs, inputs, given, global) }
25
- end
26
-
27
- describe 'metadata' do
28
- let(:command) { Mothership.commands[:orgs] }
29
-
30
- describe 'command' do
31
- subject { command }
32
- its(:description) { should eq "List available organizations" }
33
- it { expect(Mothership::Help.group(:organizations)).to include(subject) }
34
- end
35
-
36
- include_examples 'inputs must have descriptions'
1
+ require "spec_helper"
2
+
3
+ module CF
4
+ module Organization
5
+ describe Orgs do
6
+ let(:global) { {:color => false} }
7
+ let(:inputs) { {} }
8
+ let(:given) { {} }
9
+ let(:output) { StringIO.new }
10
+
11
+ let(:client) { fake_client(:organizations => organizations) }
12
+ let!(:org_1) { fake(:organization, :name => "bb_second", :spaces => fake_list(:space, 2), :domains => [fake(:domain)]) }
13
+ let!(:org_2) { fake(:organization, :name => "aa_first", :spaces => [fake(:space)], :domains => fake_list(:domain, 3)) }
14
+ let!(:org_3) { fake(:organization, :name => "cc_last", :spaces => fake_list(:space, 2), :domains => fake_list(:domain, 2)) }
15
+ let(:organizations) { [org_1, org_2, org_3] }
16
+
17
+ before do
18
+ CF::CLI.any_instance.stub(:client) { client }
19
+ CF::CLI.any_instance.stub(:precondition) { nil }
20
+ end
37
21
 
38
- describe 'arguments' do
39
- subject { command.arguments }
40
- it 'has no arguments' do
41
- should be_empty
22
+ subject do
23
+ capture_output { Mothership.new.invoke(:orgs, inputs, given, global) }
42
24
  end
43
- end
44
- end
45
25
 
46
- it 'should have the correct first two lines' do
47
- subject
48
- stdout.rewind
49
- expect(stdout.readline).to match /Getting organizations.*OK/
50
- expect(stdout.readline).to eq "\n"
51
- end
26
+ describe "metadata" do
27
+ let(:command) { Mothership.commands[:orgs] }
52
28
 
53
- context 'when there are no organizations' do
54
- let(:organizations) { [] }
29
+ describe "command" do
30
+ subject { command }
31
+ its(:description) { should eq "List available organizations" }
32
+ it { expect(Mothership::Help.group(:organizations)).to include(subject) }
33
+ end
55
34
 
56
- context 'and the full flag is given' do
57
- let(:inputs) { {:full => true} }
35
+ include_examples "inputs must have descriptions"
58
36
 
59
- it 'displays yaml-style output with all organization details' do
60
- any_instance_of CF::Organization::Orgs do |orgs|
61
- dont_allow(orgs).invoke
37
+ describe "arguments" do
38
+ subject { command.arguments }
39
+ it "has no arguments" do
40
+ should be_empty
41
+ end
62
42
  end
63
- subject
64
43
  end
65
- end
66
44
 
67
- context 'and the full flag is not given (default is false)' do
68
- it 'should show only the progress' do
45
+ it "should have the correct first two lines" do
69
46
  subject
70
-
71
47
  stdout.rewind
72
48
  expect(stdout.readline).to match /Getting organizations.*OK/
73
- expect(stdout).to be_eof
49
+ expect(stdout.readline).to eq "\n"
74
50
  end
75
- end
76
- end
77
51
 
78
- context 'when there are organizations' do
79
- context 'and the full flag is given' do
80
- let(:inputs) { {:full => true} }
52
+ context "when there are no organizations" do
53
+ let(:organizations) { [] }
54
+
55
+ context "and the full flag is given" do
56
+ let(:inputs) { {:full => true} }
81
57
 
82
- it 'displays yaml-style output with all organization details' do
83
- any_instance_of CF::Organization::Orgs do |orgs|
84
- mock(orgs).invoke(:org, :organization => org_2, :full => true).ordered
85
- mock(orgs).invoke(:org, :organization => org_1, :full => true).ordered
86
- mock(orgs).invoke(:org, :organization => org_3, :full => true).ordered
58
+ it "displays yaml-style output with all organization details" do
59
+ CF::Organization::Orgs.any_instance.should_not_receive(:invoke)
60
+ subject
61
+ end
62
+ end
63
+
64
+ context "and the full flag is not given (default is false)" do
65
+ it "should show only the progress" do
66
+ subject
67
+
68
+ stdout.rewind
69
+ expect(stdout.readline).to match /Getting organizations.*OK/
70
+ expect(stdout).to be_eof
71
+ end
87
72
  end
88
- subject
89
73
  end
90
- end
91
74
 
92
- context 'and the full flag is not given (default is false)' do
93
- it 'displays tabular output with names, spaces and domains' do
94
- subject
75
+ context "when there are organizations" do
76
+ context "and the full flag is given" do
77
+ let(:inputs) { {:full => true} }
95
78
 
96
- stdout.rewind
97
- stdout.readline
98
- stdout.readline
79
+ it "displays yaml-style output with all organization details" do
80
+ CF::Organization::Orgs.any_instance.should_receive(:invoke).with(:org, :organization => org_2, :full => true)
81
+ CF::Organization::Orgs.any_instance.should_receive(:invoke).with(:org, :organization => org_1, :full => true)
82
+ CF::Organization::Orgs.any_instance.should_receive(:invoke).with(:org, :organization => org_3, :full => true)
83
+ subject
84
+ end
85
+ end
86
+
87
+ context "and the full flag is not given (default is false)" do
88
+ it "displays tabular output with names, spaces and domains" do
89
+ subject
90
+
91
+ stdout.rewind
92
+ stdout.readline
93
+ stdout.readline
99
94
 
100
- expect(stdout.readline).to match /name\s+spaces\s+domains/
101
- organizations.sort_by(&:name).each do |org|
102
- expect(stdout.readline).to match /#{org.name}\s+#{name_list(org.spaces)}\s+#{name_list(org.domains)}/
95
+ expect(stdout.readline).to match /name\s+spaces\s+domains/
96
+ organizations.sort_by(&:name).each do |org|
97
+ expect(stdout.readline).to match /#{org.name}\s+#{name_list(org.spaces)}\s+#{name_list(org.domains)}/
98
+ end
99
+ expect(stdout).to be_eof
100
+ end
103
101
  end
104
- expect(stdout).to be_eof
105
102
  end
106
103
  end
107
104
  end
@@ -1,111 +1,112 @@
1
- require 'spec_helper'
2
- require "cf/cli/organization/rename"
3
-
4
- describe CF::Organization::Rename do
5
- let(:global) { { :color => false, :quiet => true } }
6
- let(:inputs) { {} }
7
- let(:given) { {} }
8
- let(:organizations) { fake_list(:organization, 3) }
9
- let(:client) { fake_client(:organizations => organizations) }
10
- let(:new_name) { "some-new-name" }
11
-
12
- before do
13
- any_instance_of(CF::CLI) do |cli|
14
- stub(cli).client { client }
15
- stub(cli).precondition { nil }
16
- end
17
- end
1
+ require "spec_helper"
2
+
3
+ module CF
4
+ module Organization
5
+ describe Rename do
6
+ let(:global) { {:color => false, :quiet => true} }
7
+ let(:inputs) { {} }
8
+ let(:given) { {} }
9
+ let(:organizations) { fake_list(:organization, 3) }
10
+ let(:client) { fake_client(:organizations => organizations) }
11
+ let(:new_name) { "some-new-name" }
12
+
13
+ before do
14
+ CF::CLI.any_instance.stub(:client).and_return(client)
15
+ CF::CLI.any_instance.stub(:precondition).and_return(nil)
16
+ end
18
17
 
19
- subject { Mothership.new.invoke(:rename_org, inputs, given, global) }
18
+ subject { Mothership.new.invoke(:rename_org, inputs, given, global) }
20
19
 
21
- describe 'metadata' do
22
- let(:command) { Mothership.commands[:rename_org] }
20
+ describe "metadata" do
21
+ let(:command) { Mothership.commands[:rename_org] }
23
22
 
24
- describe 'command' do
25
- subject { command }
26
- its(:description) { should eq "Rename an organization" }
27
- it { expect(Mothership::Help.group(:organizations)).to include(subject) }
28
- end
23
+ describe "command" do
24
+ subject { command }
25
+ its(:description) { should eq "Rename an organization" }
26
+ it { expect(Mothership::Help.group(:organizations)).to include(subject) }
27
+ end
29
28
 
30
- describe 'inputs' do
31
- subject { command.inputs }
29
+ describe "inputs" do
30
+ subject { command.inputs }
32
31
 
33
- it "is not missing any descriptions" do
34
- subject.each do |input, attrs|
35
- expect(attrs[:description]).to be
36
- expect(attrs[:description].strip).to_not be_empty
32
+ it "is not missing any descriptions" do
33
+ subject.each do |input, attrs|
34
+ expect(attrs[:description]).to be
35
+ expect(attrs[:description].strip).to_not be_empty
36
+ end
37
+ end
37
38
  end
38
- end
39
- end
40
39
 
41
- describe 'arguments' do
42
- subject { command.arguments }
43
- it 'has the correct argument order' do
44
- should eq([
45
- { :type => :optional, :value => nil, :name => :organization },
46
- { :type => :optional, :value => nil, :name => :name }
47
- ])
40
+ describe "arguments" do
41
+ subject { command.arguments }
42
+ it "has the correct argument order" do
43
+ should eq([
44
+ {:type => :optional, :value => nil, :name => :organization},
45
+ {:type => :optional, :value => nil, :name => :name}
46
+ ])
47
+ end
48
+ end
48
49
  end
49
- end
50
- end
51
50
 
52
- context 'when there are no organizations' do
53
- let(:organizations) { [] }
51
+ context "when there are no organizations" do
52
+ let(:organizations) { [] }
54
53
 
55
- context 'and an organization is given' do
56
- let(:given) { { :organization => "some-invalid-organization" } }
57
- it { expect { subject }.to raise_error(CF::UserError, "Unknown organization 'some-invalid-organization'.") }
58
- end
59
-
60
- context 'and an organization is not given' do
61
- it { expect { subject }.to raise_error(CF::UserError, "No organizations.") }
62
- end
63
- end
64
-
65
- context 'when there are organizations' do
66
- let(:renamed_organization) { organizations.first }
54
+ context "and an organization is given" do
55
+ let(:given) { {:organization => "some-invalid-organization"} }
56
+ it { expect { subject }.to raise_error(CF::UserError, "Unknown organization 'some-invalid-organization'.") }
57
+ end
67
58
 
68
- context 'when the defaults are used' do
69
- it 'asks for the organization and new name and renames' do
70
- mock_ask("Rename which organization?", anything) { renamed_organization }
71
- mock_ask("New name") { new_name }
72
- mock(renamed_organization).name=(new_name)
73
- mock(renamed_organization).update!
74
- subject
59
+ context "and an organization is not given" do
60
+ it { expect { subject }.to raise_error(CF::UserError, "No organizations.") }
61
+ end
75
62
  end
76
- end
77
63
 
78
- context 'when no name is provided, but an organization is' do
79
- let(:given) { { :organization => renamed_organization.name } }
64
+ context "when there are organizations" do
65
+ let(:renamed_organization) { organizations.first }
66
+
67
+ context "when the defaults are used" do
68
+ it "asks for the organization and new name and renames" do
69
+ mock_ask("Rename which organization?", anything) { renamed_organization }
70
+ mock_ask("New name") { new_name }
71
+ renamed_organization.should_receive(:name=).with(new_name)
72
+ renamed_organization.should_receive(:update!)
73
+ subject
74
+ end
75
+ end
76
+
77
+ context "when no name is provided, but an organization is" do
78
+ let(:given) { {:organization => renamed_organization.name} }
80
79
 
81
- it 'asks for the new name and renames' do
82
- dont_allow_ask("Rename which organization?", anything)
83
- mock_ask("New name") { new_name }
84
- mock(renamed_organization).name=(new_name)
85
- mock(renamed_organization).update!
86
- subject
87
- end
88
- end
80
+ it "asks for the new name and renames" do
81
+ dont_allow_ask("Rename which organization?", anything)
82
+ mock_ask("New name") { new_name }
83
+ renamed_organization.should_receive(:name=).with(new_name)
84
+ renamed_organization.should_receive(:update!)
85
+ subject
86
+ end
87
+ end
89
88
 
90
- context 'when an organization is provided and a name' do
91
- let(:inputs) { { :organization => renamed_organization, :name => new_name } }
89
+ context "when an organization is provided and a name" do
90
+ let(:inputs) { {:organization => renamed_organization, :name => new_name} }
92
91
 
93
- it 'renames the organization' do
94
- mock(renamed_organization).update!
95
- subject
96
- end
92
+ it "renames the organization" do
93
+ renamed_organization.should_receive(:update!)
94
+ subject
95
+ end
97
96
 
98
- it 'displays the progress' do
99
- mock_with_progress("Renaming to #{new_name}")
100
- mock(renamed_organization).update!
97
+ it "displays the progress" do
98
+ mock_with_progress("Renaming to #{new_name}")
99
+ renamed_organization.should_receive(:update!)
101
100
 
102
- subject
103
- end
101
+ subject
102
+ end
104
103
 
105
- context 'and the name already exists' do
106
- it 'fails' do
107
- mock(renamed_organization).update! { raise CFoundry::OrganizationNameTaken.new("Bad error", 200) }
108
- expect { subject }.to raise_error(CFoundry::OrganizationNameTaken)
104
+ context "and the name already exists" do
105
+ it "fails" do
106
+ renamed_organization.should_receive(:update!) { raise CFoundry::OrganizationNameTaken.new("Bad error", 200) }
107
+ expect { subject }.to raise_error(CFoundry::OrganizationNameTaken)
108
+ end
109
+ end
109
110
  end
110
111
  end
111
112
  end