makevoid-taza 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/History.txt +74 -0
  2. data/Manifest.txt +61 -0
  3. data/README +79 -0
  4. data/README.textile +1 -0
  5. data/VERSION.yml +4 -0
  6. data/bin/taza +17 -0
  7. data/generators/flow/flow_generator.rb +57 -0
  8. data/generators/flow/templates/flow.rb.erb +9 -0
  9. data/generators/page/page_generator.rb +58 -0
  10. data/generators/page/templates/functional_page_spec.rb.erb +8 -0
  11. data/generators/page/templates/page.rb.erb +8 -0
  12. data/generators/partial/partial_generator.rb +57 -0
  13. data/generators/partial/templates/partial.rb.erb +7 -0
  14. data/generators/site/site_generator.rb +56 -0
  15. data/generators/site/templates/site.rb.erb +10 -0
  16. data/generators/site/templates/site.yml.erb +3 -0
  17. data/lib/app_generators/taza/taza_generator.rb +74 -0
  18. data/lib/app_generators/taza/templates/config.yml.erb +3 -0
  19. data/lib/app_generators/taza/templates/rakefile.rb.erb +10 -0
  20. data/lib/app_generators/taza/templates/spec_helper.rb.erb +11 -0
  21. data/lib/extensions/array.rb +10 -0
  22. data/lib/extensions/hash.rb +15 -0
  23. data/lib/extensions/object.rb +33 -0
  24. data/lib/extensions/string.rb +11 -0
  25. data/lib/taza.rb +24 -0
  26. data/lib/taza/browser.rb +53 -0
  27. data/lib/taza/entity.rb +55 -0
  28. data/lib/taza/fixture.rb +68 -0
  29. data/lib/taza/fixtures.rb +24 -0
  30. data/lib/taza/flow.rb +40 -0
  31. data/lib/taza/page.rb +128 -0
  32. data/lib/taza/settings.rb +33 -0
  33. data/lib/taza/site.rb +150 -0
  34. data/lib/taza/tasks.rb +54 -0
  35. data/spec/array_spec.rb +17 -0
  36. data/spec/browser_spec.rb +86 -0
  37. data/spec/entity_spec.rb +35 -0
  38. data/spec/fixture_spec.rb +51 -0
  39. data/spec/fixtures_spec.rb +47 -0
  40. data/spec/flow_generator_spec.rb +50 -0
  41. data/spec/hash_spec.rb +15 -0
  42. data/spec/object_spec.rb +29 -0
  43. data/spec/page_generator_spec.rb +56 -0
  44. data/spec/page_module_spec.rb +165 -0
  45. data/spec/page_spec.rb +105 -0
  46. data/spec/partial_generator_spec.rb +38 -0
  47. data/spec/project_generator_spec.rb +56 -0
  48. data/spec/sandbox/config.yml +3 -0
  49. data/spec/sandbox/config/config.yml +1 -0
  50. data/spec/sandbox/config/site_name.yml +5 -0
  51. data/spec/sandbox/fixtures/examples.yml +15 -0
  52. data/spec/sandbox/fixtures/foo_site/bars.yml +2 -0
  53. data/spec/sandbox/fixtures/foos.yml +3 -0
  54. data/spec/sandbox/fixtures/users.yml +3 -0
  55. data/spec/sandbox/flows/batman.rb +5 -0
  56. data/spec/sandbox/flows/robin.rb +4 -0
  57. data/spec/sandbox/pages/foo/bar.rb +9 -0
  58. data/spec/sandbox/pages/foo/bay.rb +10 -0
  59. data/spec/sandbox/pages/foo/baz.rb +11 -0
  60. data/spec/sandbox/pages/foo/partials/partial_the_reckoning.rb +2 -0
  61. data/spec/settings_spec.rb +92 -0
  62. data/spec/site_fixtures_spec.rb +17 -0
  63. data/spec/site_generator_spec.rb +56 -0
  64. data/spec/site_spec.rb +268 -0
  65. data/spec/spec_helper.rb +57 -0
  66. data/spec/string_spec.rb +8 -0
  67. data/spec/taza_bin_spec.rb +13 -0
  68. data/spec/taza_tasks_spec.rb +56 -0
  69. data/taza.gemspec +46 -0
  70. metadata +196 -0
@@ -0,0 +1,86 @@
1
+ require 'spec/spec_helper'
2
+ require 'taza/browser'
3
+ require 'taza/settings'
4
+ require 'taza/options'
5
+ require 'selenium'
6
+ require 'watir'
7
+
8
+ describe Taza::Browser do
9
+
10
+ before :each do
11
+ Taza::Settings.stubs(:config_file).returns({})
12
+ ENV['TAZA_ENV'] = 'isolation'
13
+ ENV['SERVER_PORT'] = nil
14
+ ENV['SERVER_IP'] = nil
15
+ ENV['BROWSER'] = nil
16
+ ENV['DRIVER'] = nil
17
+ ENV['TIMEOUT'] = nil
18
+ end
19
+
20
+ it "should raise unknown browser error for unsupported watir browsers" do
21
+ lambda { Taza::Browser.create(:browser => :foo_browser_9000,:driver => :watir) }.should raise_error(StandardError)
22
+ end
23
+
24
+ it "should use params browser type when creating selenium" do
25
+ browser_type = :opera
26
+ Selenium::SeleniumDriver.expects(:new).with(anything,anything,'*opera',anything)
27
+ Taza::Browser.create(:browser => browser_type, :driver => :selenium)
28
+ end
29
+
30
+ it "should raise selenium unsupported browser error" do
31
+ Taza::Browser.create(:browser => :foo, :driver => :selenium)
32
+ end
33
+
34
+ it "should be able to create a selenium instance" do
35
+ browser = Taza::Browser.create(:browser => :firefox, :driver => :selenium)
36
+ browser.should be_a_kind_of(Selenium::SeleniumDriver)
37
+ end
38
+
39
+ it "should use environment settings for server port and ip" do
40
+ Taza::Settings.stubs(:path).returns(File.join('spec','sandbox'))
41
+ ENV['SERVER_PORT'] = 'server_port'
42
+ ENV['SERVER_IP'] = 'server_ip'
43
+ Selenium::SeleniumDriver.expects(:new).with('server_ip','server_port',anything,anything)
44
+ Taza::Browser.create(Taza::Settings.config("SiteName"))
45
+ end
46
+
47
+ it "should use environment settings for timeout" do
48
+ Taza::Settings.stubs(:path).returns(File.join('spec','sandbox'))
49
+ ENV['TIMEOUT'] = 'timeout'
50
+ Selenium::SeleniumDriver.expects(:new).with(anything,anything,anything,'timeout')
51
+ Taza::Browser.create(Taza::Settings.config("SiteName"))
52
+ end
53
+
54
+ it "should be able to give you the class of browser" do
55
+ Taza::Browser.expects(:watir_safari).returns(Object)
56
+ Taza::Browser.browser_class(:browser => :safari, :driver => :watir).should eql(Object)
57
+ end
58
+
59
+ it "should be able to attach to an open IE instance" do
60
+ require 'watir'
61
+ browser = Object.new
62
+ Watir::IE.stubs(:find).returns(browser)
63
+ Watir::IE.stubs(:new).returns(browser)
64
+ old_browser = Watir::IE.new
65
+ new_browser = Taza::Browser.create(:browser => :ie, :driver => :watir, :attach => true)
66
+ new_browser.should eql(old_browser)
67
+ end
68
+
69
+ it "should be able to open a new IE instance if there is no instance to attach to" do
70
+ require 'watir'
71
+ browser = Object.new
72
+ Watir::IE.stubs(:find).returns()
73
+ Watir::IE.stubs(:new).returns(browser)
74
+ new_browser = Taza::Browser.create(:browser => :ie, :driver => :watir)
75
+ browser.nil?.should be_false
76
+ end
77
+ it "should be able to open a new IE instance if attach not specified" do
78
+ require 'watir'
79
+ foo = Object.new
80
+ bar = Object.new
81
+ Watir::IE.stubs(:find).returns(foo)
82
+ Watir::IE.stubs(:new).returns(bar)
83
+ new_browser = Taza::Browser.create(:browser => :ie, :driver => :watir)
84
+ new_browser.should_not eql(foo)
85
+ end
86
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec/spec_helper'
2
+ require 'taza/entity'
3
+
4
+ describe Taza::Entity do
5
+ it "should add methods for hash string keys" do
6
+ entity = Taza::Entity.new({'apple' => 'pie'},nil)
7
+ entity.should respond_to(:apple)
8
+ end
9
+
10
+ it "should be accessible like a hash(foo[:bar])" do
11
+ entity = Taza::Entity.new({:apple => 'pie'},nil)
12
+ entity[:apple].should eql('pie')
13
+ end
14
+
15
+ it "should be able to define methods for multiple levels" do
16
+ entity = Taza::Entity.new({:fruits => {:apple => 'pie'} },nil)
17
+ entity.fruits.apple.should eql('pie')
18
+ end
19
+
20
+ it "should be able to return a hash object" do
21
+ entity = Taza::Entity.new({:apple => 'pie' },nil)
22
+ entity.to_hash[:apple].should eql('pie')
23
+ end
24
+
25
+ it "should be able to do string-to-symbol conversion for hash keys using to_hash" do
26
+ entity = Taza::Entity.new({'apple' => 'pie' },nil)
27
+ entity.to_hash[:apple].should eql('pie')
28
+ end
29
+
30
+ it "should be able to do string-to-symbol conversion for hash keys" do
31
+ entity = Taza::Entity.new({'fruits' => {'apple' => 'pie' }},nil)
32
+ entity.to_hash[:fruits][:apple].should eql('pie')
33
+ end
34
+
35
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec/spec_helper'
2
+ require 'taza/fixture'
3
+ require 'extensions/array'
4
+
5
+ describe Taza::Fixture do
6
+ before :each do
7
+ @base_path = File.join('.','spec','sandbox','fixtures','')
8
+ end
9
+
10
+ it "should be able to load entries from fixtures" do
11
+ fixture = Taza::Fixture.new
12
+ fixture.load_fixtures_from(@base_path)
13
+ example = fixture.get_fixture_entity(:examples,'first_example')
14
+ example.name.should eql("first")
15
+ example.price.should eql(1)
16
+ end
17
+
18
+ it "should use the spec fixtures folder as the base path" do
19
+ Taza::Fixture.base_path.should eql('./spec/fixtures/')
20
+ end
21
+
22
+ it "should know if a pluralized fixture of that name exists" do
23
+ fixture = Taza::Fixture.new
24
+ fixture.load_fixtures_from(@base_path)
25
+ fixture.pluralized_fixture_exists?('example').should be_true
26
+ fixture.pluralized_fixture_exists?('boo').should be_false
27
+ end
28
+
29
+ it "should be able to get all fixtures loaded excluding sub-folder fixtures" do
30
+ fixture = Taza::Fixture.new
31
+ fixture.load_fixtures_from(@base_path)
32
+ fixture.fixture_names.should be_equivalent([:examples,:users,:foos])
33
+ end
34
+
35
+ it "should be able to get specific fixture entities" do
36
+ fixture = Taza::Fixture.new
37
+ fixture.load_fixtures_from(@base_path)
38
+ examples = fixture.specific_fixture_entities(:examples, ['third_example'])
39
+ examples.length.should eql(1)
40
+ examples['third_example'].name.should eql('third')
41
+ end
42
+
43
+ it "should not modified the fixtures when you get specific entities off a fixture" do
44
+ fixture = Taza::Fixture.new
45
+ fixture.load_fixtures_from(@base_path)
46
+ previous_count = fixture.get_fixture(:examples).length
47
+ examples = fixture.specific_fixture_entities(:examples, ['third_example'])
48
+ fixture.get_fixture(:examples).length.should eql(previous_count)
49
+ end
50
+
51
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec/spec_helper'
2
+ require 'taza/fixture'
3
+
4
+ describe "Taza::Fixtures" do
5
+ Taza::Fixture.stubs(:base_path).returns('./spec/sandbox/fixtures/')
6
+ require 'taza/fixtures'
7
+ include Taza::Fixtures
8
+
9
+ it "should be able to look up a fixture entity off fixture_methods module" do
10
+ examples(:first_example).name.should eql('first')
11
+ end
12
+
13
+ it "should still raise method missing error" do
14
+ lambda{zomgwtf(:first_example)}.should raise_error(NoMethodError)
15
+ end
16
+
17
+ #TODO: this test tests what is in entity's instance eval not happy with it being here
18
+ it "should be able to look up a fixture entity off fixture_methods module" do
19
+ examples(:first_example).user.name.should eql(users(:shatner).name)
20
+ end
21
+
22
+ it "should be able to resolve one to many relationships" do
23
+ foos(:gap).examples.length.should eql(2)
24
+ end
25
+
26
+ it "should be able to get one to many entities" do
27
+ foos(:gap).examples['first_example'].name.should eql('first')
28
+ foos(:gap).examples['second_example'].name.should eql('second')
29
+ end
30
+
31
+ it "should not be able to access fixtures in sub-folders if not included" do
32
+ lambda{bars(:foo)}.should raise_error(NoMethodError)
33
+ end
34
+
35
+ it "should template fixture files" do
36
+ users(:shatner).age.should eql(66)
37
+ end
38
+
39
+ it "should be able to get one to many entities for hash[key] style" do
40
+ foos(:gap)['examples']['first_example']['name'].should eql('first')
41
+ end
42
+
43
+ it "should be able to access multiple levels inside fixtures" do
44
+ examples(:forth_example).something.user('shatner').name.should eql('William Shatner')
45
+ end
46
+
47
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec/spec_helper'
2
+ require 'rubygems'
3
+ require 'fileutils'
4
+ require 'taza/site'
5
+
6
+ class Taza::Site
7
+ def flows
8
+ flows = []
9
+ Dir.glob(File.join(path,'flows','*.rb')).each do |file|
10
+ require file
11
+
12
+ flows << "#{self.class.parent.to_s}::#{File.basename(file,'.rb').camelize}".constantize
13
+ end
14
+ flows
15
+ end
16
+ end
17
+
18
+ describe "Flow Generation" do
19
+ include RubiGen::GeneratorTestHelper
20
+ include Helpers::Generator
21
+ include Helpers::Taza
22
+
23
+ before :all do
24
+ @site_name = "Foo"
25
+ @site_folder = File.join(PROJECT_FOLDER,'lib','sites',"gap")
26
+ @site_file = File.join(PROJECT_FOLDER,'lib','sites',"gap.rb")
27
+ @flow_name = "CheckOut"
28
+ end
29
+
30
+ before :each do
31
+ run_generator('taza', [APP_ROOT], generator_sources)
32
+ @site_class = generate_site(@site_name)
33
+ end
34
+
35
+ after :each do
36
+ bare_teardown
37
+ end
38
+
39
+ it "should give you usage if you do not give two arguments" do
40
+ FlowGenerator.any_instance.expects(:usage)
41
+ lambda { run_generator('flow', [@flow_name], generator_sources) }.should raise_error
42
+ end
43
+
44
+ it "should give you usage if you give a site that does not exist" do
45
+ FlowGenerator.any_instance.expects(:usage)
46
+ $stderr.expects(:puts).with(regexp_matches(/NoSuchSite/))
47
+ lambda { run_generator('flow', [@flow_name,"NoSuchSite"], generator_sources) }.should raise_error
48
+ end
49
+
50
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec/spec_helper'
2
+ require 'taza/entity'
3
+ require 'extensions/hash'
4
+
5
+ # This is too tightly coupled to Taza::Entity
6
+ describe 'Hash Extensions' do
7
+ it "should add methods for hash keys to some instance" do
8
+ entity = {'apple' => 'pie'}.convert_hash_keys_to_methods(nil)
9
+ entity.should respond_to(:apple)
10
+ end
11
+ it "should not add the methods to a hash" do
12
+ entity = {'apple' => 'pie'}.convert_hash_keys_to_methods(nil)
13
+ entity.should_not be_a_instance_of(Hash)
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe "Object" do
4
+ before :all do
5
+ @orig_version = VERSION
6
+ Object.send :remove_const, :VERSION
7
+ Object.const_set :VERSION, "1.8.6"
8
+ load 'lib/extensions/object.rb'
9
+ end
10
+
11
+ after :all do
12
+ Object.send :remove_const, :VERSION
13
+ Object.const_set :VERSION, @orig_version
14
+ end
15
+
16
+ it "should execute blocks with args in instance context" do
17
+ str = "string"
18
+
19
+ class << str
20
+ def my_singleton_method(arg)
21
+ arg
22
+ end
23
+ end
24
+
25
+ block = Proc.new { |arg| my_singleton_method(arg) }
26
+
27
+ str.instance_exec("foo",&block).should == "foo"
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec/spec_helper'
2
+ require 'rubygems'
3
+ require 'fileutils'
4
+ require 'taza/page'
5
+
6
+ describe "Page Generation" do
7
+ include RubiGen::GeneratorTestHelper
8
+ include Helpers::Generator
9
+ include Helpers::Taza
10
+
11
+ before :all do
12
+ @page_name = "CheckOut"
13
+ end
14
+
15
+ before :each do
16
+ run_generator('taza', [APP_ROOT], generator_sources)
17
+ @site_class = generate_site('Gap')
18
+ end
19
+
20
+ after :each do
21
+ bare_teardown
22
+ end
23
+
24
+ it "should give you usage if you do not give two arguments" do
25
+ PageGenerator.any_instance.expects(:usage)
26
+ lambda { run_generator('page', [@page_name], generator_sources) }.should raise_error
27
+ end
28
+
29
+ it "should give you usage if you give a site that does not exist" do
30
+ PageGenerator.any_instance.expects(:usage)
31
+ $stderr.expects(:puts).with(regexp_matches(/NoSuchSite/))
32
+ lambda { run_generator('page', [@page_name,"NoSuchSite"], generator_sources) }.should raise_error
33
+ end
34
+
35
+ it "should generate a page spec that can be required" do
36
+ run_generator('page', [@page_name,@site_class.to_s], generator_sources)
37
+ page_functional_spec = File.join(PROJECT_FOLDER,'spec','isolation',@site_class.to_s.underscore,'check_out_page_spec.rb')
38
+ system("ruby -c #{page_functional_spec} > #{null_device}").should be_true
39
+ end
40
+
41
+ it "should be able to access the generated page from the site" do
42
+ run_generator('page', [@page_name,@site_class.to_s], generator_sources)
43
+ stub_settings
44
+ stub_browser
45
+ @site_class.new.check_out_page
46
+ end
47
+
48
+ it "should be able to access the generated page for its site" do
49
+ stub_browser
50
+ stub_settings
51
+ new_site_class = generate_site('Pag')
52
+ run_generator('page', [@page_name,@site_class.to_s], generator_sources)
53
+ run_generator('page', [@page_name,new_site_class.to_s], generator_sources)
54
+ new_site_class.new.check_out_page.class.should_not eql(@site_class.new.check_out_page.class)
55
+ end
56
+ end
@@ -0,0 +1,165 @@
1
+ require 'spec/spec_helper'
2
+ require 'taza/page'
3
+
4
+ describe "Taza Page Module" do
5
+
6
+ class PageWithModule < ::Taza::Page
7
+
8
+ page_module :module do
9
+ element(:module_element) { browser }
10
+ end
11
+
12
+ end
13
+
14
+ it "should execute elements in the context of their page module" do
15
+ page = PageWithModule.new(:module)
16
+ page.browser = :something
17
+ page.module_element.should eql(:something)
18
+ end
19
+
20
+ class AnotherPageWithModule < ::Taza::Page
21
+
22
+ page_module :other_module do
23
+ element(:another_module_element) { browser }
24
+ end
25
+
26
+ end
27
+
28
+
29
+ it "should not execute elements that belong to a page module but accessed without it" do
30
+ lambda { AnotherPageWithModule.new.another_module_element }.should raise_error(NoMethodError)
31
+ end
32
+
33
+ it "should execute elements in the context of their page module when accessed with it" do
34
+ page = AnotherPageWithModule.new(:other_module)
35
+ page.browser = :another_thing
36
+ page.another_module_element.should eql(:another_thing)
37
+ end
38
+
39
+
40
+ class TestPageWithModules < ::Taza::Page
41
+
42
+ page_module :module_one do
43
+ element(:some_module_element) { :something }
44
+ end
45
+
46
+ page_module :module_two do
47
+ element(:some_module_element) { :nothing }
48
+ end
49
+
50
+ end
51
+
52
+ it "should execute elements with the same name but different page modules" do
53
+ module_one = TestPageWithModules.new(:module_one)
54
+ module_two = TestPageWithModules.new(:module_two)
55
+ module_one.some_module_element.should eql(:something)
56
+ module_two.some_module_element.should eql(:nothing)
57
+ end
58
+
59
+ class PageWithMultipleModuleElements < ::Taza::Page
60
+
61
+ page_module :module do
62
+ element(:module_element) { :something }
63
+ element(:another_module_element) { :nothing }
64
+ end
65
+
66
+ end
67
+
68
+ it "should execute elements with the same name but different page modules" do
69
+ page_module = PageWithMultipleModuleElements.new(:module)
70
+ page_module.module_element.should eql(:something)
71
+ page_module.another_module_element.should eql(:nothing)
72
+ end
73
+
74
+ class PageWithFilterAndModule < ::Taza::Page
75
+ page_module :module do
76
+ element(:sample_element) {:something}
77
+ end
78
+ filter :sample_filter, :module
79
+ def sample_filter
80
+ true
81
+ end
82
+ end
83
+
84
+ it "should execute filters for page modules" do
85
+ page = PageWithFilterAndModule.new(:module)
86
+ page.sample_element.should eql(:something)
87
+ end
88
+
89
+ class PageWithFalseFilterAndModule < ::Taza::Page
90
+ page_module :module do
91
+ element(:sample_element) {:something}
92
+ end
93
+ filter :false_filter, :module
94
+ def false_filter
95
+ false
96
+ end
97
+ end
98
+
99
+ it "should raise an error for page-module filters that return false" do
100
+ page = PageWithFalseFilterAndModule.new(:module)
101
+ lambda { page.sample_element }.should raise_error(Taza::FilterError)
102
+ end
103
+
104
+ class PageWithFilterAndModuleElements < ::Taza::Page
105
+ page_module :module do
106
+ element(:sample_element) {:something}
107
+ end
108
+ page_module_filter :sample_filter, :module, :sample_element
109
+ def sample_filter
110
+ false
111
+ end
112
+ end
113
+
114
+ it "should execute filters for elements inside page modules" do
115
+ page = PageWithFilterAndModuleElements.new(:module)
116
+ lambda { page.sample_element }.should raise_error(Taza::FilterError)
117
+ end
118
+
119
+ class PageWithFiltersAndModuleElements < ::Taza::Page
120
+ page_module :module do
121
+ element(:sample_element) {:something}
122
+ element(:another_sample_element) {:something}
123
+ end
124
+ page_module_filter :sample_filter, :module
125
+ def sample_filter
126
+ true
127
+ end
128
+ page_module_filter :another_sample_filter, :module, :sample_element
129
+ def another_sample_filter
130
+ false
131
+ end
132
+ end
133
+
134
+ it "should execute filters for specific and all elements inside page modules" do
135
+ page = PageWithFiltersAndModuleElements.new(:module)
136
+ lambda { page.sample_element }.should raise_error(Taza::FilterError)
137
+ page.another_sample_element.should eql(:something)
138
+ end
139
+
140
+ class PageWithFiltersAndModulesAndElements < ::Taza::Page
141
+ page_module :foo_module do
142
+ element(:sample_element) {:something}
143
+ end
144
+ page_module_filter :foo_filter, :foo_module
145
+ def foo_filter
146
+ true
147
+ end
148
+ page_module :bar_module do
149
+ element(:sample_element) {:nothing}
150
+ end
151
+ page_module_filter :bar_filter, :bar_module
152
+ def bar_filter
153
+ false
154
+ end
155
+ end
156
+
157
+ it "should execute page module filters for identical element names appropriately" do
158
+ foo = PageWithFiltersAndModulesAndElements.new(:foo_module)
159
+ foo.sample_element.should eql(:something)
160
+ bar = PageWithFiltersAndModulesAndElements.new(:bar_module)
161
+ lambda { bar.sample_element }.should raise_error(Taza::FilterError)
162
+ end
163
+
164
+
165
+ end