hyper-vis 1.0.0.lap34 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +154 -23
- data/hyper-vis.gemspec +5 -5
- data/lib/hyper-vis.rb +7 -0
- data/lib/hyperloop/vis/graph2d/component.rb +16 -0
- data/lib/hyperloop/vis/graph2d/mixin.rb +89 -0
- data/lib/hyperloop/vis/graph3d/component.rb +15 -0
- data/lib/hyperloop/vis/graph3d/mixin.rb +79 -0
- data/lib/hyperloop/vis/network/mixin.rb +1 -1
- data/lib/hyperloop/vis/timeline/component.rb +16 -0
- data/lib/hyperloop/vis/timeline/mixin.rb +89 -0
- data/lib/hyperloop/vis/version.rb +1 -1
- data/lib/vis.rb +4 -1
- data/lib/vis/data_common.rb +46 -0
- data/lib/vis/data_set.rb +6 -1
- data/lib/vis/graph2d.rb +145 -0
- data/lib/vis/graph3d.rb +135 -0
- data/lib/vis/network.rb +187 -8
- data/lib/vis/railtie.rb +7 -0
- data/lib/vis/timeline.rb +338 -0
- data/lib/vis/utilities.rb +7 -199
- data/spec/test_app/Gemfile +2 -4
- data/spec/test_app/app/assets/stylesheets/application.css +2 -1
- data/spec/test_app/db/schema.rb +28 -0
- data/spec/vis_graph2d_component_spec.rb +89 -0
- data/spec/vis_graph2d_spec.rb +304 -0
- data/spec/vis_graph3d_component_spec.rb +124 -0
- data/spec/vis_graph3d_spec.rb +247 -0
- data/spec/vis_timeline_component_spec.rb +89 -0
- data/spec/vis_timeline_spec.rb +425 -0
- metadata +37 -13
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Hyperloop::Vis::Graph3d::Component', js: true do
|
4
|
+
|
5
|
+
it 'creates a component by using the mixin and renders it' do
|
6
|
+
mount 'OuterComponent' do
|
7
|
+
class VisComponent
|
8
|
+
include Hyperloop::Vis::Graph3d::Mixin
|
9
|
+
|
10
|
+
render_with_dom_node do |dom_node, data, options|
|
11
|
+
net = Vis::Graph3d.new(dom_node, data, options)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
class OuterComponent < Hyperloop::Component
|
15
|
+
render do
|
16
|
+
options = {
|
17
|
+
width: '600px',
|
18
|
+
height: '600px',
|
19
|
+
style: 'surface',
|
20
|
+
show_perspective: true,
|
21
|
+
show_grid: true,
|
22
|
+
show_shadow: false,
|
23
|
+
keep_aspect_ratio: true,
|
24
|
+
vertical_ratio: 0.5
|
25
|
+
}
|
26
|
+
dataset = Vis::DataSet.new
|
27
|
+
steps = 50 # number of datapoints will be steps*steps
|
28
|
+
axis_max = 314
|
29
|
+
axis_step = axis_max / steps
|
30
|
+
(0...axis_max).step(axis_step) do |x|
|
31
|
+
(0...axis_max).step(axis_step) do |y|
|
32
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
33
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
DIV { VisComponent(vis_data: dataset, options: options)}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
expect(page.body).to include('<canvas')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'creates a component by inheriting and renders it' do
|
44
|
+
mount 'OuterComponent' do
|
45
|
+
class VisComponent < Hyperloop::Vis::Graph3d::Component
|
46
|
+
render_with_dom_node do |dom_node, data, options|
|
47
|
+
net = Vis::Graph3d.new(dom_node, data, options)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
class OuterComponent < Hyperloop::Component
|
51
|
+
render do
|
52
|
+
options = {
|
53
|
+
width: '600px',
|
54
|
+
height: '600px',
|
55
|
+
style: 'surface',
|
56
|
+
show_perspective: true,
|
57
|
+
show_grid: true,
|
58
|
+
show_shadow: false,
|
59
|
+
keep_aspect_ratio: true,
|
60
|
+
vertical_ratio: 0.5
|
61
|
+
}
|
62
|
+
dataset = Vis::DataSet.new
|
63
|
+
steps = 50 # number of datapoints will be steps*steps
|
64
|
+
axis_max = 314
|
65
|
+
axis_step = axis_max / steps
|
66
|
+
(0...axis_max).step(axis_step) do |x|
|
67
|
+
(0...axis_max).step(axis_step) do |y|
|
68
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
69
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
DIV { VisComponent(vis_data: dataset, options: options)}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
expect(page.body).to include('<canvas')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'actually passes the params to the component' do
|
80
|
+
mount 'OuterComponent' do
|
81
|
+
class VisComponent < Hyperloop::Vis::Graph3d::Component
|
82
|
+
def self.passed_data
|
83
|
+
@@passed_data
|
84
|
+
end
|
85
|
+
def self.passed_options
|
86
|
+
@@passed_options
|
87
|
+
end
|
88
|
+
render_with_dom_node do |dom_node, data, options|
|
89
|
+
@@passed_data = data
|
90
|
+
@@passed_options = options
|
91
|
+
net = Vis::Graph3d.new(dom_node, data, options)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
class OuterComponent < Hyperloop::Component
|
95
|
+
render do
|
96
|
+
options = {
|
97
|
+
width: '600px',
|
98
|
+
height: '600px',
|
99
|
+
style: 'surface',
|
100
|
+
show_perspective: true,
|
101
|
+
show_grid: true,
|
102
|
+
show_shadow: false,
|
103
|
+
keep_aspect_ratio: true,
|
104
|
+
vertical_ratio: 0.5
|
105
|
+
}
|
106
|
+
dataset = Vis::DataSet.new
|
107
|
+
steps = 50 # number of datapoints will be steps*steps
|
108
|
+
axis_max = 314
|
109
|
+
axis_step = axis_max / steps
|
110
|
+
(0...axis_max).step(axis_step) do |x|
|
111
|
+
(0...axis_max).step(axis_step) do |y|
|
112
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
113
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
DIV { VisComponent(vis_data: dataset, options: options)}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
expect(page.body).to include('<canvas')
|
121
|
+
expect_evaluate_ruby('VisComponent.passed_data.is_a?(Vis::DataSet)').to eq(true)
|
122
|
+
expect_evaluate_ruby('VisComponent.passed_options.has_key?(:show_shadow)').to eq(true)
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Vis::Graph3d', js: true do
|
4
|
+
|
5
|
+
it 'creates a new Graph with options' do
|
6
|
+
expect_evaluate_ruby do
|
7
|
+
options = {
|
8
|
+
width: '600px',
|
9
|
+
height: '600px',
|
10
|
+
style: 'surface',
|
11
|
+
show_perspective: true,
|
12
|
+
show_grid: true,
|
13
|
+
show_shadow: false,
|
14
|
+
keep_aspect_ratio: true,
|
15
|
+
vertical_ratio: 0.5
|
16
|
+
}
|
17
|
+
dataset = Vis::DataSet.new
|
18
|
+
steps = 50 # number of datapoints will be steps*steps
|
19
|
+
axis_max = 314
|
20
|
+
axis_step = axis_max / steps
|
21
|
+
(0...axis_max).step(axis_step) do |x|
|
22
|
+
(0...axis_max).step(axis_step) do |y|
|
23
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
24
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
dom_node = Vis::Graph3d.test_container
|
28
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
29
|
+
[g3d.is_a?(Vis::Graph3d), dom_node.JS[:children].JS[:length]]
|
30
|
+
end.to eq([true, 1])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'it can replace the data' do
|
34
|
+
expect_evaluate_ruby do
|
35
|
+
options = {
|
36
|
+
width: '600px',
|
37
|
+
height: '600px',
|
38
|
+
style: 'surface',
|
39
|
+
show_perspective: true,
|
40
|
+
show_grid: true,
|
41
|
+
show_shadow: false,
|
42
|
+
keep_aspect_ratio: true,
|
43
|
+
vertical_ratio: 0.5
|
44
|
+
}
|
45
|
+
dataset = Vis::DataSet.new
|
46
|
+
steps = 50 # number of datapoints will be steps*steps
|
47
|
+
axis_max = 314
|
48
|
+
axis_step = axis_max / steps
|
49
|
+
(0...axis_max).step(axis_step) do |x|
|
50
|
+
(0...axis_max).step(axis_step) do |y|
|
51
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
52
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
dom_node = Vis::Graph3d.test_container
|
56
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
57
|
+
created = dom_node.JS[:children].JS[:length]
|
58
|
+
new_dataset = Vis::DataSet.new
|
59
|
+
(0...axis_max).step(axis_step) do |x|
|
60
|
+
(0...axis_max).step(axis_step) do |y|
|
61
|
+
value = Math.cos(x/50) * Math.sin(y/50) * 50 + 50
|
62
|
+
new_dataset.add(x: x, y: y, z: value, style: value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
g3d.set_data(new_dataset)
|
66
|
+
[g3d.is_a?(Vis::Graph3d), created]
|
67
|
+
end.to eq([true, 1])
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'it can set options' do
|
71
|
+
expect_evaluate_ruby do
|
72
|
+
options = {
|
73
|
+
width: '600px',
|
74
|
+
height: '600px',
|
75
|
+
style: 'surface',
|
76
|
+
show_perspective: true,
|
77
|
+
show_grid: true,
|
78
|
+
show_shadow: false,
|
79
|
+
keep_aspect_ratio: true,
|
80
|
+
vertical_ratio: 0.5
|
81
|
+
}
|
82
|
+
dataset = Vis::DataSet.new
|
83
|
+
steps = 50 # number of datapoints will be steps*steps
|
84
|
+
axis_max = 314
|
85
|
+
axis_step = axis_max / steps
|
86
|
+
(0...axis_max).step(axis_step) do |x|
|
87
|
+
(0...axis_max).step(axis_step) do |y|
|
88
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
89
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
dom_node = Vis::Graph3d.test_container
|
93
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
94
|
+
created = dom_node.JS[:children].JS[:length]
|
95
|
+
error = false
|
96
|
+
begin
|
97
|
+
g3d.set_options({
|
98
|
+
width: '500px',
|
99
|
+
height: '500px',
|
100
|
+
style: 'surface',
|
101
|
+
show_perspective: true,
|
102
|
+
show_grid: true,
|
103
|
+
show_shadow: true,
|
104
|
+
keep_aspect_ratio: true,
|
105
|
+
vertical_ratio: 0.5
|
106
|
+
})
|
107
|
+
rescue
|
108
|
+
error = true
|
109
|
+
end
|
110
|
+
[g3d.is_a?(Vis::Graph3d), created, error]
|
111
|
+
end.to eq([true, 1, false])
|
112
|
+
end
|
113
|
+
|
114
|
+
xit 'it can set a event listener' do
|
115
|
+
# needs simulated user input
|
116
|
+
expect_evaluate_ruby do
|
117
|
+
options = {
|
118
|
+
width: '600px',
|
119
|
+
height: '600px',
|
120
|
+
style: 'surface',
|
121
|
+
show_perspective: true,
|
122
|
+
show_grid: true,
|
123
|
+
show_shadow: false,
|
124
|
+
keep_aspect_ratio: true,
|
125
|
+
vertical_ratio: 0.5
|
126
|
+
}
|
127
|
+
dataset = Vis::DataSet.new
|
128
|
+
steps = 50 # number of datapoints will be steps*steps
|
129
|
+
axis_max = 314
|
130
|
+
axis_step = axis_max / steps
|
131
|
+
(0...axis_max).step(axis_step) do |x|
|
132
|
+
(0...axis_max).step(axis_step) do |y|
|
133
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
134
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
dom_node = Vis::Graph3d.test_container
|
138
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
139
|
+
created = dom_node.JS[:children].JS[:length]
|
140
|
+
received = []
|
141
|
+
g3d.on(:camera_position_change) do |info|
|
142
|
+
received << info
|
143
|
+
`console.log('received', info)`
|
144
|
+
end
|
145
|
+
[g3d.is_a?(Vis::Graph3d), created, received.size]
|
146
|
+
end.to eq([true, 1, 1])
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'can call redraw' do
|
150
|
+
expect_evaluate_ruby do
|
151
|
+
options = {
|
152
|
+
width: '600px',
|
153
|
+
height: '600px',
|
154
|
+
style: 'surface',
|
155
|
+
show_perspective: true,
|
156
|
+
show_grid: true,
|
157
|
+
show_shadow: false,
|
158
|
+
keep_aspect_ratio: true,
|
159
|
+
vertical_ratio: 0.5
|
160
|
+
}
|
161
|
+
dataset = Vis::DataSet.new
|
162
|
+
steps = 50 # number of datapoints will be steps*steps
|
163
|
+
axis_max = 314
|
164
|
+
axis_step = axis_max / steps
|
165
|
+
(0...axis_max).step(axis_step) do |x|
|
166
|
+
(0...axis_max).step(axis_step) do |y|
|
167
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
168
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
dom_node = Vis::Graph3d.test_container
|
172
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
173
|
+
created = dom_node.JS[:children].JS[:length]
|
174
|
+
g3d.redraw
|
175
|
+
redrawn = dom_node.JS[:children].JS[:length]
|
176
|
+
[g3d.is_a?(Vis::Graph3d), created, redrawn]
|
177
|
+
end.to eq([true, 1, 1])
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'can set the size' do
|
181
|
+
expect_evaluate_ruby do
|
182
|
+
options = {
|
183
|
+
width: '600px',
|
184
|
+
height: '600px',
|
185
|
+
style: 'surface',
|
186
|
+
show_perspective: true,
|
187
|
+
show_grid: true,
|
188
|
+
show_shadow: false,
|
189
|
+
keep_aspect_ratio: true,
|
190
|
+
vertical_ratio: 0.5
|
191
|
+
}
|
192
|
+
dataset = Vis::DataSet.new
|
193
|
+
steps = 50 # number of datapoints will be steps*steps
|
194
|
+
axis_max = 314
|
195
|
+
axis_step = axis_max / steps
|
196
|
+
(0...axis_max).step(axis_step) do |x|
|
197
|
+
(0...axis_max).step(axis_step) do |y|
|
198
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
199
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
dom_node = Vis::Graph3d.test_container
|
203
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
204
|
+
created = dom_node.JS[:children].JS[:length]
|
205
|
+
g3d.set_size('400px', '300px')
|
206
|
+
dom_node.JS.querySelector('canvas')
|
207
|
+
[g3d.is_a?(Vis::Graph3d), created]
|
208
|
+
end.to eq([true, 1])
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'can set and get the camera position' do
|
212
|
+
expect_evaluate_ruby do
|
213
|
+
options = {
|
214
|
+
width: '600px',
|
215
|
+
height: '600px',
|
216
|
+
style: 'surface',
|
217
|
+
show_perspective: true,
|
218
|
+
show_grid: true,
|
219
|
+
show_shadow: false,
|
220
|
+
keep_aspect_ratio: true,
|
221
|
+
vertical_ratio: 0.5
|
222
|
+
}
|
223
|
+
dataset = Vis::DataSet.new
|
224
|
+
steps = 50 # number of datapoints will be steps*steps
|
225
|
+
axis_max = 314
|
226
|
+
axis_step = axis_max / steps
|
227
|
+
(0...axis_max).step(axis_step) do |x|
|
228
|
+
(0...axis_max).step(axis_step) do |y|
|
229
|
+
value = Math.sin(x/50) * Math.cos(y/50) * 50 + 50
|
230
|
+
dataset.add(x: x, y: y, z: value, style: value)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
dom_node = Vis::Graph3d.test_container
|
234
|
+
g3d = Vis::Graph3d.new(dom_node, dataset, options)
|
235
|
+
created = dom_node.JS[:children].JS[:length]
|
236
|
+
position = g3d.get_camera_position
|
237
|
+
new_position = position.dup
|
238
|
+
new_position[:distance] = new_position[:distance] + 1
|
239
|
+
g3d.set_camera_position(new_position)
|
240
|
+
final_position = g3d.get_camera_position
|
241
|
+
[g3d.is_a?(Vis::Graph3d), created, final_position[:distance] == new_position[:distance]]
|
242
|
+
end.to eq([true, 1, true])
|
243
|
+
end
|
244
|
+
|
245
|
+
xit 'animation_start'
|
246
|
+
xit 'animation_stop'
|
247
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Hyperloop::Vis::Timeline::Component', js: true do
|
4
|
+
|
5
|
+
it 'creates a component by using the mixin and renders it' do
|
6
|
+
mount 'OuterComponent' do
|
7
|
+
class VisComponent
|
8
|
+
include Hyperloop::Vis::Timeline::Mixin
|
9
|
+
|
10
|
+
render_with_dom_node do |dom_node, items|
|
11
|
+
net = Vis::Timeline.new(dom_node, items)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
class OuterComponent < Hyperloop::Component
|
15
|
+
render do
|
16
|
+
data = Vis::DataSet.new([
|
17
|
+
{id: 1, content: 'item 1', start: '2013-04-20'},
|
18
|
+
{id: 2, content: 'item 2', start: '2013-04-14'},
|
19
|
+
{id: 3, content: 'item 3', start: '2013-04-18'},
|
20
|
+
{id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
|
21
|
+
{id: 5, content: 'item 5', start: '2013-04-25'},
|
22
|
+
{id: 6, content: 'item 6', start: '2013-04-27'}
|
23
|
+
])
|
24
|
+
DIV { VisComponent(items: data) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
expect(page.body).to include('class="vis-timeline')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'creates a component by inheriting and renders it' do
|
32
|
+
mount 'OuterComponent' do
|
33
|
+
class VisComponent < Hyperloop::Vis::Timeline::Component
|
34
|
+
render_with_dom_node do |dom_node, items|
|
35
|
+
net = Vis::Timeline.new(dom_node, items)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
class OuterComponent < Hyperloop::Component
|
39
|
+
render do
|
40
|
+
data = Vis::DataSet.new([
|
41
|
+
{id: 1, content: 'item 1', start: '2013-04-20'},
|
42
|
+
{id: 2, content: 'item 2', start: '2013-04-14'},
|
43
|
+
{id: 3, content: 'item 3', start: '2013-04-18'},
|
44
|
+
{id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
|
45
|
+
{id: 5, content: 'item 5', start: '2013-04-25'},
|
46
|
+
{id: 6, content: 'item 6', start: '2013-04-27'}
|
47
|
+
])
|
48
|
+
DIV { VisComponent(items: data) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
expect(page.body).to include('class="vis-timeline')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'actually passes the params to the component' do
|
56
|
+
mount 'OuterComponent' do
|
57
|
+
class VisComponent < Hyperloop::Vis::Timeline::Component
|
58
|
+
def self.passed_data
|
59
|
+
@@passed_data
|
60
|
+
end
|
61
|
+
def self.passed_options
|
62
|
+
@@passed_options
|
63
|
+
end
|
64
|
+
render_with_dom_node do |dom_node, items, groups, options|
|
65
|
+
@@passed_data = items
|
66
|
+
@@passed_options = options
|
67
|
+
net = Vis::Timeline.new(dom_node, items, options)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
class OuterComponent < Hyperloop::Component
|
71
|
+
render do
|
72
|
+
data = Vis::DataSet.new([
|
73
|
+
{id: 1, content: 'item 1', start: '2013-04-20'},
|
74
|
+
{id: 2, content: 'item 2', start: '2013-04-14'},
|
75
|
+
{id: 3, content: 'item 3', start: '2013-04-18'},
|
76
|
+
{id: 4, content: 'item 4', start: '2013-04-16', end: '2013-04-19'},
|
77
|
+
{id: 5, content: 'item 5', start: '2013-04-25'},
|
78
|
+
{id: 6, content: 'item 6', start: '2013-04-27'}
|
79
|
+
])
|
80
|
+
options = { align: 'left' }
|
81
|
+
DIV { VisComponent(items: data, options: options)}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
expect(page.body).to include('class="vis-timeline')
|
86
|
+
expect_evaluate_ruby('VisComponent.passed_data.is_a?(Vis::DataSet)').to eq(true)
|
87
|
+
expect_evaluate_ruby('VisComponent.passed_options.has_key?(:align)').to eq(true)
|
88
|
+
end
|
89
|
+
end
|