hobo 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/bin/hobo +21 -22
  2. data/hobo_files/plugin/CHANGES.txt +429 -4
  3. data/hobo_files/plugin/Rakefile +2 -2
  4. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +6 -5
  5. data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +2 -2
  6. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +20 -15
  7. data/hobo_files/plugin/generators/hobo_model/templates/model.rb +1 -0
  8. data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +2 -0
  9. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_base.css +1 -2
  10. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.css +4 -3
  11. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +94 -12
  12. data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +5 -183
  13. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +1 -1
  14. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +23 -1
  15. data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +2 -0
  16. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +3 -1
  17. data/hobo_files/plugin/init.rb +18 -7
  18. data/hobo_files/plugin/lib/active_record/has_many_association.rb +2 -2
  19. data/hobo_files/plugin/lib/extensions.rb +56 -12
  20. data/hobo_files/plugin/lib/hobo.rb +25 -88
  21. data/hobo_files/plugin/lib/hobo/composite_model.rb +2 -0
  22. data/hobo_files/plugin/lib/hobo/controller.rb +40 -20
  23. data/hobo_files/plugin/lib/hobo/dryml.rb +122 -106
  24. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +2 -1
  25. data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +3 -2
  26. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +19 -3
  27. data/hobo_files/plugin/lib/hobo/dryml/template.rb +40 -25
  28. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +41 -20
  29. data/hobo_files/plugin/lib/hobo/email_address.rb +4 -1
  30. data/hobo_files/plugin/lib/hobo/enum_string.rb +50 -0
  31. data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +36 -0
  32. data/hobo_files/plugin/lib/hobo/field_spec.rb +4 -7
  33. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +47 -44
  34. data/hobo_files/plugin/lib/hobo/html_string.rb +2 -0
  35. data/hobo_files/plugin/lib/hobo/markdown_string.rb +2 -0
  36. data/hobo_files/plugin/lib/hobo/model.rb +158 -89
  37. data/hobo_files/plugin/lib/hobo/model_controller.rb +422 -376
  38. data/hobo_files/plugin/lib/hobo/model_queries.rb +1 -1
  39. data/hobo_files/plugin/lib/hobo/model_router.rb +174 -0
  40. data/hobo_files/plugin/lib/hobo/password_string.rb +2 -0
  41. data/hobo_files/plugin/lib/hobo/percentage.rb +14 -0
  42. data/hobo_files/plugin/lib/hobo/plugins.rb +4 -4
  43. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +10 -2
  44. data/hobo_files/plugin/lib/hobo/text.rb +3 -3
  45. data/hobo_files/plugin/lib/hobo/textile_string.rb +2 -0
  46. data/hobo_files/plugin/lib/hobo/undefined.rb +3 -2
  47. data/hobo_files/plugin/lib/hobo/{authenticated_user.rb → user.rb} +10 -3
  48. data/hobo_files/plugin/lib/hobo/user_controller.rb +27 -23
  49. data/hobo_files/plugin/tags/core.dryml +8 -2
  50. data/hobo_files/plugin/tags/rapid.dryml +52 -40
  51. data/hobo_files/plugin/tags/rapid_document_tags.dryml +15 -11
  52. data/hobo_files/plugin/tags/rapid_editing.dryml +41 -9
  53. data/hobo_files/plugin/tags/rapid_forms.dryml +136 -36
  54. data/hobo_files/plugin/tags/rapid_navigation.dryml +2 -2
  55. data/hobo_files/plugin/tags/rapid_pages.dryml +204 -221
  56. data/hobo_files/plugin/tags/rapid_plus.dryml +8 -6
  57. data/hobo_files/plugin/tags/rapid_support.dryml +2 -3
  58. metadata +44 -42
  59. data/hobo_files/plugin/lib/hobo/define_tags.rb +0 -56
  60. data/hobo_files/plugin/lib/hobo/http_parameters.rb +0 -225
@@ -59,7 +59,7 @@ ul.account_nav { font-size: 80%; clear:right; }
59
59
 
60
60
  .flash { margin: 10px 30px; background: white; border: 2px solid #aaf; padding: 10px; text-align: center; }
61
61
 
62
- #page {
62
+ .page_wrapper {
63
63
  width:800px;
64
64
  background-color: white;
65
65
  margin-left:auto;
@@ -1,6 +1,28 @@
1
1
  <include src="plugins/hobo/tags/rapid"/>
2
2
 
3
- <def tag="Page" attrs="title_prefix, title">
3
+ <def tag="Page" extend_with="theme">
4
+ <PageWithoutTheme merge>
5
+ <wrapper>
6
+ <div id="page_top">
7
+ <div id="page_right">
8
+ <div id="page_bottom">
9
+ <div id="page_left">
10
+ <div id="page_corner02">
11
+ <div id="page_corner04">
12
+ <div id="page_corner03">
13
+ <div id="page_corner01">
14
+ <div id="page_inner_top">
15
+ <default_tagbody/>
16
+ </div></div></div></div></div></div></div></div></div>
17
+ </wrapper>
18
+
19
+ <stylesheets><default_tagbody/><theme_stylesheet/></stylesheets>
20
+
21
+ </PageWithoutTheme>
22
+ </def>
23
+
24
+
25
+ <def tag="OldPage" attrs="title_prefix, title">
4
26
  <% title ||= type_name + ": " + name(:no_wrapper => true) %>
5
27
  <doctype version="HTML 4.01 Transitional"/>
6
28
  <html>
@@ -2,4 +2,6 @@ class <%= class_name %>Controller < ApplicationController
2
2
 
3
3
  hobo_user_controller
4
4
 
5
+ auto_actions :all, :except => :create
6
+
5
7
  end
@@ -1,11 +1,13 @@
1
1
  class <%= class_name %> < ActiveRecord::Base
2
2
 
3
- hobo_user_model :username
3
+ hobo_user_model
4
4
 
5
5
  fields do
6
6
  username :string
7
7
  timestamps
8
8
  end
9
+
10
+ set_login_attr :username
9
11
 
10
12
  alias_attribute :to_s, :username
11
13
 
@@ -1,3 +1,4 @@
1
+ # Monkey patches, ooh ooh
1
2
  require 'extensions'
2
3
  require 'rexml'
3
4
  require 'active_record/has_many_association'
@@ -9,6 +10,7 @@ require 'hobo'
9
10
  require 'hobo/dryml'
10
11
 
11
12
  require 'hobo/model'
13
+ require 'hobo/field_declaration_dsl'
12
14
 
13
15
  require 'hobo/dryml/template'
14
16
  require 'hobo/dryml/taglib'
@@ -19,23 +21,33 @@ require 'hobo/plugins'
19
21
 
20
22
  require 'extensions/test_case' if RAILS_ENV == "test"
21
23
 
24
+ # Rich data types
25
+ require "hobo/html_string"
26
+ require "hobo/markdown_string"
27
+ require "hobo/textile_string"
28
+ require "hobo/password_string"
29
+ require "hobo/text"
30
+ require "hobo/email_address"
31
+ require "hobo/enum_string"
32
+ require "hobo/percentage"
33
+
22
34
 
23
35
  ActionView::Base.register_template_handler("dryml", Hobo::Dryml::TemplateHandler)
24
36
 
25
37
  class ActionController::Base
26
38
 
27
39
  def self.hobo_user_controller(model=nil)
40
+ @model = model
28
41
  include Hobo::ModelController
29
- self.model = model if model
30
42
  include Hobo::UserController
31
43
  end
32
44
 
33
45
  def self.hobo_model_controller(model=nil)
46
+ @model = model
34
47
  include Hobo::ModelController
35
- self.model = model if model
36
48
  end
37
49
 
38
- def self.hobo_controller(model=nil)
50
+ def self.hobo_controller
39
51
  include Hobo::Controller
40
52
  end
41
53
 
@@ -45,13 +57,12 @@ class ActiveRecord::Base
45
57
  def self.hobo_model
46
58
  include Hobo::Model
47
59
  end
48
- def self.hobo_user_model(login_attr=nil, &b)
60
+ def self.hobo_user_model
49
61
  include Hobo::Model
50
- include Hobo::AuthenticatedUser
51
- set_login_attr(login_attr, &b) if login_attr
62
+ include Hobo::User
52
63
  end
53
64
  end
54
65
 
55
66
  # Default settings
56
67
 
57
- Hobo.developer_features = ["development", "test"].include?(RAILS_ENV) if Hobo.developer_features? == nil
68
+ Hobo.developer_features = RAILS_ENV.in?(["development", "test"]) if Hobo.developer_features?.nil?
@@ -28,10 +28,10 @@ module ActiveRecord::Associations
28
28
  if loaded?
29
29
  target.include?(record)
30
30
  else
31
- find(record.id) && true rescue false
31
+ (r = find(record.id)) && r == record rescue false
32
32
  end
33
33
  end
34
-
34
+
35
35
 
36
36
  def member_class
37
37
  proxy_reflection.klass
@@ -24,13 +24,29 @@ class Module
24
24
  aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
25
25
  yield(aliased_target, punctuation) if block_given?
26
26
  without = "#{aliased_target}_without_#{feature}#{punctuation}"
27
- unless without.in?(instance_methods)
27
+ unless instance_methods.include?(without)
28
28
  alias_method without, target
29
29
  alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
30
30
  end
31
31
  end
32
32
 
33
33
 
34
+ def alias_tag_chain(tag, feature)
35
+ if tag.to_s =~ /^[A-Z]/
36
+ without = "#{tag}Without#{feature.to_s.camelize}"
37
+ with = "#{tag}With#{feature.to_s.camelize}"
38
+ else
39
+ without = "#{tag}_without_#{feature}"
40
+ with = "#{tag}_with_#{feature}"
41
+ end
42
+
43
+ unless instance_methods.include?(without)
44
+ alias_method without, tag
45
+ alias_method tag, with
46
+ end
47
+ end
48
+
49
+
34
50
  # Fix delegate so it doesn't go bang if 'to' is nil
35
51
  def delegate(*methods)
36
52
  options = methods.pop
@@ -46,7 +62,7 @@ class Module
46
62
  EOS
47
63
  end
48
64
  end
49
-
65
+
50
66
  private
51
67
 
52
68
  def bool_attr_accessor(*args)
@@ -77,7 +93,7 @@ module Kernel
77
93
 
78
94
  def it() It.new end
79
95
  alias its it
80
-
96
+
81
97
  end
82
98
 
83
99
 
@@ -148,13 +164,41 @@ end
148
164
 
149
165
 
150
166
  class SafeNil
151
- def self.instance
152
- @instance ||= SafeNil.new
167
+ include Singleton
168
+
169
+ def method_missing(method, *args, &b)
170
+ return nil unless nil.respond_to? method
171
+ nil.send(method, *args, &b) rescue nil
172
+ end
173
+ end
174
+
175
+ alias DelegateClass_without_safe_nil DelegateClass
176
+ def DelegateClass(klass)
177
+ c = DelegateClass_without_safe_nil(klass)
178
+ c.class_eval do
179
+ def _?
180
+ self
181
+ end
182
+ end
183
+ c
184
+ end
185
+
186
+
187
+
188
+ class TrueClass
189
+
190
+ def implies(x)
191
+ x
153
192
  end
154
193
 
155
- def method_missing(*args, &b)
156
- nil.send(*args, &b) rescue nil
194
+ end
195
+
196
+ class FalseClass
197
+
198
+ def implies(x)
199
+ true
157
200
  end
201
+
158
202
  end
159
203
 
160
204
 
@@ -168,10 +212,10 @@ module Enumerable
168
212
  not_found
169
213
  end
170
214
 
171
- def every(proc)
172
- map(&proc)
215
+ def every(method, *args)
216
+ map { |x| x.send(method, *args) }
173
217
  end
174
-
218
+
175
219
  def map_with_index
176
220
  res = []
177
221
  each_with_index {|x, i| res << yield(x, i)}
@@ -218,9 +262,9 @@ class Hash
218
262
  res
219
263
  end
220
264
 
221
- def map_hash
265
+ def map_hash(&b)
222
266
  res = {}
223
- each {|k,v| res[k] = yield(k,v) }
267
+ each {|k,v| res[k] = b.arity == 1 ? yield(v) : yield(k, v) }
224
268
  res
225
269
  end
226
270
 
@@ -88,7 +88,7 @@ module Hobo
88
88
 
89
89
  def dom_id(obj, attr=nil)
90
90
  if obj.nil?
91
- raise HoboError, "Tried to get dom id of nil.#{attr}" if attr
91
+ raise ArgumentError, "Tried to get dom id of nil.#{attr}" if attr
92
92
  return 'nil'
93
93
  end
94
94
 
@@ -98,11 +98,13 @@ module Hobo
98
98
  elsif obj.is_a?(Class)
99
99
  return type_id(obj)
100
100
  elsif !obj.respond_to?(:typed_id)
101
- if attr
102
- return dom_id(get_field(obj, attr))
103
- else
104
- raise ArgumentError, "Can't create dom id for #{obj.inspect}"
105
- end
101
+ return (if attr
102
+ dom_id(get_field(obj, attr))
103
+ elsif obj.respond_to?(:id)
104
+ "#{obj.class.name.underscore}_#{obj.id}"
105
+ else
106
+ raise ArgumentError, "Can't create dom id for #{obj.inspect}"
107
+ end)
106
108
  end
107
109
  attr ? "#{obj.typed_id}_#{attr}" : obj.typed_id
108
110
  end
@@ -138,84 +140,12 @@ module Hobo
138
140
  results
139
141
  end
140
142
 
141
- def add_routes(map)
142
- begin
143
- ActiveRecord::Base.connection.reconnect! unless ActiveRecord::Base.connection.active?
144
- rescue
145
- # No database, no routes
146
- return
147
- end
148
-
149
- require "#{RAILS_ROOT}/app/controllers/application" unless Object.const_defined? :ApplicationController
150
- require "#{RAILS_ROOT}/app/assemble.rb" if File.exists? "#{RAILS_ROOT}/app/assemble.rb"
151
-
152
- for model in Hobo.models
153
- controller_name = "#{model.name.pluralize}Controller"
154
- controller = controller_name.constantize if (Object.const_defined? controller_name) ||
155
- File.exists?("#{RAILS_ROOT}/app/controllers/#{controller_name.underscore}.rb")
156
-
157
- if controller
158
- web_name = model.name.underscore.pluralize.downcase
159
-
160
- # Simple support for composite models, we might later need a CompositeModelController
161
- if model < Hobo::CompositeModel
162
- map.connect "#{web_name}/:id", :controller => web_name, :action => 'show'
163
-
164
- elsif controller < Hobo::ModelController
165
- map.resources web_name, :collection => { :completions => :get }
166
-
167
- for collection in controller.collections
168
- new_method = Hobo.simple_has_many_association?(model.reflections[collection])
169
- Hobo.add_collection_routes(map, web_name, collection, new_method)
170
- end
171
-
172
- for method in controller.web_methods
173
- map.named_route("#{web_name.singularize}_#{method}",
174
- "#{web_name}/:id/#{method}",
175
- :controller => web_name,
176
- :action => method.to_s,
177
- :conditions => { :method => :post })
178
- end
179
-
180
- for view in controller.show_actions
181
- map.named_route("#{web_name.singularize}_#{view}",
182
- "#{web_name}/:id/#{view}",
183
- :controller => web_name,
184
- :action => view.to_s,
185
- :conditions => { :method => :get })
186
- end
187
-
188
- if controller < Hobo::UserController
189
- prefix = web_name == "users" ? "" : "#{web_name.singularize}_"
190
- map.named_route("#{web_name.singularize}_login", "#{prefix}login",
191
- :controller => web_name, :action => 'login')
192
- map.named_route("#{web_name.singularize}_logout", "#{prefix}logout",
193
- :controller => web_name, :action => 'logout')
194
- map.named_route("#{web_name.singularize}_signup", "#{prefix}signup",
195
- :controller => web_name, :action => 'signup')
196
- end
197
- end
198
- end
199
- end
200
- end
201
-
202
-
203
- def add_collection_routes(map, controller_name, collection_name, new_method)
204
- singular_name = collection_name.to_s.singularize
205
- map.with_options :controller => controller_name, :conditions => { :method => :get } do |m|
206
- m.named_route("#{controller_name.singularize}_#{collection_name}",
207
- "#{controller_name}/:id/#{collection_name}",
208
- :action => "show_#{collection_name}")
209
-
210
- m.named_route("new_#{controller_name.singularize}_#{singular_name}",
211
- "#{controller_name}/:id/#{collection_name}/new",
212
- :action => "new_#{singular_name}") if new_method
213
- end
143
+ def add_routes(m)
144
+ Hobo::ModelRouter.add_routes(m)
214
145
  end
215
146
 
216
-
217
- def all_controllers
218
- Hobo.models.map {|m| m.name.underscore.pluralize}
147
+ def all_models
148
+ Hobo.models.map { |m| m.name.underscore }
219
149
  end
220
150
 
221
151
 
@@ -229,7 +159,8 @@ module Hobo
229
159
 
230
160
 
231
161
  def get_field(object, field)
232
- if field.to_s =~ /\d+/
162
+ return nil if object.nil?
163
+ if field.to_s =~ /^\d+$/
233
164
  object[field.to_i]
234
165
  else
235
166
  object.send(field)
@@ -248,6 +179,7 @@ module Hobo
248
179
 
249
180
  field, parent = nil
250
181
  path.each do |field|
182
+ return nil if object.nil?
251
183
  parent = object
252
184
  object = get_field(parent, field)
253
185
  end
@@ -281,15 +213,20 @@ module Hobo
281
213
 
282
214
  refl = object.class.reflections[field.to_sym] if object.is_a?(ActiveRecord::Base)
283
215
 
284
- # has_many and polymorphic associations are not editable (for now)
285
- return false if refl and (refl.macro == :has_many or refl.options[:polymorphic] or refl.macro == :has_one)
216
+ # has_one and polymorphic associations are not editable (for now)
217
+ return false if refl and (refl.options[:polymorphic] or refl.macro == :has_one)
286
218
 
287
219
  if object.has_hobo_method?(:editable_by?)
288
220
  check_permission(:edit, person, object, field.to_sym)
221
+ elsif object.has_hobo_method?("#{field}_editable_by?")
222
+ object.send("#{field}_editable_by?", person)
289
223
  else
290
224
  # Fake an edit test by setting the field in question to
291
225
  # Hobo::Undefined and then testing for update permission
292
226
 
227
+ # This technique is not suitable for has_many associations
228
+ return false if refl._?.macro == :has_many
229
+
293
230
  current = object.send(field)
294
231
  new = object.duplicate
295
232
 
@@ -346,10 +283,10 @@ module Hobo
346
283
 
347
284
  if field
348
285
  field = field.to_sym if field.is_a? String
349
- return false if object.is_a?(ActiveRecord::Base) and object.class.never_show?(field)
286
+ return false if object.class.respond_to?(:never_show?) && object.class.never_show?(field)
350
287
  else
351
288
  # Special support for classes (can view instances?)
352
- if object.is_a?(Class) and object < ActiveRecord::Base
289
+ if object.is_a?(Class) and object < Hobo::Model
353
290
  object = object.new
354
291
  elsif Hobo.simple_has_many_association?(object)
355
292
  object = object.new
@@ -357,7 +294,7 @@ module Hobo
357
294
  end
358
295
  viewable = check_permission(:view, person, object, field)
359
296
  if viewable and field and
360
- ( (field_val = get_field(object, field)).is_a?(ActiveRecord::Base) or field_val.is_a?(Array) )
297
+ ( (field_val = get_field(object, field)).is_a?(Hobo::Model) or field_val.is_a?(Array) )
361
298
  # also ask the current value if it is viewable
362
299
  can_view?(person, field_val)
363
300
  else
@@ -64,6 +64,8 @@ module Hobo
64
64
  objects = self.class.models.map {|m| instance_variable_get("@#{m.underscore}")}
65
65
  objects.every(:id).join("_")
66
66
  end
67
+
68
+ alias_method :to_param, :id
67
69
 
68
70
  end
69
71
 
@@ -4,19 +4,27 @@ module Hobo
4
4
 
5
5
  include AuthenticationSupport
6
6
 
7
- def self.included(base)
8
- if base.is_a?(Class)
9
- included_in_class(base)
7
+ class << self
8
+
9
+ def included(base)
10
+ if base.is_a?(Class)
11
+ included_in_class(base)
12
+ end
10
13
  end
11
- end
12
-
13
- def self.included_in_class(klass)
14
- klass.extend(ClassMethods)
15
- klass.class_eval do
16
- alias_method_chain :redirect_to, :object_url
17
- @included_taglibs = []
14
+
15
+ def included_in_class(klass)
16
+ klass.extend(ClassMethods)
17
+ klass.class_eval do
18
+ alias_method_chain :redirect_to, :object_url
19
+ @included_taglibs = []
20
+ end
21
+ Hobo::HoboHelper.add_to_controller(klass)
22
+ end
23
+
24
+ def controller_and_view_for(page_path)
25
+ page_path.match(/(.*)\/([^\/]+)/)[1..2]
18
26
  end
19
- Hobo::HoboHelper.add_to_controller(klass)
27
+
20
28
  end
21
29
 
22
30
  module ClassMethods
@@ -27,27 +35,30 @@ module Hobo
27
35
  @included_taglibs << if options[:from_plugin]
28
36
  'plugins/' + options[:from_plugin] + '/taglibs/' + src
29
37
  else
30
- src
38
+ src.to_s
31
39
  end
32
40
  end
33
41
  end
34
42
 
43
+
35
44
  protected
36
45
 
37
- def redirect_to_with_object_url(destination, view=nil)
46
+ def redirect_to_with_object_url(destination, *args)
38
47
  if destination.is_a?(String, Hash, Symbol)
39
48
  redirect_to_without_object_url(destination)
40
49
  else
41
- redirect_to_without_object_url(object_url(destination, view))
50
+ redirect_to_without_object_url(object_url(destination, *args))
42
51
  end
43
52
  end
44
53
 
45
- def hobo_ajax_response(this=nil, results={})
46
- this ||= @this
47
- part_page = params[:part_page]
54
+
55
+ def hobo_ajax_response(*args)
56
+ results = args.extract_options!
57
+ this = args.first || @this
58
+ page_path = params[:page_path]
48
59
  r = params[:render]
49
60
  if r
50
- ajax_update_response(this, part_page, r.values, results)
61
+ ajax_update_response(this, page_path, r.values, results)
51
62
  true
52
63
  else
53
64
  false
@@ -55,9 +66,9 @@ module Hobo
55
66
  end
56
67
 
57
68
 
58
- def ajax_update_response(this, part_page, render_specs, results={})
69
+ def ajax_update_response(this, page_path, render_specs, results={})
59
70
  add_variables_to_assigns
60
- renderer = Hobo::Dryml.page_renderer(@template, [], part_page) if part_page
71
+ renderer = Hobo::Dryml.page_renderer(@template, [], page_path) if page_path
61
72
 
62
73
  render :update do |page|
63
74
  page << "var _update = typeof Hobo == 'undefined' ? Element.update : Hobo.updateElement;"
@@ -129,3 +140,12 @@ module Hobo
129
140
 
130
141
  end
131
142
  end
143
+
144
+
145
+ class ActionController::Base
146
+
147
+ def home_page
148
+ ""
149
+ end
150
+
151
+ end