ramaze 0.1.3 → 0.1.4

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.
Files changed (149) hide show
  1. data/bin/ramaze +58 -26
  2. data/doc/AUTHORS +2 -0
  3. data/doc/CHANGELOG +401 -0
  4. data/doc/README +14 -9
  5. data/doc/README.html +737 -0
  6. data/doc/TODO +14 -14
  7. data/doc/changes.txt +401 -0
  8. data/doc/changes.xml +401 -0
  9. data/doc/meta/announcement.txt +28 -15
  10. data/doc/meta/configuration.txt +3 -3
  11. data/doc/meta/internals.txt +2 -2
  12. data/doc/meta/users.kml +62 -0
  13. data/doc/readme_chunks/examples.txt +1 -1
  14. data/doc/readme_chunks/features.txt +13 -8
  15. data/doc/tutorial/todolist.html +2 -2
  16. data/doc/tutorial/todolist.mkd +2 -2
  17. data/examples/blog/README +3 -0
  18. data/examples/blog/spec/blog.rb +101 -0
  19. data/examples/blog/{main.rb → start.rb} +0 -0
  20. data/examples/caching.rb +16 -5
  21. data/examples/layout.rb +41 -0
  22. data/examples/templates/template_amrita2.rb +1 -1
  23. data/examples/templates/template_erubis.rb +1 -1
  24. data/examples/templates/template_ezamar.rb +1 -1
  25. data/examples/templates/template_haml.rb +1 -1
  26. data/examples/templates/template_liquid.rb +1 -1
  27. data/examples/templates/template_markaby.rb +1 -1
  28. data/examples/templates/template_remarkably.rb +1 -1
  29. data/examples/todolist/README +1 -0
  30. data/{spec/examples → examples/todolist/spec}/todolist.rb +3 -3
  31. data/examples/todolist/{main.rb → start.rb} +0 -0
  32. data/examples/whywiki/{main.rb → start.rb} +0 -0
  33. data/examples/wiktacular/README +2 -0
  34. data/examples/wiktacular/spec/wiktacular.rb +146 -0
  35. data/examples/wiktacular/src/controller.rb +11 -0
  36. data/examples/wiktacular/src/model.rb +5 -1
  37. data/examples/wiktacular/{main.rb → start.rb} +0 -1
  38. data/examples/wiktacular/template/edit.xhtml +1 -2
  39. data/examples/wiktacular/template/html_layout.xhtml +27 -0
  40. data/examples/wiktacular/template/index.xhtml +8 -10
  41. data/examples/wiktacular/template/new.xhtml +1 -2
  42. data/lib/proto/{main.rb → start.rb} +0 -0
  43. data/lib/proto/template/index.xhtml +1 -1
  44. data/lib/ramaze/action/render.rb +58 -4
  45. data/lib/ramaze/action.rb +20 -0
  46. data/lib/ramaze/adapter/cgi.rb +7 -4
  47. data/lib/ramaze/adapter/fcgi.rb +6 -4
  48. data/lib/ramaze/adapter/mongrel.rb +4 -0
  49. data/lib/ramaze/adapter/webrick.rb +20 -9
  50. data/lib/ramaze/adapter.rb +3 -1
  51. data/lib/ramaze/cache/memcached.rb +2 -26
  52. data/lib/ramaze/cache.rb +8 -4
  53. data/lib/ramaze/controller/resolve.rb +26 -8
  54. data/lib/ramaze/controller.rb +44 -7
  55. data/lib/ramaze/dispatcher/action.rb +5 -1
  56. data/lib/ramaze/dispatcher/directory.rb +115 -0
  57. data/lib/ramaze/dispatcher/error.rb +19 -5
  58. data/lib/ramaze/dispatcher/file.rb +2 -2
  59. data/lib/ramaze/dispatcher.rb +52 -39
  60. data/lib/ramaze/global/dsl.rb +3 -2
  61. data/lib/ramaze/global/globalstruct.rb +26 -4
  62. data/lib/ramaze/global.rb +20 -11
  63. data/lib/ramaze/helper/aspect.rb +29 -11
  64. data/lib/ramaze/helper/auth.rb +2 -2
  65. data/lib/ramaze/helper/cache.rb +2 -0
  66. data/lib/ramaze/helper/identity.rb +21 -6
  67. data/lib/ramaze/helper/link.rb +1 -1
  68. data/lib/ramaze/helper/pager.rb +158 -100
  69. data/lib/ramaze/helper/partial.rb +22 -0
  70. data/lib/ramaze/helper/redirect.rb +1 -2
  71. data/lib/ramaze/helper/stack.rb +1 -1
  72. data/lib/ramaze/inform/informer.rb +20 -0
  73. data/lib/ramaze/inform/syslog.rb +5 -0
  74. data/lib/ramaze/snippets/kernel/__dir__.rb +21 -0
  75. data/lib/ramaze/snippets/kernel/aquire.rb +22 -12
  76. data/lib/ramaze/snippets/numeric/human_readable_filesize_format.rb +33 -0
  77. data/lib/ramaze/snippets/ramaze/caller_lines.rb +1 -1
  78. data/lib/ramaze/snippets/struct/values_at.rb +11 -4
  79. data/lib/ramaze/sourcereload.rb +29 -1
  80. data/{spec → lib/ramaze/spec}/helper/context.rb +0 -0
  81. data/{spec → lib/ramaze/spec}/helper/layout.rb +1 -1
  82. data/{spec → lib/ramaze/spec}/helper/minimal.rb +0 -0
  83. data/{spec → lib/ramaze/spec}/helper/mock_http.rb +0 -0
  84. data/{spec → lib/ramaze/spec}/helper/requester.rb +0 -0
  85. data/{spec → lib/ramaze/spec}/helper/simple_http.rb +0 -0
  86. data/{spec → lib/ramaze/spec}/helper/wrap.rb +0 -0
  87. data/lib/ramaze/spec/helper.rb +60 -0
  88. data/lib/ramaze/store/default.rb +3 -0
  89. data/lib/ramaze/template/ezamar/render_partial.rb +3 -0
  90. data/lib/ramaze/template/sass.rb +45 -0
  91. data/lib/ramaze/template.rb +1 -1
  92. data/lib/ramaze/tool/create.rb +5 -5
  93. data/lib/ramaze/tool/localize.rb +26 -5
  94. data/lib/ramaze/tool/mime.rb +7 -0
  95. data/lib/ramaze/trinity/response.rb +15 -0
  96. data/lib/ramaze/trinity/session.rb +1 -1
  97. data/lib/ramaze/version.rb +1 -1
  98. data/lib/ramaze.rb +5 -0
  99. data/rake_tasks/conf.rake +4 -4
  100. data/rake_tasks/maintaince.rake +12 -7
  101. data/rake_tasks/spec.rake +7 -4
  102. data/spec/examples/caching.rb +6 -8
  103. data/spec/helper.rb +3 -60
  104. data/spec/ramaze/action/basics.rb +17 -0
  105. data/spec/ramaze/action/cache.rb +28 -0
  106. data/spec/ramaze/action/layout.rb +110 -0
  107. data/spec/ramaze/action/render.rb +14 -0
  108. data/spec/ramaze/action/template/bar.xhtml +1 -0
  109. data/spec/ramaze/action/template/other_wrapper.xhtml +1 -0
  110. data/spec/ramaze/action/template/single_wrapper.xhtml +1 -0
  111. data/spec/ramaze/controller/template/edit/content.xhtml +1 -0
  112. data/spec/ramaze/controller/template/edit.xhtml +1 -0
  113. data/spec/ramaze/controller/template_resolving.rb +2 -2
  114. data/spec/ramaze/dispatcher/directory.rb +53 -0
  115. data/spec/ramaze/dispatcher/file.rb +0 -3
  116. data/spec/ramaze/error.rb +17 -2
  117. data/spec/ramaze/helper/aspect.rb +14 -20
  118. data/spec/ramaze/helper/pager.rb +83 -1
  119. data/spec/ramaze/helper/partial.rb +1 -1
  120. data/spec/ramaze/helper/template/test_template.xhtml +1 -0
  121. data/spec/ramaze/inform/informer.rb +37 -5
  122. data/spec/ramaze/localize.rb +1 -1
  123. data/spec/ramaze/template/haml.rb +5 -5
  124. data/spec/ramaze/template/sass/file.css.sass +5 -0
  125. data/spec/ramaze/template/sass.rb +46 -0
  126. data/spec/ramaze/template.rb +1 -1
  127. data/spec/ramaze/trinity/session.rb +27 -0
  128. data/spec/snippets/kernel/__dir__.rb +8 -0
  129. data/spec/snippets/kernel/aquire.rb +71 -0
  130. data/spec/snippets/kernel/constant.rb +27 -0
  131. data/spec/snippets/numeric/human_readable_filesize_format.rb +11 -0
  132. data/spec/snippets/ramaze/caller_info.rb +39 -0
  133. data/spec/snippets/ramaze/caller_lines.rb +27 -0
  134. data/spec/snippets/string/DIVIDE.rb +18 -0
  135. data/spec/snippets/string/camel_case.rb +25 -0
  136. data/spec/snippets/string/color.rb +11 -0
  137. data/spec/snippets/string/snake_case.rb +17 -0
  138. data/spec/snippets/struct/fill.rb +27 -0
  139. data/spec/snippets/struct/values_at.rb +39 -0
  140. metadata +71 -31
  141. data/examples/todolist/todolist.db +0 -5
  142. data/examples/wiktacular/src/page.rb +0 -66
  143. data/lib/ramaze/helper/feed.rb +0 -135
  144. data/lib/ramaze/helper/form.rb +0 -204
  145. data/lib/ramaze/snippets/openstruct/temp.rb +0 -13
  146. data/lib/ramaze/store/yaml.rb +0 -170
  147. data/spec/ramaze/helper/feed.rb +0 -127
  148. data/spec/ramaze/helper/form.rb +0 -146
  149. data/spec/ramaze/store/yaml.rb +0 -76
@@ -1,135 +0,0 @@
1
- # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
- # All files in this distribution are subject to the terms of the Ruby license.
3
-
4
- module Ramaze
5
- module FeedHelper
6
-
7
- # just a stub, for the moment, doing nothing more than calling
8
- # #to_xml on the object you pass
9
-
10
- def feed object
11
- object.to_xml
12
- end
13
- end
14
- end
15
-
16
- module ReFeed
17
-
18
- # Does a couple of things on include.
19
- #
20
- # defines #xml_accessor, which in turn offers a way to define
21
- # both an attr_accessor and xml-annotation.
22
- # xml_accessor :name, :age
23
- #
24
- # defines #xml, a little DSLy way to add an attribute that
25
- # is later used to generate/read XML
26
- # xml :name, :age
27
- #
28
- # defines #from_xml, which takes XML and maps the structure of the
29
- # XML to your instances accessors.
30
- # Foo.new.from_xml('<name>manveru</name><age>22</age>')
31
- # # #<Foo @name='manveru', @age=22>
32
-
33
- def self.included(klass)
34
- klass.class_eval do
35
- const_set('XML_ATTRIBUTES', {})
36
-
37
- class << self
38
-
39
- # Offers a way to define
40
- # both an attr_accessor and xml-annotation.
41
- # xml_accessor :name, :age
42
-
43
- def xml_accessor(*args)
44
- args = xml(*args)
45
- attr_accessor(*args)
46
- end
47
-
48
- # A little DSLy way to add an attribute that
49
- # is later used to generate/read XML
50
- # xml :name, :age
51
-
52
- def xml(*arguments)
53
- args = []
54
- hash = nil
55
- klass = Object.const_get(self.to_s)
56
-
57
- arguments.each do |arg|
58
- if arg.respond_to?(:to_sym)
59
- args << arg.to_sym
60
- elsif arg.respond_to?(:to_hash)
61
- hash = arg
62
- end
63
- end
64
-
65
- args.each do |arg|
66
- klass::XML_ATTRIBUTES[arg] = hash
67
- end
68
- end
69
-
70
- # Which takes XML and maps the structure of the
71
- # XML to your instances accessors.
72
- # Foo.new.from_xml('<name>manveru</name><age>22</age>')
73
- # # #<Foo @name='manveru', @age=22>
74
-
75
- def from_xml(text)
76
- instance = self.new
77
-
78
- require 'hpricot'
79
-
80
- xml = Hpricot(text.to_s)
81
- attributes = instance.xml_attributes
82
-
83
- attributes.each do |attribute, opts|
84
- value = xml.at(attribute)
85
- instance.send("#{attribute}=", value.inner_html) if value
86
- end
87
- instance
88
- rescue LoadError => ex
89
- error ex
90
- ensure
91
- instance
92
- end
93
- end
94
- end
95
- end
96
-
97
- # return the XML_ATTRIBUTES of self.class
98
-
99
- def xml_attributes
100
- self.class::XML_ATTRIBUTES
101
- end
102
-
103
- # convert this instance to XML
104
-
105
- def to_xml
106
- name = self.class.name
107
- xml = xml_attributes.map do |key, opts|
108
- value = send(key)
109
-
110
- next unless value
111
- next if (opts[:type] == :attribute rescue false)
112
-
113
- if opts and not opts.empty?
114
- case opts[:type]
115
- when nil, :text : "<#{key}>#{value}</#{key}>"
116
- when :cdata : "<#{key}><![CDATA[#{value}]]></#{key}>"
117
- when :collection : value.map{|v| v.to_xml }
118
- end
119
- elsif value.respond_to?(:to_xml)
120
- value.to_xml
121
- elsif value.respond_to?(:all?) and value.all?{|v| v.respond_to?(:to_xml) }
122
- value.map{|v| v.to_xml }
123
- end
124
- end
125
-
126
- attributes = xml_attributes.select{|k, o| o && o[:type] == :attribute}
127
- attributes.map!{|k, o| %{#{k}="#{send(k)}"} }
128
-
129
- unless attributes or attributes.empty?
130
- "<#{name}>#{xml}</#{name}>"
131
- else
132
- "<#{name} #{attributes.join(' ')}>#{xml}</#{name}>"
133
- end
134
- end
135
- end
@@ -1,204 +0,0 @@
1
- # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
- # All files in this distribution are subject to the terms of the Ruby license.
3
-
4
- module Ramaze
5
- module FormHelper
6
-
7
- # Mapping different classes to an specific method on FormHelper::Control.
8
-
9
- ClassMap = {
10
- String => :text,
11
- Time => :time,
12
- Date => :date,
13
- Fixnum => :number,
14
- }
15
-
16
- # Create the contents of a <form> for Og-objects.
17
- # This can be an instance or the class itself. Depending if you
18
- # want to edit an object or create a new one.
19
- #
20
- # Please note that the enclosing <form> itself is not (yet) generated.
21
- #
22
- # attributes that have no mapping in ClassMap are silently ignored.
23
-
24
- def form obj, options = {}
25
- default = {:deny => /oid/, :submit => true}
26
- options = default.merge(options)
27
-
28
- if obj.respond_to? :serializable_attributes
29
- instance = obj.new
30
- else
31
- instance = obj
32
- obj = obj.class
33
- end
34
-
35
- attributes = obj.serializable_attributes
36
- out = []
37
-
38
- chosen_attributes(attributes, options).each do |attribute|
39
-
40
- o = OpenStruct.new :klass => obj.ann[attribute].class,
41
- :value => (instance.send(attribute) rescue nil),
42
- :name => attribute.to_s,
43
- :title => (options.has_key?(attribute) ? options[attribute] : attribute)
44
-
45
- control = obj.ann[attribute].control
46
- control = ClassMap[o.klass] unless control.is_a?(Symbol)
47
-
48
- out << Control.send(control, o) unless control.nil? or control == :none
49
- end
50
- if options[:submit] == true
51
- out << %{<input type="submit" />}
52
- elsif options[:submit]
53
- out << %{<input type="submit" value="#{options[:submit]}" />}
54
- end
55
- out.join("<br />\n")
56
- end
57
-
58
- # options #=>
59
- # { :deny => /oid/ }
60
- # { :deny => [/time/, /oid/]}
61
-
62
- def chosen_attributes(attributes, options)
63
- attributes.reject do |attribute|
64
- attribute = attribute.to_s
65
- [options[:deny]].flatten.find do |d|
66
- first_comp = attribute =~ d rescue attribute == d
67
- first_comp || attribute == d
68
- end
69
- end
70
- end
71
-
72
- # Home of all the methods that output a tag for a specific
73
- # attribute.
74
- # They take objects that respond to :value and :name, preferably
75
- # an modified OpenStruct that responds to :temp to allow for easy
76
- # forking. ( lib/ramaze/snippets/openstruct/temp.rb )
77
-
78
- module Control
79
- class << self
80
-
81
- # A simple text-control, default to 0
82
-
83
- def number o
84
- o.value ||= 0
85
- text(o)
86
- end
87
-
88
- # <input type="text" />
89
-
90
- def text o
91
- o.value ||= ""
92
- tag = ''
93
- tag << "#{o.title}: " if o.title
94
- tag << %{<input type="text" name="#{o.name}" value="#{o.value}" />}
95
- end
96
-
97
- # <textarea></textarea>
98
-
99
- def textarea o
100
- o.value ||= ""
101
- %{<textarea name="#{o.name}">#{o.value}</textarea>}
102
- end
103
-
104
- # compound of #date_day, #date_month, #date_year, #time_hour,
105
- # #time_minute and #time_second
106
-
107
- def time o
108
- o.value ||= Time.now
109
- [
110
- date_day(o.temp(:value => o.value.day)),
111
- date_month(o.temp(:value => o.value.month)),
112
- date_year(o.temp(:value => o.value.year)),
113
- time_hour(o.temp(:value => o.value.hour)),
114
- time_minute(o.temp(:value => o.value.min)),
115
- time_second(o.temp(:value => o.value.sec)),
116
- ].join("\n")
117
- end
118
-
119
- # <select name="xxx[sec]">
120
- # <option value="0">0</option>
121
- # ...
122
- # <option value="60">60</option>
123
- # </select>
124
-
125
- def time_second(o)
126
- select(o.name + '[sec]', (0...60), o.value)
127
- end
128
-
129
- # <select name="xxx[min]">
130
- # <option value="0">0</option>
131
- # ...
132
- # <option value="60">60</option>
133
- # </select>
134
-
135
- def time_minute(o)
136
- select(o.name + '[min]', (0...60), o.value)
137
- end
138
-
139
- # <select name="xxx[hour]">
140
- # <option value="1">1</option>
141
- # ...
142
- # <option value="23">23</option>
143
- # </select>
144
-
145
- def time_hour(o)
146
- select(o.name + '[hour]', (0...23), o.value)
147
- end
148
-
149
- # compound of #date_day, #date_month and #date_year
150
-
151
- def date o
152
- o.value ||= Date.today
153
- [
154
- date_day(o.temp(:value => o.value.day)),
155
- date_month(o.temp(:value => o.value.month)),
156
- date_year(o.temp(:value => o.value.year)),
157
- ].join("\n")
158
- end
159
-
160
- # <select name="xxx[day]">
161
- # <option value="1">1</option>
162
- # ...
163
- # <option value="31">31</option>
164
- # </select>
165
-
166
- def date_day(o)
167
- select(o.name + '[day]', (1..31), o.value)
168
- end
169
-
170
- # <select name="xxx[month]">
171
- # <option value="1">1950</option>
172
- # ...
173
- # <option value="12">12</option>
174
- # </select>
175
-
176
- def date_month(o)
177
- select(o.name + '[month]', (1..12), o.value)
178
- end
179
-
180
- # <select name="xxx[year]">
181
- # <option value="1950">1950</option>
182
- # ...
183
- # <option value="2050">2050</option>
184
- # </select>
185
-
186
- def date_year(o)
187
- select(o.name + '[year]', (1950..2050), o.value)
188
- end
189
-
190
- # <select>
191
- # <option></option>
192
- # </select>
193
-
194
- def select name, range, default
195
- out = %{<select name="#{name}">\n}
196
- range.each do |i|
197
- out << %{<option value="#{i}"#{' selected="selected"' if default == i}>#{i}</option>\n}
198
- end
199
- out << "</select>\n"
200
- end
201
- end
202
- end
203
- end
204
- end
@@ -1,13 +0,0 @@
1
- # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
- # All files in this distribution are subject to the terms of the Ruby license.
3
-
4
- # Extensions for OpenStruct
5
-
6
- class OpenStruct
7
-
8
- # create a new OpenStruct and fill it with a merge of the old @table and the passed hash
9
-
10
- def temp hash
11
- self.class.new(@table.merge(hash))
12
- end
13
- end
@@ -1,170 +0,0 @@
1
- # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
- # All files in this distribution are subject to the terms of the Ruby license.
3
-
4
- require 'yaml'
5
- require 'pstore'
6
- require 'fileutils'
7
- require 'set'
8
-
9
- module Ramaze::Store
10
- module YAML
11
- def self.new(*args)
12
- Manager.new(*args)
13
- end
14
-
15
- class Store < PStore
16
- def initialize( *o )
17
- @opt = ::YAML::DEFAULTS.dup
18
- if String === o.first
19
- super(o.shift)
20
- end
21
- if o.last.is_a? Hash
22
- @opt.update(o.pop)
23
- end
24
- end
25
-
26
- def dump(table = nil)
27
- @table.to_yaml(@opt)
28
- end
29
-
30
- def load(content)
31
- ::YAML::load(content)
32
- end
33
-
34
- def load_file(file)
35
- ::YAML::load(file)
36
- end
37
- end
38
-
39
- class YAMLStoreWrapper
40
-
41
- # pass on all methods inside a transaction
42
-
43
- def method_missing(meth, *args, &block)
44
- @entities.transaction do
45
- @entities.send(meth, *args, &block)
46
- end
47
- end
48
-
49
- # yield a block in a transaction, identical to #db.transaction{}
50
-
51
- def transaction
52
- @entities.transaction do
53
- yield(@entities)
54
- end
55
- end
56
-
57
- def to_yaml
58
- (@entities.instance_variable_get('@table') || {}).to_yaml
59
- end
60
-
61
- # loads the #to_yaml
62
-
63
- def original
64
- ::YAML.load_file(@store_filename) rescue {}
65
- end
66
-
67
- # available keys of the store
68
-
69
- def keys
70
- (original || {}).keys
71
- end
72
-
73
- # is the Store empty? (no keys)
74
-
75
- def empty?
76
- keys.empty?
77
- end
78
-
79
- def all
80
- original
81
- end
82
-
83
- def [](eid)
84
- transaction do |e|
85
- e[eid.to_s.to_sym]
86
- end
87
- end
88
-
89
- def []=(eid, entity)
90
- transaction do |e|
91
- e[eid.to_s.to_sym] = entity
92
- end
93
- end
94
-
95
- def each
96
- original.each do |key, value|
97
- yield key, value
98
- end
99
- end
100
-
101
- def delete eid
102
- transaction do |e|
103
- e[eid.to_s.to_sym] = nil
104
- end
105
- end
106
- end
107
-
108
- class Manager < YAMLStoreWrapper
109
- attr_accessor :store, :store_filename, :store_name, :entities
110
-
111
- def initialize name, options = {}
112
- @store_name = name
113
- @store_filename = "#{@store_name}.yaml"
114
-
115
- FileUtils.rm_f(@store_filename) if options[:destroy]
116
-
117
- @entities = Store.new(@store_filename)
118
- end
119
-
120
- def new
121
- entity = Entity.new
122
- entity.manager = self
123
- entity
124
- end
125
-
126
- def create_with hash = {}
127
- entity = new
128
- hash.each do |key, value|
129
- entity.send("#{key}=", value)
130
- end
131
- entity.save
132
- entity
133
- end
134
-
135
- def next_eid
136
- (keys.max || '`').next
137
- end
138
-
139
- def store entity
140
- if entity.eid
141
- self[entity.eid] = entity
142
- else
143
- eid = next_eid
144
- entity.eid = eid
145
- self[entity.eid] = entity
146
- end
147
- end
148
- end
149
-
150
- class Entity < OpenStruct
151
- attr_accessor :manager
152
- trait :no_properties => Set.new(%w[ manager ])
153
-
154
- def save
155
- our_name = self.manager.store_name
156
- @table.each do |key, value|
157
- if value.respond_to?(:save) and value.send(our_name) != self
158
- value.send("#{our_name}=", self)
159
- value.save
160
- end
161
- end
162
- @manager.store self
163
- end
164
-
165
- def to_yaml_properties
166
- instance_variables - self.class.ancestral_trait[:no_properties].map{|np| "@#{np}"}
167
- end
168
- end
169
- end
170
- end