ProMotion 1.0.4 → 1.1.0.rc1
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.
- checksums.yaml +4 -4
- data/ProMotion.gemspec +3 -2
- data/README.md +10 -7
- data/app/screens/basic_screen.rb +12 -0
- data/bin/promotion +45 -0
- data/lib/ProMotion/cocoatouch/table_view_controller.rb +2 -2
- data/lib/ProMotion/cocoatouch/view_controller.rb +2 -2
- data/lib/ProMotion/containers/split_screen.rb +6 -1
- data/lib/ProMotion/containers/tabs.rb +12 -1
- data/lib/ProMotion/delegate/delegate_module.rb +16 -2
- data/lib/ProMotion/delegate/delegate_notifications.rb +7 -7
- data/lib/ProMotion/map/map_screen_annotation.rb +10 -1
- data/lib/ProMotion/map/map_screen_module.rb +8 -3
- data/lib/ProMotion/pro_motion.rb +1 -1
- data/lib/ProMotion/screen/screen_module.rb +35 -16
- data/lib/ProMotion/screen/screen_navigation.rb +11 -13
- data/lib/ProMotion/table/extensions/indexable.rb +2 -2
- data/lib/ProMotion/table/extensions/searchable.rb +4 -3
- data/lib/ProMotion/table/grouped_table.rb +7 -2
- data/lib/ProMotion/table/table.rb +54 -47
- data/lib/ProMotion/thirdparty/formotion_screen.rb +5 -3
- data/lib/ProMotion/version.rb +1 -1
- data/lib/ProMotion/view/styling.rb +33 -20
- data/resources/test.png +0 -0
- data/spec/functional/func_map_screen_spec.rb +60 -3
- data/spec/functional/func_screen_spec.rb +29 -6
- data/spec/functional/func_searchable_table_spec.rb +13 -1
- data/spec/functional/func_split_screen_spec.rb +8 -0
- data/spec/functional/func_table_screen_spec.rb +28 -23
- data/spec/functional/func_web_screen_spec.rb +1 -1
- data/spec/helpers/custom_title_view.rb +4 -0
- data/spec/helpers/home_screen.rb +6 -0
- data/spec/helpers/table_screen.rb +23 -27
- data/spec/helpers/table_screen_formotion.rb +5 -0
- data/spec/helpers/table_screen_searchable.rb +10 -0
- data/spec/helpers/test_delegate_colors.rb +17 -0
- data/spec/helpers/test_helper.rb +5 -0
- data/spec/unit/delegate_spec.rb +79 -1
- data/spec/unit/map_spec.rb +22 -0
- data/spec/unit/screen_helpers_spec.rb +44 -35
- data/spec/unit/screen_spec.rb +45 -6
- data/spec/unit/split_screen_open_screen_spec.rb +1 -1
- data/spec/unit/tables/formotion_screen_spec.rb +6 -0
- data/spec/unit/tables/table_module_spec.rb +28 -2
- data/spec/unit/tables/table_view_cell_spec.rb +5 -4
- data/spec/unit/view_helper_spec.rb +21 -10
- metadata +28 -6
- data/resources/test.jpeg +0 -0
@@ -23,8 +23,8 @@ module ProMotion
|
|
23
23
|
elsif args[:in_tab] && self.tab_bar
|
24
24
|
present_view_controller_in_tab_bar_controller screen, args[:in_tab]
|
25
25
|
|
26
|
-
elsif self.
|
27
|
-
push_view_controller screen
|
26
|
+
elsif self.navigationController
|
27
|
+
push_view_controller screen, self.navigationController, args[:animated].nil? ? true : args[:animated]
|
28
28
|
|
29
29
|
else
|
30
30
|
open_root_screen (screen.navigationController || screen)
|
@@ -55,7 +55,7 @@ module ProMotion
|
|
55
55
|
if self.modal?
|
56
56
|
close_modal_screen args
|
57
57
|
|
58
|
-
elsif self.
|
58
|
+
elsif self.navigationController
|
59
59
|
close_nav_screen args
|
60
60
|
send_on_return(args) # TODO: this would be better implemented in a callback or view_did_disappear.
|
61
61
|
|
@@ -76,14 +76,13 @@ module ProMotion
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
def push_view_controller(vc, nav_controller=nil)
|
80
|
-
unless self.
|
79
|
+
def push_view_controller(vc, nav_controller=nil, animated=true)
|
80
|
+
unless self.navigationController
|
81
81
|
PM.logger.error "You need a nav_bar if you are going to push #{vc.to_s} onto it."
|
82
82
|
end
|
83
|
-
nav_controller ||= self.
|
83
|
+
nav_controller ||= self.navigationController
|
84
84
|
vc.first_screen = false if vc.respond_to?(:first_screen=)
|
85
|
-
|
86
|
-
nav_controller.pushViewController(vc, animated: true)
|
85
|
+
nav_controller.pushViewController(vc, animated: animated)
|
87
86
|
end
|
88
87
|
|
89
88
|
protected
|
@@ -113,7 +112,7 @@ module ProMotion
|
|
113
112
|
|
114
113
|
def ensure_wrapper_controller_in_place(screen, args={})
|
115
114
|
unless args[:close_all] || args[:modal] || args[:in_detail] || args[:in_master]
|
116
|
-
screen.
|
115
|
+
screen.navigationController ||= self.navigationController
|
117
116
|
screen.tab_bar ||= self.tab_bar if screen.respond_to?("tab_bar=")
|
118
117
|
end
|
119
118
|
end
|
@@ -127,7 +126,6 @@ module ProMotion
|
|
127
126
|
if vc
|
128
127
|
|
129
128
|
if vc.is_a?(UINavigationController)
|
130
|
-
screen.navigation_controller = vc if screen.respond_to?("navigation_controller=")
|
131
129
|
push_view_controller(screen, vc)
|
132
130
|
else
|
133
131
|
# TODO: This should probably open the vc, shouldn't it?
|
@@ -150,12 +148,12 @@ module ProMotion
|
|
150
148
|
def close_nav_screen(args={})
|
151
149
|
args[:animated] = true unless args.has_key?(:animated)
|
152
150
|
if args[:to_screen] == :root
|
153
|
-
self.
|
151
|
+
self.navigationController.popToRootViewControllerAnimated args[:animated]
|
154
152
|
elsif args[:to_screen] && args[:to_screen].is_a?(UIViewController)
|
155
153
|
self.parent_screen = args[:to_screen]
|
156
|
-
self.
|
154
|
+
self.navigationController.popToViewController(args[:to_screen], animated: args[:animated])
|
157
155
|
else
|
158
|
-
self.
|
156
|
+
self.navigationController.popViewControllerAnimated(args[:animated])
|
159
157
|
end
|
160
158
|
end
|
161
159
|
|
@@ -2,9 +2,9 @@ module ProMotion
|
|
2
2
|
module Table
|
3
3
|
module Indexable
|
4
4
|
def table_data_index
|
5
|
-
return nil if
|
5
|
+
return nil if self.promotion_table_data.filtered || !self.class.get_indexable
|
6
6
|
|
7
|
-
index =
|
7
|
+
index = self.promotion_table_data.sections.collect{ |section| section[:title][0] }
|
8
8
|
index.unshift("{search}") if self.class.get_searchable
|
9
9
|
index
|
10
10
|
end
|
@@ -42,19 +42,20 @@ module ProMotion
|
|
42
42
|
######### iOS methods, headless camel case #######
|
43
43
|
|
44
44
|
def searchDisplayController(controller, shouldReloadTableForSearchString:search_string)
|
45
|
-
|
45
|
+
self.promotion_table_data.search(search_string)
|
46
46
|
true
|
47
47
|
end
|
48
48
|
|
49
49
|
def searchDisplayControllerWillEndSearch(controller)
|
50
|
-
|
51
|
-
@promotion_table_data_data = nil
|
50
|
+
self.promotion_table_data.stop_searching
|
52
51
|
self.table_view.setScrollEnabled true
|
53
52
|
self.table_view.reloadData
|
53
|
+
@table_search_display_controller.delegate.will_end_search if @table_search_display_controller.delegate.respond_to? "will_end_search"
|
54
54
|
end
|
55
55
|
|
56
56
|
def searchDisplayControllerWillBeginSearch(controller)
|
57
57
|
self.table_view.setScrollEnabled false
|
58
|
+
@table_search_display_controller.delegate.will_begin_search if @table_search_display_controller.delegate.respond_to? "will_begin_search"
|
58
59
|
end
|
59
60
|
end
|
60
61
|
end
|
@@ -1,7 +1,12 @@
|
|
1
1
|
module ProMotion
|
2
2
|
module GroupedTable
|
3
|
-
|
4
|
-
|
3
|
+
module GroupedTableClassMethods
|
4
|
+
def table_style
|
5
|
+
UITableViewStyleGrouped
|
6
|
+
end
|
7
|
+
end
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(GroupedTableClassMethods)
|
5
10
|
end
|
6
11
|
end
|
7
12
|
end
|
@@ -6,22 +6,14 @@ module ProMotion
|
|
6
6
|
include ProMotion::Table::Refreshable
|
7
7
|
include ProMotion::Table::Indexable
|
8
8
|
|
9
|
-
|
10
|
-
@table_view ||= begin
|
11
|
-
t = UITableView.alloc.initWithFrame(self.view.frame, style: table_style)
|
12
|
-
t.dataSource = self
|
13
|
-
t.delegate = self
|
14
|
-
t
|
15
|
-
end
|
16
|
-
end
|
9
|
+
attr_reader :promotion_table_data
|
17
10
|
|
18
|
-
def
|
19
|
-
|
11
|
+
def table_view
|
12
|
+
self.view
|
20
13
|
end
|
21
14
|
|
22
15
|
def screen_setup
|
23
16
|
check_table_data
|
24
|
-
set_up_table_view
|
25
17
|
set_up_searchable
|
26
18
|
set_up_refreshable
|
27
19
|
end
|
@@ -30,11 +22,8 @@ module ProMotion
|
|
30
22
|
PM.logger.error "Missing #table_data method in TableScreen #{self.class.to_s}." unless self.respond_to?(:table_data)
|
31
23
|
end
|
32
24
|
|
33
|
-
def
|
34
|
-
|
35
|
-
table_view
|
36
|
-
|
37
|
-
self.view = self.create_table_view_from_data(self.table_data)
|
25
|
+
def promotion_table_data
|
26
|
+
@promotion_table_data ||= TableData.new(table_data, table_view)
|
38
27
|
end
|
39
28
|
|
40
29
|
def set_up_searchable
|
@@ -53,37 +42,31 @@ module ProMotion
|
|
53
42
|
end
|
54
43
|
end
|
55
44
|
|
56
|
-
def create_table_view_from_data(data)
|
57
|
-
@promotion_table_data = TableData.new(data, table_view)
|
58
|
-
table_view
|
59
|
-
end
|
60
|
-
|
61
45
|
def searching?
|
62
|
-
|
46
|
+
self.promotion_table_data.filtered
|
63
47
|
end
|
64
48
|
|
65
49
|
def original_search_string
|
66
|
-
|
50
|
+
self.promotion_table_data.original_search_string
|
67
51
|
end
|
68
52
|
|
69
53
|
def search_string
|
70
|
-
|
54
|
+
self.promotion_table_data.search_string
|
71
55
|
end
|
72
56
|
|
73
57
|
def update_table_view_data(data)
|
74
|
-
|
75
|
-
@promotion_table_data.data = data
|
58
|
+
self.promotion_table_data.data = data
|
76
59
|
table_view.reloadData
|
77
60
|
end
|
78
61
|
|
79
62
|
# Methods to retrieve data
|
80
63
|
|
81
64
|
def section_at_index(index)
|
82
|
-
|
65
|
+
self.promotion_table_data.section(index)
|
83
66
|
end
|
84
67
|
|
85
68
|
def cell_at_section_and_index(section, index)
|
86
|
-
|
69
|
+
self.promotion_table_data.cell(section: section, index: index)
|
87
70
|
end
|
88
71
|
|
89
72
|
def trigger_action(action, arguments)
|
@@ -121,9 +104,9 @@ module ProMotion
|
|
121
104
|
|
122
105
|
index_paths.each do |index_path|
|
123
106
|
delete_cell = false
|
124
|
-
delete_cell = send(:on_cell_deleted,
|
107
|
+
delete_cell = send(:on_cell_deleted, self.promotion_table_data.cell(index_path: index_path)) if self.respond_to?("on_cell_deleted:")
|
125
108
|
unless delete_cell == false
|
126
|
-
|
109
|
+
self.promotion_table_data.delete_cell(index_path: index_path)
|
127
110
|
deletable_index_paths << index_path
|
128
111
|
end
|
129
112
|
end
|
@@ -136,7 +119,7 @@ module ProMotion
|
|
136
119
|
params[:index] = params[:index_path].row
|
137
120
|
end
|
138
121
|
|
139
|
-
data_cell =
|
122
|
+
data_cell = self.promotion_table_data.cell(section: params[:section], index: params[:index])
|
140
123
|
return UITableViewCell.alloc.init unless data_cell # No data?
|
141
124
|
|
142
125
|
table_cell = create_table_cell(data_cell)
|
@@ -165,28 +148,24 @@ module ProMotion
|
|
165
148
|
|
166
149
|
########## Cocoa touch methods #################
|
167
150
|
def numberOfSectionsInTableView(table_view)
|
168
|
-
|
151
|
+
Array(self.promotion_table_data.data).length
|
169
152
|
end
|
170
153
|
|
171
154
|
# Number of cells
|
172
155
|
def tableView(table_view, numberOfRowsInSection:section)
|
173
|
-
|
174
|
-
0
|
156
|
+
self.promotion_table_data.section_length(section)
|
175
157
|
end
|
176
158
|
|
177
159
|
def tableView(table_view, titleForHeaderInSection:section)
|
178
|
-
|
160
|
+
section = section_at_index(section) || return
|
161
|
+
section[:title]
|
179
162
|
end
|
180
163
|
|
181
164
|
# Set table_data_index if you want the right hand index column (jumplist)
|
182
165
|
def sectionIndexTitlesForTableView(table_view)
|
183
|
-
return
|
184
|
-
|
185
|
-
|
186
|
-
self.table_data_index
|
187
|
-
else
|
188
|
-
nil
|
189
|
-
end
|
166
|
+
return if self.promotion_table_data.filtered
|
167
|
+
return self.table_data_index if self.respond_to?(:table_data_index)
|
168
|
+
nil
|
190
169
|
end
|
191
170
|
|
192
171
|
def tableView(table_view, cellForRowAtIndexPath:index_path)
|
@@ -194,18 +173,18 @@ module ProMotion
|
|
194
173
|
end
|
195
174
|
|
196
175
|
def tableView(table_view, willDisplayCell: table_cell, forRowAtIndexPath: index_path)
|
197
|
-
data_cell =
|
176
|
+
data_cell = self.promotion_table_data.cell(index_path: index_path)
|
198
177
|
table_cell.backgroundColor = data_cell[:background_color] || UIColor.whiteColor
|
199
178
|
table_cell.send(:restyle!) if table_cell.respond_to?(:restyle!)
|
200
179
|
end
|
201
180
|
|
202
181
|
def tableView(table_view, heightForRowAtIndexPath:index_path)
|
203
|
-
(
|
182
|
+
(self.promotion_table_data.cell(index_path: index_path)[:height] || table_view.rowHeight).to_f
|
204
183
|
end
|
205
184
|
|
206
185
|
def tableView(table_view, didSelectRowAtIndexPath:index_path)
|
207
|
-
data_cell =
|
208
|
-
table_view.deselectRowAtIndexPath(index_path, animated: true)
|
186
|
+
data_cell = self.promotion_table_data.cell(index_path: index_path)
|
187
|
+
table_view.deselectRowAtIndexPath(index_path, animated: true) unless data_cell[:keep_selection] == true
|
209
188
|
|
210
189
|
data_cell[:arguments] ||= {}
|
211
190
|
data_cell[:arguments][:cell] = data_cell if data_cell[:arguments].is_a?(Hash) # TODO: Should we really do this?
|
@@ -214,7 +193,7 @@ module ProMotion
|
|
214
193
|
end
|
215
194
|
|
216
195
|
def tableView(table_view, editingStyleForRowAtIndexPath: index_path)
|
217
|
-
data_cell =
|
196
|
+
data_cell = self.promotion_table_data.cell(index_path: index_path)
|
218
197
|
|
219
198
|
case data_cell[:editing_style]
|
220
199
|
when nil, :none
|
@@ -250,6 +229,30 @@ module ProMotion
|
|
250
229
|
delete_row(index_paths, animation)
|
251
230
|
end
|
252
231
|
|
232
|
+
# Section view methods
|
233
|
+
def tableView(table_view, viewForHeaderInSection: index)
|
234
|
+
section = section_at_index(index)
|
235
|
+
|
236
|
+
if section[:title_view]
|
237
|
+
klass = section[:title_view]
|
238
|
+
view = klass.new if klass.respond_to?(:new)
|
239
|
+
view.title = section[:title] if view.respond_to?(:title=)
|
240
|
+
view
|
241
|
+
else
|
242
|
+
nil
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def tableView(table_view, heightForHeaderInSection: index)
|
247
|
+
section = section_at_index(index)
|
248
|
+
|
249
|
+
if section[:title_view] || (section[:title] && !section[:title].empty?)
|
250
|
+
section[:title_view_height] || tableView.sectionHeaderHeight
|
251
|
+
else
|
252
|
+
0.0
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
253
256
|
protected
|
254
257
|
|
255
258
|
def map_row_animation_symbol(symbol)
|
@@ -268,6 +271,10 @@ module ProMotion
|
|
268
271
|
end
|
269
272
|
|
270
273
|
module TableClassMethods
|
274
|
+
def table_style
|
275
|
+
UITableViewStylePlain
|
276
|
+
end
|
277
|
+
|
271
278
|
# Searchable
|
272
279
|
def searchable(params={})
|
273
280
|
@searchable_params = params
|
@@ -2,7 +2,7 @@ module ProMotion
|
|
2
2
|
if defined?(Formotion) && defined?(Formotion::FormController)
|
3
3
|
class FormotionScreen < Formotion::FormController
|
4
4
|
include ProMotion::ScreenModule
|
5
|
-
|
5
|
+
|
6
6
|
def self.new(args = {})
|
7
7
|
s = self.alloc.initWithStyle(UITableViewStyleGrouped)
|
8
8
|
s.on_create(args) if s.respond_to?(:on_create)
|
@@ -19,6 +19,8 @@ module ProMotion
|
|
19
19
|
s.tableView.allowsSelectionDuringEditing = true
|
20
20
|
s.title = t
|
21
21
|
|
22
|
+
s.form.on_submit { |form| s.on_submit(form) if s.respond_to?(:on_submit) }
|
23
|
+
|
22
24
|
s
|
23
25
|
end
|
24
26
|
|
@@ -28,11 +30,11 @@ module ProMotion
|
|
28
30
|
self.form.controller = self
|
29
31
|
self.tableView.reloadData
|
30
32
|
end
|
31
|
-
|
33
|
+
|
32
34
|
def screen_setup
|
33
35
|
self.title = self.class.send(:get_title)
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
def loadView
|
37
39
|
super
|
38
40
|
self.send(:on_load) if self.respond_to?(:on_load)
|
data/lib/ProMotion/version.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module ProMotion
|
2
2
|
module Styling
|
3
3
|
include Conversions
|
4
|
-
|
4
|
+
|
5
5
|
def set_attributes(element, args = {})
|
6
|
+
args = get_attributes_from_symbol(args)
|
6
7
|
args.each { |k, v| set_attribute(element, k, v) }
|
7
8
|
element
|
8
9
|
end
|
@@ -34,6 +35,8 @@ module ProMotion
|
|
34
35
|
args[:resize].each { |r| attributes[:autoresizingMask] |= map_resize_symbol(r) }
|
35
36
|
end
|
36
37
|
|
38
|
+
args[:left] = args.delete(:x) if args[:x]
|
39
|
+
args[:top] = args.delete(:y) if args[:y]
|
37
40
|
if [:left, :top, :width, :height].select{ |a| args[a] && args[a] != :auto }.length == 4
|
38
41
|
attributes[:frame] = CGRectMake(args[:left], args[:top], args[:width], args[:height])
|
39
42
|
end
|
@@ -64,33 +67,35 @@ module ProMotion
|
|
64
67
|
end
|
65
68
|
nil
|
66
69
|
end
|
67
|
-
|
70
|
+
|
68
71
|
def add(element, attrs = {})
|
69
72
|
add_to view_or_self, element, attrs
|
70
73
|
end
|
71
74
|
alias :add_element :add
|
72
75
|
alias :add_view :add
|
73
76
|
|
74
|
-
def remove(
|
75
|
-
|
76
|
-
element = nil
|
77
|
+
def remove(elements)
|
78
|
+
Array(elements).each(&:removeFromSuperview)
|
77
79
|
end
|
78
80
|
alias :remove_element :remove
|
79
81
|
alias :remove_view :remove
|
80
82
|
|
81
|
-
def add_to(parent_element,
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
def add_to(parent_element, elements, attrs = {})
|
84
|
+
attrs = get_attributes_from_symbol(attrs)
|
85
|
+
Array(elements).each do |element|
|
86
|
+
parent_element.addSubview element
|
87
|
+
if attrs && attrs.length > 0
|
88
|
+
set_attributes(element, attrs)
|
89
|
+
set_easy_attributes(parent_element, element, attrs)
|
90
|
+
end
|
86
91
|
end
|
87
|
-
|
92
|
+
elements
|
88
93
|
end
|
89
|
-
|
94
|
+
|
90
95
|
def view_or_self
|
91
96
|
self.respond_to?(:view) ? self.view : self
|
92
97
|
end
|
93
|
-
|
98
|
+
|
94
99
|
# These three color methods are stolen from BubbleWrap.
|
95
100
|
def rgb_color(r,g,b)
|
96
101
|
rgba_color(r,g,b,1)
|
@@ -103,7 +108,7 @@ module ProMotion
|
|
103
108
|
|
104
109
|
def hex_color(str)
|
105
110
|
hex_color = str.gsub("#", "")
|
106
|
-
case hex_color.size
|
111
|
+
case hex_color.size
|
107
112
|
when 3
|
108
113
|
colors = hex_color.scan(%r{[0-9A-Fa-f]}).map{ |el| (el * 2).to_i(16) }
|
109
114
|
when 6
|
@@ -111,16 +116,24 @@ module ProMotion
|
|
111
116
|
else
|
112
117
|
raise ArgumentError
|
113
118
|
end
|
114
|
-
|
119
|
+
|
115
120
|
if colors.size == 3
|
116
121
|
rgb_color(colors[0], colors[1], colors[2])
|
117
122
|
else
|
118
123
|
raise ArgumentError
|
119
|
-
end
|
124
|
+
end
|
120
125
|
end
|
121
|
-
|
126
|
+
|
122
127
|
protected
|
123
|
-
|
128
|
+
|
129
|
+
def get_attributes_from_symbol(attrs)
|
130
|
+
return attrs if attrs.is_a?(Hash)
|
131
|
+
PM.logger.error "#{attrs} styling method is not defined" unless self.respond_to?(attrs)
|
132
|
+
new_attrs = send(attrs)
|
133
|
+
PM.logger.error "#{attrs} should return a hash" unless new_attrs.is_a?(Hash)
|
134
|
+
new_attrs
|
135
|
+
end
|
136
|
+
|
124
137
|
def map_resize_symbol(symbol)
|
125
138
|
@_resize_symbols ||= {
|
126
139
|
left: UIViewAutoresizingFlexibleLeftMargin,
|
@@ -128,10 +141,10 @@ module ProMotion
|
|
128
141
|
top: UIViewAutoresizingFlexibleTopMargin,
|
129
142
|
bottom: UIViewAutoresizingFlexibleBottomMargin,
|
130
143
|
width: UIViewAutoresizingFlexibleWidth,
|
131
|
-
height: UIViewAutoresizingFlexibleHeight
|
144
|
+
height: UIViewAutoresizingFlexibleHeight
|
132
145
|
}
|
133
146
|
@_resize_symbols[symbol] || symbol
|
134
147
|
end
|
135
|
-
|
148
|
+
|
136
149
|
end
|
137
150
|
end
|