fron 0.1.4 → 0.2.0rc1

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.reek +11 -0
  4. data/.rubocop.yml +54 -0
  5. data/.travis.yml +11 -0
  6. data/.yardopts +4 -0
  7. data/Changelog.md +7 -0
  8. data/Gemfile +3 -1
  9. data/Gemfile.lock +106 -15
  10. data/Rakefile +19 -15
  11. data/Readme.md +23 -0
  12. data/fron.gemspec +2 -2
  13. data/lib/fron/version.rb +2 -1
  14. data/opal/fron.rb +5 -5
  15. data/opal/fron/core.rb +3 -10
  16. data/opal/fron/core/behaviors/components.rb +42 -0
  17. data/opal/fron/core/behaviors/events.rb +27 -0
  18. data/opal/fron/core/behaviors/routes.rb +59 -0
  19. data/opal/fron/core/component.rb +64 -90
  20. data/opal/fron/core/eventable.rb +18 -0
  21. data/opal/fron/core/logger.rb +10 -1
  22. data/opal/fron/core_ext.rb +9 -0
  23. data/opal/fron/core_ext/array.rb +12 -0
  24. data/opal/fron/core_ext/date.rb +57 -0
  25. data/opal/fron/core_ext/hash.rb +52 -0
  26. data/opal/fron/core_ext/kernel.rb +57 -0
  27. data/opal/fron/core_ext/nil.rb +7 -0
  28. data/opal/fron/core_ext/numeric.rb +19 -0
  29. data/opal/fron/core_ext/object.rb +11 -0
  30. data/opal/fron/core_ext/proc.rb +19 -0
  31. data/opal/fron/{core-ext → core_ext}/string.rb +4 -0
  32. data/opal/fron/dom.rb +15 -13
  33. data/opal/fron/dom/document.rb +22 -6
  34. data/opal/fron/dom/element.rb +105 -67
  35. data/opal/fron/dom/event.rb +110 -40
  36. data/opal/fron/dom/{file-reader.rb → file_reader.rb} +6 -1
  37. data/opal/fron/dom/fragment.rb +2 -0
  38. data/opal/fron/dom/modules/attributes.rb +43 -0
  39. data/opal/fron/dom/modules/classlist.rb +26 -13
  40. data/opal/fron/dom/modules/dimensions.rb +79 -9
  41. data/opal/fron/dom/modules/element_accessor.rb +35 -0
  42. data/opal/fron/dom/modules/events.rb +67 -20
  43. data/opal/fron/dom/node.rb +98 -39
  44. data/opal/fron/dom/nodelist.rb +9 -2
  45. data/opal/fron/dom/style.rb +23 -2
  46. data/opal/fron/dom/text.rb +4 -0
  47. data/opal/fron/dom/window.rb +31 -2
  48. data/opal/fron/event_mock.rb +54 -0
  49. data/opal/fron/js/syntetic_event.js +16 -0
  50. data/opal/fron/request.rb +2 -2
  51. data/opal/fron/request/request.rb +77 -14
  52. data/opal/fron/request/response.rb +33 -6
  53. data/opal/fron/storage.rb +1 -1
  54. data/opal/fron/storage/local_storage.rb +54 -0
  55. data/opal/fron/utils/drag.rb +135 -0
  56. data/opal/fron/utils/keyboard.rb +70 -0
  57. data/opal/fron/utils/point.rb +78 -0
  58. data/opal/fron/utils/render_proc.rb +27 -0
  59. data/spec/core-ext/array_spec.rb +15 -0
  60. data/spec/core-ext/date_spec.rb +54 -0
  61. data/spec/core-ext/hash_spec.rb +18 -2
  62. data/spec/core-ext/kernel_spec.rb +57 -0
  63. data/spec/core-ext/nil_spec.rb +9 -0
  64. data/spec/core-ext/numeric_spec.rb +25 -0
  65. data/spec/core-ext/proc_spec.rb +15 -0
  66. data/spec/core-ext/string_spec.rb +11 -0
  67. data/spec/core/behaviors/events_spec.rb +25 -0
  68. data/spec/core/behaviors/routes_spec.rb +59 -0
  69. data/spec/core/component_inheritance_spec.rb +26 -16
  70. data/spec/core/component_spec.rb +25 -29
  71. data/spec/core/eventable_spec.rb +19 -19
  72. data/spec/core/logger_spec.rb +5 -6
  73. data/spec/dom/document_spec.rb +4 -5
  74. data/spec/dom/element_spec.rb +106 -15
  75. data/spec/dom/event_spec.rb +101 -61
  76. data/spec/dom/file_reader_spec.rb +11 -0
  77. data/spec/dom/fragment_spec.rb +3 -4
  78. data/spec/dom/instance_retaining_spec.rb +58 -0
  79. data/spec/dom/modules/classlist_spec.rb +18 -19
  80. data/spec/dom/modules/dimensions_spec.rb +87 -22
  81. data/spec/dom/modules/events_spec.rb +22 -8
  82. data/spec/dom/node_spec.rb +25 -17
  83. data/spec/dom/nodelist_spec.rb +2 -3
  84. data/spec/dom/style_spec.rb +6 -5
  85. data/spec/dom/text_spec.rb +4 -3
  86. data/spec/dom/window_spec.rb +24 -9
  87. data/spec/js/mocks.js +14 -0
  88. data/spec/request/request_spec.rb +34 -15
  89. data/spec/request/response_spec.rb +9 -10
  90. data/spec/spec_helper.rb +11 -0
  91. data/spec/storage/{local-storage_spec.rb → local_storage_spec.rb} +6 -7
  92. data/spec/utils/drag_spec.rb +136 -0
  93. data/spec/utils/keyboard_spec.rb +75 -0
  94. data/spec/utils/point_spec.rb +55 -0
  95. data/spec/utils/render_proc_spec.rb +18 -0
  96. metadata +58 -36
  97. data/docs/application.md +0 -7
  98. data/docs/configuration.md +0 -29
  99. data/docs/controllers.md +0 -35
  100. data/docs/routing.md +0 -63
  101. data/opal/fron/core-ext.rb +0 -5
  102. data/opal/fron/core-ext/hash.rb +0 -31
  103. data/opal/fron/core-ext/kernel.rb +0 -10
  104. data/opal/fron/core-ext/numeric.rb +0 -9
  105. data/opal/fron/core-ext/proc.rb +0 -9
  106. data/opal/fron/core/adapters/local.rb +0 -43
  107. data/opal/fron/core/adapters/rails.rb +0 -65
  108. data/opal/fron/core/application.rb +0 -42
  109. data/opal/fron/core/configuration.rb +0 -29
  110. data/opal/fron/core/controller.rb +0 -41
  111. data/opal/fron/core/model.rb +0 -90
  112. data/opal/fron/core/router.rb +0 -86
  113. data/opal/fron/storage/local-storage.rb +0 -34
  114. data/spec/core/adapter/local_spec.rb +0 -65
  115. data/spec/core/adapter/rails_spec.rb +0 -77
  116. data/spec/core/application_spec.rb +0 -35
  117. data/spec/core/configuration_spec.rb +0 -20
  118. data/spec/core/controlller_spec.rb +0 -68
  119. data/spec/core/model_spec.rb +0 -125
  120. data/spec/core/router_spec.rb +0 -124
@@ -0,0 +1,11 @@
1
+ # Object
2
+ # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
3
+ class Object
4
+ # Defines a class method
5
+ #
6
+ # @param name [String] The name of the method
7
+ # @param blk [Block] The body of the method
8
+ def meta_def(name, &blk)
9
+ (class << self; self; end).instance_eval { define_method name, &blk }
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # Proc
2
+ class Proc
3
+ # Runs the given block after the given wait period
4
+ # if called continously
5
+ #
6
+ # @param ms [Numeric] The wait period
7
+ def throttle(ms)
8
+ Native `throttle(#{self}, #{ms}, {leading: false})`
9
+ end
10
+
11
+ # Runs the given block after the given wait period
12
+ # if called continously. The wait period restarts with each call
13
+ #
14
+ # @param ms [Numeric] The wait period
15
+ # @param leading [Boolean] To run the function at the start or not
16
+ def debounce(ms, leading = false)
17
+ Native `debounce(#{self}, #{ms}, #{leading})`
18
+ end
19
+ end
@@ -1,4 +1,8 @@
1
+ # String
1
2
  class String
3
+ # Returns the camelized version of self
4
+ #
5
+ # @return [String] The camelized version
2
6
  def camelize
3
7
  `#{self}.replace(/(?:-|_|(\/))([a-z\d]*)/gi,function(m,first,second){
4
8
  return second.charAt(0).toUpperCase() + second.substr(1).toLowerCase()
@@ -1,13 +1,15 @@
1
- require './dom/modules/events'
2
- require './dom/modules/classlist'
3
- require './dom/modules/dimensions'
4
- require './dom/nodelist'
5
- require './dom/style'
6
- require './dom/node'
7
- require './dom/text'
8
- require './dom/element'
9
- require './dom/fragment'
10
- require './dom/document'
11
- require './dom/window'
12
- require './dom/event'
13
- require './dom/file-reader'
1
+ require 'fron/dom/modules/events'
2
+ require 'fron/dom/modules/classlist'
3
+ require 'fron/dom/modules/dimensions'
4
+ require 'fron/dom/modules/attributes'
5
+ require 'fron/dom/modules/element_accessor'
6
+ require 'fron/dom/nodelist'
7
+ require 'fron/dom/style'
8
+ require 'fron/dom/node'
9
+ require 'fron/dom/text'
10
+ require 'fron/dom/element'
11
+ require 'fron/dom/fragment'
12
+ require 'fron/dom/document'
13
+ require 'fron/dom/window'
14
+ require 'fron/dom/event'
15
+ require 'fron/dom/file_reader'
@@ -1,28 +1,44 @@
1
1
  module DOM
2
+ # This module is a wrapper for the native *document* object.
2
3
  module Document
3
- def self.activeElement
4
+ extend SingleForwardable
5
+ @doc = DOM::Element.new `document`
6
+
7
+ def_delegators :@doc, :find
8
+
9
+ # Returns the active element
10
+ #
11
+ # @return [DOM::Element] The element
12
+ def self.active_element
4
13
  find ':focus'
5
14
  end
6
15
 
16
+ # Returns the head element
17
+ #
18
+ # @return [DOM::Element] The head element
7
19
  def self.head
8
20
  @head ||= find 'head'
9
21
  end
10
22
 
23
+ # Returns the body element
24
+ #
25
+ # @return [DOM::Element] The body element
11
26
  def self.body
12
27
  @body ||= find 'body'
13
28
  end
14
29
 
30
+ # Returns the documents title
31
+ #
32
+ # @return [String] The title
15
33
  def self.title
16
34
  `document.title`
17
35
  end
18
36
 
37
+ # Sets the documents title with the given value
38
+ #
39
+ # @param value [String] The title
19
40
  def self.title=(value)
20
41
  `document.title = #{value}`
21
42
  end
22
-
23
- def self.find(selector)
24
- value = `document.querySelector(#{selector}) || false`
25
- value ? DOM::Element.new(value) : nil
26
- end
27
43
  end
28
44
  end
@@ -1,36 +1,60 @@
1
1
  module DOM
2
+ # Element
3
+ #
4
+ # TODO: Describe the element creation ways here
2
5
  class Element < NODE
6
+ extend ElementAccessor
7
+ include Attributes
3
8
  include ClassList
4
9
  include Dimensions
5
10
 
11
+ # @return [Style] The style object
6
12
  attr_reader :style
7
13
 
8
- EVENT_TARGET_CLASS = self
14
+ # Attribute regexp
9
15
  ATTRIBUTE_REGEXP = /\[(.*?)=(.*?)\]/
16
+
17
+ # Tag regexp
10
18
  TAG_REGEXP = /(^[A-Za-z_\-0-9]+)(.*)/
19
+
20
+ # Modifier regexp
11
21
  MODIFIER_REGEXP = /(#|\.)(.+?)(?=#|\.| |$)/
12
22
 
23
+ element_accessor :value
24
+ element_accessor :innerHTML, as: :html
25
+
26
+ element_accessor :readonly, default: false
27
+ element_accessor :checked, default: false
28
+ element_accessor :disabled, default: false
29
+
30
+ element_method :focus
31
+ element_method :blur
32
+
33
+ # Initializes a new elment based on the data
34
+ #
35
+ # @param data [*] The data
13
36
  def initialize(data)
14
37
  if `typeof #{data} === 'string'`
15
- match, tag, rest = data.match(TAG_REGEXP).to_a
38
+ tag, rest = data.match(TAG_REGEXP).to_a[1..2]
16
39
  @el = `document.createElement(#{tag})`
40
+ `#{@el}._instance = #{self}`
17
41
  rest = rest.gsub ATTRIBUTE_REGEXP do |match|
18
- m,key,value = match.match(ATTRIBUTE_REGEXP).to_a
42
+ key, value = match.match(ATTRIBUTE_REGEXP).to_a[1..2]
19
43
  self[key] = value
20
44
  ''
21
45
  end
22
46
  rest = rest.gsub MODIFIER_REGEXP do |match|
23
- m,type,value = match.match(MODIFIER_REGEXP).to_a
47
+ type, value = match.match(MODIFIER_REGEXP).to_a[1..2]
24
48
  case type
25
- when "#"
49
+ when '#'
26
50
  self['id'] = value
27
- when "."
28
- addClass value
51
+ when '.'
52
+ add_class value
29
53
  end
30
54
  ''
31
55
  end
32
- if (m = rest.match /\s(.+)$/)
33
- self.text = m[0].strip
56
+ if (match = rest.match(/\s(.+)$/))
57
+ self.text = match[0].strip
34
58
  end
35
59
  else
36
60
  super data
@@ -38,6 +62,11 @@ module DOM
38
62
  @style = Style.new @el
39
63
  end
40
64
 
65
+ # Returns whether or not the element matches the given selector
66
+ #
67
+ # @param selector [String] The selector
68
+ #
69
+ # @return [Boolean] True if matches false if not
41
70
  def matches(selector)
42
71
  %x{
43
72
  var proto = Element.prototype
@@ -50,81 +79,90 @@ module DOM
50
79
  }
51
80
  end
52
81
 
53
- # Visiblity
54
- # --------------------------------
82
+ # Hides the element
55
83
  def hide
56
84
  @style.display = 'none'
57
85
  end
58
86
 
87
+ # Shows the element
59
88
  def show
60
- @style.display = 'block'
61
- end
62
-
63
- # Attribute access
64
- # --------------------------------
65
- def [](name)
66
- `#{@el}.getAttribute(#{name})`
67
- end
68
-
69
- def []=(name,value)
70
- `#{@el}.setAttribute(#{name},#{value})`
71
- end
72
-
73
- # Traversing
74
- # --------------------------------
75
- def find(selector)
76
- value = `#{@el}.querySelector(#{selector}) || false`
77
- value ? DOM::Element.new(value) : nil
78
- end
79
-
80
- # HTML Modification
81
- # --------------------------------
82
- def html
83
- `#{@el}.innerHTML`
84
- end
85
-
86
- def html=(value)
87
- `#{@el}.innerHTML = #{value}`
88
- end
89
-
90
- def value
91
- `#{@el}.value`
92
- end
93
-
94
- def value=(value)
95
- `#{@el}.value = #{value}`
96
- end
97
-
98
- def checked
99
- `!!#{@el}.checked`
100
- end
101
-
102
- def checked=(value)
103
- `#{@el}.checked = #{value}`
104
- end
105
-
106
- def disabled
107
- `#{@el}.disabled`
108
- end
109
-
110
- def disabled=(value)
111
- `#{@el}.disabled = #{value}`
112
- end
113
-
114
- def focus
115
- `#{@el}.focus()`
89
+ @style.display = ''
116
90
  end
117
91
 
92
+ # Return the files of the element
93
+ #
94
+ # @return [Array] The files
118
95
  def files
119
96
  Native `#{@el}.files`
120
97
  end
121
98
 
99
+ # Returns the lowercased tag name of the lement
100
+ #
101
+ # @return [String] The tag name
122
102
  def tag
123
103
  `#{@el}.tagName`.downcase
124
104
  end
125
105
 
106
+ # Returns the id of the element
107
+ #
108
+ # @return [String] The id
126
109
  def id
127
110
  self['id']
128
111
  end
112
+
113
+ # Returns the element matching the given selector or nil
114
+ #
115
+ # @param selector [String] The selector
116
+ #
117
+ # @return [DOM::Element] The element
118
+ def find(selector)
119
+ DOM::Element.from_node `#{@el}.querySelector(#{selector}) || Opal.nil`
120
+ end
121
+
122
+ # Finds all of the elements matching the selector.
123
+ #
124
+ # @param selector [String] The selector
125
+ #
126
+ # @return [NodeList] The elements
127
+ def find_all(selector)
128
+ DOM::NodeList.new `Array.prototype.slice.call(#{@el}.querySelectorAll(#{selector}))`
129
+ end
130
+
131
+ # Returns the next element sibling
132
+ #
133
+ # @return [DOM::Element] The element
134
+ def next
135
+ DOM::Element.from_node `#{@el}.nextElementSibling || Opal.nil`
136
+ end
137
+
138
+ # Returns the previous element sibling
139
+ #
140
+ # @return [DOM::Element] The element
141
+ def previous
142
+ DOM::Element.from_node `#{@el}.previousElementSibling || Opal.nil`
143
+ end
144
+
145
+ # Returns whether or not the given node
146
+ # is inside the node.
147
+ #
148
+ # @param other [DOM::NODE] The other node
149
+ #
150
+ # @return [Boolean] True if contains false if not
151
+ def include?(other)
152
+ `#{@el}.contains(#{DOM::NODE.get_element(other)})`
153
+ end
154
+
155
+ # Returns the path of the elemnt
156
+ #
157
+ # @return [String] The path
158
+ def path
159
+ element = self
160
+ items = [element.tag]
161
+ while element.parent
162
+ items.unshift element.parent.tag
163
+ element = element.parent
164
+ end
165
+ items.join ' '
166
+ end
129
167
  end
130
168
  end
@@ -1,6 +1,7 @@
1
1
  module DOM
2
+ # Event
2
3
  class Event
3
-
4
+ # Special keys for converions
4
5
  SPECIAL_KEYS = {
5
6
  8 => 'backspace',
6
7
  9 => 'tab',
@@ -94,95 +95,164 @@ module DOM
94
95
  221 => ']',
95
96
  222 => '\'',
96
97
  224 => 'cmd',
97
- 57392 => 'ctrl',
98
- 63289 => 'num'
98
+ 57_392 => 'ctrl',
99
+ 63_289 => 'num'
99
100
  }
100
101
 
101
- def initialize(e,targetClass)
102
- @e = e
103
- @targetClass = targetClass
102
+ # Initializes the event
103
+ #
104
+ # @param event [Event] The native event
105
+ def initialize(event)
106
+ @event = event
107
+ end
108
+
109
+ # Runs missing method calls
110
+ #
111
+ # @param name [String] The name of the method
112
+ def method_missing(name)
113
+ `#{@event}[#{name}]`
104
114
  end
105
115
 
116
+ # Returns the string represenation of the pressed key
117
+ #
118
+ # @return [String] The pressed key
106
119
  def key
107
- return SPECIAL_KEYS[keyCode] if SPECIAL_KEYS[keyCode]
108
- `String.fromCharCode(#{keyCode}).toLowerCase()`
120
+ return SPECIAL_KEYS[key_code] if SPECIAL_KEYS[key_code]
121
+ `String.fromCharCode(#{key_code}).toLowerCase()`
109
122
  end
110
123
 
111
- def stopImmediatePropagation
112
- `#{@e}.stopImmediatePropagation()`
124
+ # Stops the immediate propagation of the event
125
+ def stop_immediate_propagation
126
+ `#{@event}.stopImmediatePropagation()`
113
127
  end
114
128
 
115
- def dataTransfer
116
- Native `#{@e}.dataTransfer`
129
+ # Returns the native dataTransfrer object
130
+ #
131
+ # @return [Object] The object
132
+ def data_transfer
133
+ Native `#{@event}.dataTransfer`
117
134
  end
118
135
 
136
+ # Returns the index of the pressed mouse button
137
+ #
138
+ # @return [Numeric] The index
119
139
  def button
120
- `#{@e}.button`
140
+ `#{@event}.button`
121
141
  end
122
142
 
143
+ # Returns the target of the event
144
+ #
145
+ # @return [DOM::NODE] The target
123
146
  def target
124
- @targetClass.new `#{@e}.target`
147
+ DOM::Element.from_node `#{@event}.target`
125
148
  end
126
149
 
127
- def charCode
128
- `#{@e}.charCode`
150
+ # Returns the character code of the pressed key
151
+ #
152
+ # @return [Numeric] The code
153
+ def char_code
154
+ `#{@event}.charCode`
129
155
  end
130
156
 
131
- def keyCode
132
- `#{@e}.keyCode`
157
+ # Returns the key code of the pressed key
158
+ #
159
+ # @return [Numeric] The code
160
+ def key_code
161
+ `#{@event}.keyCode`
133
162
  end
134
163
 
164
+ # Stops the event
135
165
  def stop
136
- preventDefault
137
- stopPropagation
166
+ prevent_default
167
+ stop_immediate_propagation
168
+ stop_propagation
169
+ end
170
+
171
+ # Returns whether the default was prevented or not
172
+ #
173
+ # @return [Boolean] True if it has false if not
174
+ def default_prevented?
175
+ `#{@event}.defaultPrevented`
138
176
  end
139
177
 
140
- def preventDefault
141
- `#{@e}.preventDefault()`
178
+ # Prevents the default action of the event
179
+ def prevent_default
180
+ `#{@event}.preventDefault()`
142
181
  end
143
182
 
144
- def stopPropagation
145
- `#{@e}.stopPropagation()`
183
+ # Stops the propagation of the event
184
+ def stop_propagation
185
+ `#{@event}.stopPropagation()`
146
186
  end
147
187
 
148
- def pageX
149
- `#{@e}.pageX`
188
+ # Returns the pageX coordinate of the event
189
+ #
190
+ # @return [Numeric] The coordinate
191
+ def page_x
192
+ `#{@event}.pageX`
150
193
  end
151
194
 
152
- def pageY
153
- `#{@e}.pageY`
195
+ # Returns the pageY coordinate of the event
196
+ #
197
+ # @return [Numeric] The coordinate
198
+ def page_y
199
+ `#{@event}.pageY`
154
200
  end
155
201
 
156
- def screenX
157
- `#{@e}.screenX`
202
+ # Returns the screenX coordinate of the event
203
+ #
204
+ # @return [Numeric] The coordinate
205
+ def screen_x
206
+ `#{@event}.screenX`
158
207
  end
159
208
 
160
- def screenY
161
- `#{@e}.screenY`
209
+ # Returns the screenY coordinate of the event
210
+ #
211
+ # @return [Numeric] The coordinate
212
+ def screen_y
213
+ `#{@event}.screenY`
162
214
  end
163
215
 
164
- def clientX
165
- `#{@e}.clientX`
216
+ # Returns the clientX coordinate of the event
217
+ #
218
+ # @return [Numeric] The coordinate
219
+ def client_x
220
+ `#{@event}.clientX`
166
221
  end
167
222
 
168
- def clientY
169
- `#{@e}.clientY`
223
+ # Returns the clientY coordinate of the event
224
+ #
225
+ # @return [Numeric] The coordinate
226
+ def client_y
227
+ `#{@event}.clientY`
170
228
  end
171
229
 
230
+ # Returns whether the alt key has been pressed
231
+ #
232
+ # @return [Boolan] True if pressed false if not
172
233
  def alt?
173
- `#{@e}.altKey`
234
+ `#{@event}.altKey`
174
235
  end
175
236
 
237
+ # Returns whether the shift key has been pressed
238
+ #
239
+ # @return [Boolan] True if pressed false if not
176
240
  def shift?
177
- `#{@e}.shiftKey`
241
+ `#{@event}.shiftKey`
178
242
  end
179
243
 
244
+ # Returns whether the control key has been pressed
245
+ #
246
+ # @return [Boolan] True if pressed false if not
180
247
  def ctrl?
181
- `#{@e}.ctrlKey`
248
+ `#{@event}.ctrlKey`
182
249
  end
183
250
 
251
+ # Returns whether the meta (apple) key has been pressed
252
+ #
253
+ # @return [Boolan] True if pressed false if not
184
254
  def meta?
185
- `#{@e}.metaKey`
255
+ `#{@event}.metaKey`
186
256
  end
187
257
  end
188
258
  end