glimmer-dsl-tk 0.0.3 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
- # Copyright (c) 2020 Andy Maleh
2
- #
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -22,7 +22,7 @@
22
22
  require 'glimmer/tk/widget_proxy'
23
23
 
24
24
  module Glimmer
25
- module Tk
25
+ module Tk
26
26
  # Proxy for Tk::Tile::Button
27
27
  #
28
28
  # Follows the Proxy Design Pattern
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ # Proxy for Tk::Tile::TEntry
27
+ #
28
+ # Follows the Proxy Design Pattern
29
+ class EntryProxy < WidgetProxy
30
+ def validatecommand_block=(proc)
31
+ tk.validatecommand(proc)
32
+ end
33
+ def invalidcommand_block=(proc)
34
+ tk.invalidcommand(proc)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,5 @@
1
- # Copyright (c) 2020 Andy Maleh
2
- #
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -22,7 +22,7 @@
22
22
  require 'glimmer/tk/widget_proxy'
23
23
 
24
24
  module Glimmer
25
- module Tk
25
+ module Tk
26
26
  # Proxy for Tk::Tile::Frame
27
27
  #
28
28
  # Follows the Proxy Design Pattern
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ # Proxy for Tk::Tile::TLabel
27
+ #
28
+ # Follows the Proxy Design Pattern
29
+ class LabelProxy < WidgetProxy
30
+ # TODO specify attribute setters
31
+ # def tk_widget_has_attribute_setter?(attribute)
32
+ # if ['anchor', 'justify'].include?(attribute.to_s)
33
+ # true
34
+ # else
35
+ # super
36
+ # end
37
+ # end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,60 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ # Custom list widget implementation
27
+ class ListProxy < WidgetProxy
28
+ def initialize(underscored_widget_name, parent_proxy, args)
29
+ super('treeview', parent_proxy, args)
30
+ @tk.show = 'tree'
31
+ end
32
+
33
+ def widget_custom_attribute_mapping
34
+ @widget_custom_attribute_mapping ||= {
35
+ ::Tk::Tile::Treeview => {
36
+ 'items' => {
37
+ getter: {name: 'items', invoker: lambda { |widget, args| tk.children('').map(&:text) }},
38
+ setter: {name: 'items=', invoker: lambda { |widget, args|
39
+ @tk.delete @tk.children('')
40
+ args.first.each do |child|
41
+ @tk.insert('', 'end', :text => child)
42
+ end
43
+ }},
44
+ },
45
+ 'selection' => {
46
+ getter: {name: 'selection', invoker: lambda { |widget, args| @tk.selection.map(&:text) }},
47
+ setter: {name: 'selection=', invoker: lambda { |widget, args|
48
+ selection_args = args.first.is_a?(Array) ? args.first : [args.first]
49
+ selection_items = selection_args.map do |arg|
50
+ @tk.children('').detect {|item| item.text == arg}
51
+ end
52
+ @tk.selection_set(*selection_items)
53
+ }},
54
+ },
55
+ },
56
+ }
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
- # Copyright (c) 2020 Andy Maleh
2
- #
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -22,7 +22,7 @@
22
22
  require 'glimmer/tk/widget_proxy'
23
23
 
24
24
  module Glimmer
25
- module Tk
25
+ module Tk
26
26
  # Proxy for Tk::Tile::Notebook
27
27
  #
28
28
  # Follows the Proxy Design Pattern
@@ -1,5 +1,5 @@
1
- # Copyright (c) 2020 Andy Maleh
2
- #
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -1,5 +1,5 @@
1
- # Copyright (c) 2020 Andy Maleh
2
- #
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -29,7 +29,13 @@ module Glimmer
29
29
 
30
30
  DEFAULT_INITIALIZERS = {
31
31
  'combobox' => lambda do |tk|
32
- tk.textvariable = ::TkVariable.new
32
+ tk.textvariable = ::TkVariable.new
33
+ end,
34
+ 'label' => lambda do |tk|
35
+ tk.textvariable = ::TkVariable.new
36
+ end,
37
+ 'entry' => lambda do |tk|
38
+ tk.textvariable = ::TkVariable.new
33
39
  end,
34
40
  }
35
41
 
@@ -44,9 +50,30 @@ module Glimmer
44
50
  Glimmer::Tk.const_get(class_name)
45
51
  rescue
46
52
  Glimmer::Tk::WidgetProxy
47
- end
48
- end
49
- end
53
+ end
54
+ end
55
+
56
+ # This supports widgets in and out of basic Tk
57
+ def tk_widget_class_for(underscored_widget_name)
58
+ tk_widget_class_basename = underscored_widget_name.camelcase(:upper)
59
+ potential_tk_widget_class_names = [
60
+ "::Tk::Tile::#{tk_widget_class_basename}",
61
+ "::Tk::#{tk_widget_class_basename}",
62
+ "::Tk#{tk_widget_class_basename}",
63
+ "::Glimmer::Tk::#{tk_widget_class_basename}Proxy",
64
+ ]
65
+ tk_widget_class = nil
66
+ potential_tk_widget_class_names.each do |tk_widget_name|
67
+ begin
68
+ tk_widget_class = eval(tk_widget_name)
69
+ break
70
+ rescue RuntimeError, SyntaxError, NameError => e
71
+ Glimmer::Config.logger.debug e.full_message
72
+ end
73
+ end
74
+ tk_widget_class
75
+ end
76
+ end
50
77
 
51
78
  # Initializes a new Tk Widget
52
79
  #
@@ -56,14 +83,9 @@ module Glimmer
56
83
  @args = args
57
84
  tk_widget_class = self.class.tk_widget_class_for(underscored_widget_name)
58
85
  @tk = tk_widget_class.new(@parent_proxy.tk, *args)
59
- begin
60
- # a common widget initializer
61
- @tk.grid
62
- rescue => e
63
- # catching error just in case a widget doesn't support it
64
- Glimmer::Config.logger.debug e.full_message
65
- end
66
- DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk)
86
+ # a common widget initializer
87
+ @tk.grid
88
+ DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk)
67
89
  @parent_proxy.post_initialize_child(self)
68
90
  end
69
91
 
@@ -81,57 +103,63 @@ module Glimmer
81
103
  !!tk_widget_class_for(underscored_widget_name)
82
104
  end
83
105
 
84
- # This supports widgets in and out of basic Tk
85
- def self.tk_widget_class_for(underscored_widget_name)
86
- tk_widget_name = "::Tk::Tile::#{underscored_widget_name.camelcase(:upper)}"
87
- tk_widget_class = eval(tk_widget_name)
88
- tk_widget_class
89
- rescue SyntaxError, NameError => e
90
- puts e.full_message
91
- nil
92
- rescue => e
93
- puts e.full_message
94
- nil
106
+ def tk_widget_has_attribute_setter?(attribute)
107
+ result = nil
108
+ begin
109
+ # TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
110
+ @tk.send(attribute_setter(attribute), @tk.send(attribute))
111
+ result = true
112
+ rescue => e
113
+ result = false
114
+ end
115
+ result
95
116
  end
96
117
 
97
- def tk_widget_has_attribute?(attribute_name)
118
+ def tk_widget_has_attribute_getter_setter?(attribute)
98
119
  result = nil
99
- begin
100
- # TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
101
- @tk.send(attribute_setter(attribute_name), @tk.send(attribute_name))
120
+ begin
121
+ # TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
122
+ @tk.send(attribute, @tk.send(attribute))
102
123
  result = true
103
124
  rescue => e
104
125
  result = false
105
126
  end
106
- result
127
+ result
107
128
  end
108
129
 
109
- def has_attribute?(attribute_name, *args)
110
- tk_widget_has_attribute?(attribute_name) || respond_to?(attribute_setter(attribute_name), args)
130
+ def has_attribute?(attribute, *args)
131
+ (widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]) ||
132
+ tk_widget_has_attribute_setter?(attribute) ||
133
+ tk_widget_has_attribute_getter_setter?(attribute) ||
134
+ respond_to?(attribute_setter(attribute), args)
111
135
  end
112
136
 
113
- def set_attribute(attribute_name, *args)
114
- widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute_name.to_s]
137
+ def set_attribute(attribute, *args)
138
+ widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
115
139
  if widget_custom_attribute
116
140
  widget_custom_attribute[:setter][:invoker].call(@tk, args)
117
- elsif tk_widget_has_attribute?(attribute_name)
118
- @tk.send(attribute_setter(attribute_name), *args) unless @tk.send(attribute_name) == args.first
141
+ elsif tk_widget_has_attribute_setter?(attribute)
142
+ @tk.send(attribute_setter(attribute), *args) unless @tk.send(attribute) == args.first
143
+ elsif tk_widget_has_attribute_getter_setter?(attribute)
144
+ @tk.send(attribute, *args) unless @tk.send(attribute) == args.first
119
145
  else
120
- send(attribute_setter(attribute_name), args)
146
+ send(attribute_setter(attribute), args)
121
147
  end
122
148
  end
123
149
 
124
- def get_attribute(attribute_name)
125
- widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute_name.to_s]
150
+ def get_attribute(attribute)
151
+ widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
126
152
  if widget_custom_attribute
127
153
  widget_custom_attribute[:getter][:invoker].call(@tk, args)
154
+ elsif tk_widget_has_attribute_getter_setter?(attribute)
155
+ @tk.send(attribute)
128
156
  else
129
- @tk.send(attribute_name)
157
+ send(attribute)
130
158
  end
131
- end
159
+ end
132
160
 
133
- def attribute_setter(attribute_name)
134
- "#{attribute_name}="
161
+ def attribute_setter(attribute)
162
+ "#{attribute}="
135
163
  end
136
164
 
137
165
  def widget_custom_attribute_mapping
@@ -142,13 +170,25 @@ module Glimmer
142
170
  setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
143
171
  },
144
172
  },
173
+ ::Tk::Tile::TLabel => {
174
+ 'text' => {
175
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
176
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
177
+ },
178
+ },
179
+ ::Tk::Tile::TEntry => {
180
+ 'text' => {
181
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
182
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first unless @text_variable_edit }},
183
+ },
184
+ },
145
185
  }
146
186
  end
147
187
 
148
- def widget_property_listener_installers
149
- @tk_widget_property_listener_installers ||= {
188
+ def widget_attribute_listener_installers
189
+ @tk_widget_attribute_listener_installers ||= {
150
190
  ::Tk::Tile::TCombobox => {
151
- :text => lambda do |observer|
191
+ 'text' => lambda do |observer|
152
192
  if observer.is_a?(Glimmer::DataBinding::ModelBinding)
153
193
  model = observer.model
154
194
  options_model_property = observer.property_name + '_options'
@@ -158,29 +198,51 @@ module Glimmer
158
198
  observer.call(@tk.textvariable.value)
159
199
  }
160
200
  end,
161
- }
201
+ },
202
+ ::Tk::Tile::TEntry => {
203
+ 'text' => lambda do |observer|
204
+ tk.validate = 'key'
205
+ tk.validatecommand { |new_tk_variable|
206
+ @text_variable_edit = new_tk_variable.value != @tk.textvariable.value
207
+ if @text_variable_edit
208
+ observer.call(new_tk_variable.value)
209
+ @text_variable_edit = nil
210
+ true
211
+ else
212
+ false
213
+ end
214
+ }
215
+ end,
216
+ },
162
217
  }
163
218
  end
164
219
 
165
- def add_observer(observer, property_name)
166
- property_listener_installers = @tk.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
167
- widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
220
+ def add_observer(observer, attribute)
221
+ attribute_listener_installers = @tk.class.ancestors.map {|ancestor| widget_attribute_listener_installers[ancestor]}.compact
222
+ widget_listener_installers = attribute_listener_installers.map{|installer| installer[attribute.to_s]}.compact if !attribute_listener_installers.empty?
168
223
  widget_listener_installers.to_a.first&.call(observer)
169
- end
224
+ end
170
225
 
171
226
  def content(&block)
172
227
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, &block)
173
228
  end
174
229
 
175
230
  def method_missing(method, *args, &block)
176
- tk.send(method, *args, &block)
231
+ method = method.to_s
232
+ if args.empty? && block.nil? && widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method]
233
+ get_attribute(method)
234
+ elsif widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method.sub(/=$/, '')] && method.end_with?('=') && block.nil?
235
+ set_attribute(method.sub(/=$/, ''), *args)
236
+ else
237
+ tk.send(method, *args, &block)
238
+ end
177
239
  rescue => e
178
240
  Glimmer::Config.logger.debug {"Neither WidgetProxy nor #{tk.class.name} can handle the method ##{method}"}
179
- super
241
+ super(method.to_sym, *args, &block)
180
242
  end
181
243
 
182
244
  def respond_to?(method, *args, &block)
183
- super ||
245
+ super ||
184
246
  tk.respond_to?(method, *args, &block)
185
247
  end
186
248
  end