rrlist 0.0.1
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.
- data/.gitignore +7 -0
- data/Gemfile +5 -0
- data/README.md +158 -0
- data/Rakefile +1 -0
- data/doc/RRArchive.html +555 -0
- data/doc/RRComposite.html +639 -0
- data/doc/RRList/Functions.html +675 -0
- data/doc/RRList/List.html +2277 -0
- data/doc/RRList/Stores.html +115 -0
- data/doc/RRList/Stores/InMemoryArray.html +609 -0
- data/doc/RRListStore.html +115 -0
- data/doc/RRListStore/InMemoryArray.html +580 -0
- data/doc/RRMath.html +634 -0
- data/doc/RRlist.html +131 -0
- data/doc/_index.html +170 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +338 -0
- data/doc/file.README.html +227 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +227 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +178 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +268 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/rrlist.rb +3 -0
- data/lib/rrlist/functions.rb +80 -0
- data/lib/rrlist/list.rb +212 -0
- data/lib/rrlist/stores.rb +45 -0
- data/lib/rrlist/version.rb +3 -0
- data/rrlist.gemspec +27 -0
- data/spec/lib/rrlist/functions_spec.rb +19 -0
- data/spec/lib/rrlist/list_spec.rb +416 -0
- data/spec/spec_helper.rb +36 -0
- metadata +167 -0
data/rrlist.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rrlist/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rrlist"
|
7
|
+
s.version = RRList::VERSION
|
8
|
+
s.authors = ["Federico Dayan"]
|
9
|
+
s.email = ["federico.dayan@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/fddayan/rrlist"
|
11
|
+
s.summary = %q{A list that its size remains constant over time}
|
12
|
+
s.description = %q{Inspired by RRDTool. A list that its size remains constant over time. You can use ranges and functions.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "rrlist"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_dependency "trollop"
|
23
|
+
s.add_dependency "rainbow"
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
s.add_development_dependency "yard"
|
26
|
+
s.add_development_dependency "redcarpet"
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RRList::Functions do
|
4
|
+
|
5
|
+
context ".calc_average" do
|
6
|
+
it "should agregate" do
|
7
|
+
RRList::Functions.calc_average(3,(2+3+4)/3,7).should eq ((2+3+4+7)/4)
|
8
|
+
RRList::Functions.calc_average(3,(2+3+4)/3.0,(7+4)/2.0,2).should eq ((2+3+4+7+4)/5.0)
|
9
|
+
RRList::Functions.calc_average(5,2,7,5).should eq 4.5
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it { RRList::Functions.avg.should be_a(Proc) }
|
14
|
+
it { RRList::Functions.incr.should be_a(Proc) }
|
15
|
+
it { RRList::Functions.decr.should be_a(Proc) }
|
16
|
+
it { RRList::Functions.min.should be_a(Proc) }
|
17
|
+
it { RRList::Functions.max.should be_a(Proc) }
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,416 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RRList::List do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
RRList::List.new(:size => 10 ,:range => 1).tap do |rr_list|
|
7
|
+
0.upto(30) { |v| rr_list.add(v) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it { subject.get(22).should be 22 }
|
12
|
+
it { subject.get(122).should be_nil }
|
13
|
+
|
14
|
+
it { subject.min_index.should be 21 }
|
15
|
+
it { subject.max_index.should be 30 }
|
16
|
+
|
17
|
+
it { subject.index_size.should be 10 }
|
18
|
+
|
19
|
+
it { subject.in_limits?(20).should be false }
|
20
|
+
it { subject.in_limits?(21).should be true }
|
21
|
+
it { subject.in_limits?(30).should be true }
|
22
|
+
it { subject.in_limits?(31).should be false }
|
23
|
+
|
24
|
+
it { subject.out_of_range?(1).should be true }
|
25
|
+
it { subject.out_of_range?(15).should be false }
|
26
|
+
it { subject.out_of_range?(20).should be false }
|
27
|
+
it { subject.out_of_range?(100).should be true }
|
28
|
+
|
29
|
+
it { subject.lower?(20).should be true }
|
30
|
+
it { subject.lower?(21).should be false }
|
31
|
+
|
32
|
+
it { subject.higher?(30).should be false }
|
33
|
+
it { subject.higher?(31).should be true }
|
34
|
+
|
35
|
+
it { subject.values.should eq [21,22,23,24,25,26,27,28,29,30] }
|
36
|
+
|
37
|
+
context "set_at" do
|
38
|
+
it "should set value without moving cursor" do
|
39
|
+
mi = subject.max_index
|
40
|
+
subject.set_at(25,nil)
|
41
|
+
subject.values.should eq [21,22,23,24,nil,26,27,28,29,30]
|
42
|
+
subject.max_index.should be mi
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should throw an exception if value is not in limits" do
|
46
|
+
lambda { subject.set_at(10,nil) }.should raise_exception
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "each should iterate over the list" do
|
51
|
+
subject.each { |v| v.should_not be_nil }
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should clear the values but do not lose position" do
|
55
|
+
subject.clear
|
56
|
+
subject.min_index.should be 21
|
57
|
+
subject.max_index.should be 30
|
58
|
+
subject.values.should eq [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should reset to original" do
|
62
|
+
subject.reset
|
63
|
+
subject.min_index.should be 0
|
64
|
+
subject.max_index.should be 0
|
65
|
+
subject.values.should eq [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
|
66
|
+
end
|
67
|
+
|
68
|
+
context ".each_with_index" do
|
69
|
+
|
70
|
+
it "should iterate over passing the rigth index" do
|
71
|
+
rr_list = RRList::List.new :size => 10 ,:range => 5
|
72
|
+
0.upto(100) { |v| rr_list.add_at(v,v) }
|
73
|
+
|
74
|
+
res = {}
|
75
|
+
rr_list.each_with_index do |value, index|
|
76
|
+
res[index.to_s] = value
|
77
|
+
end
|
78
|
+
|
79
|
+
res.should eq "55"=>59, "60"=>64, "65"=>69, "70"=>74, "75"=>79, "80"=>84, "85"=>89, "90"=>94, "95"=>99, "100"=>100
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "add_at" do
|
84
|
+
|
85
|
+
it "should move to the right if added a higher index" do
|
86
|
+
subject.add_at(31,31)
|
87
|
+
|
88
|
+
subject.min_index.should be 22
|
89
|
+
subject.max_index.should be 31
|
90
|
+
subject.values.should eq [22,23,24,25,26,27,28,29,30,31]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should fail if index value is lower than index" do
|
94
|
+
lambda { subject.add_at(29,29) }.should raise_exception
|
95
|
+
end
|
96
|
+
|
97
|
+
it "out of range shoudld lose all values" do
|
98
|
+
subject.add_at(200,200)
|
99
|
+
|
100
|
+
subject.min_index.should be 191
|
101
|
+
subject.max_index.should be 200
|
102
|
+
subject.values.should eq [nil,nil,nil,nil,nil,nil,nil,nil,nil,200]
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should add zero" do
|
106
|
+
rr_list = RRList::List.new :size => 10
|
107
|
+
|
108
|
+
0.upto(5) { |v| rr_list.add_at(v,v) }
|
109
|
+
|
110
|
+
rr_list.values.should eq [0,1,2,3,4,5,nil,nil,nil,nil]
|
111
|
+
end
|
112
|
+
|
113
|
+
it "without never calling .add should work anyway" do
|
114
|
+
rr_list = RRList::List.new :size => 10
|
115
|
+
|
116
|
+
0.upto(50) { |v| rr_list.add_at(v,v) }
|
117
|
+
|
118
|
+
rr_list.values.should eq [41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "before_add" do
|
123
|
+
|
124
|
+
it "should load proc from symbols" do
|
125
|
+
rr_list = RRList::List.new :size => 10 ,:range => 5, &RRList::Functions.avg
|
126
|
+
|
127
|
+
0.upto(40) do |v|
|
128
|
+
rr_list.add_at(v,v)
|
129
|
+
end
|
130
|
+
|
131
|
+
rr_list.values.size.should be 10
|
132
|
+
rr_list.values.should eq [{:value=>2.0, :size=>5}, {:value=>7.0, :size=>5}, {:value=>12.0, :size=>5}, {:value=>17.0, :size=>5}, {:value=>22.0, :size=>5}, {:value=>27.0, :size=>5}, {:value=>32.0, :size=>5}, {:value=>37.0, :size=>5}, {:value=>40, :size=>1}, nil]
|
133
|
+
end
|
134
|
+
|
135
|
+
it "when rotating the list old values get used by before_add because do not get removed." do
|
136
|
+
rr_list = RRList::List.new :size => 10 ,:range => 5 do |index,old_value,new_value|
|
137
|
+
if old_value
|
138
|
+
{
|
139
|
+
value: RRList::Functions.calc_average(old_value[:size],old_value[:value],new_value),
|
140
|
+
size: old_value[:size] + 1
|
141
|
+
}
|
142
|
+
else
|
143
|
+
{
|
144
|
+
value: new_value,
|
145
|
+
size: 1,
|
146
|
+
}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
0.upto(200) do |v|
|
151
|
+
rr_list.add_at(v,v)
|
152
|
+
end
|
153
|
+
|
154
|
+
rr_list.values.size.should be 10
|
155
|
+
rr_list.values.should eq [{:value=>157.0, :size=>5}, {:value=>162.0, :size=>5}, {:value=>167.0, :size=>5}, {:value=>172.0, :size=>5}, {:value=>177.0, :size=>5}, {:value=>182.0, :size=>5}, {:value=>187.0, :size=>5}, {:value=>192.0, :size=>5}, {:value=>197.0, :size=>5}, {:value=>200, :size=>1}]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should apply agregate function before replacing position on range" do
|
159
|
+
rr_list = RRList::List.new :size => 10 ,:range => 5 do |index,old_value,new_value|
|
160
|
+
if old_value
|
161
|
+
{
|
162
|
+
value: RRList::Functions.calc_average(old_value[:size],old_value[:value],new_value),
|
163
|
+
size: old_value[:size] + 1
|
164
|
+
}
|
165
|
+
else
|
166
|
+
{
|
167
|
+
value: new_value,
|
168
|
+
size: 1,
|
169
|
+
}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
0.upto(40) do |v|
|
174
|
+
rr_list.add_at(v,v)
|
175
|
+
end
|
176
|
+
|
177
|
+
rr_list.values.size.should be 10
|
178
|
+
rr_list.values.should eq [{:value=>2.0, :size=>5}, {:value=>7.0, :size=>5}, {:value=>12.0, :size=>5}, {:value=>17.0, :size=>5}, {:value=>22.0, :size=>5}, {:value=>27.0, :size=>5}, {:value=>32.0, :size=>5}, {:value=>37.0, :size=>5}, {:value=>40, :size=>1}, nil]
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should apply agregate function before replacing position" do
|
182
|
+
rr_list = RRList::List.new :size => 10 ,:range => 1 do |index,old_value,new_value|
|
183
|
+
if old_value
|
184
|
+
{
|
185
|
+
value: RRList::Functions.calc_average(old_value[:size],old_value[:value],new_value),
|
186
|
+
size: old_value[:size] + 1
|
187
|
+
}
|
188
|
+
else
|
189
|
+
{
|
190
|
+
value: new_value,
|
191
|
+
size: 1,
|
192
|
+
}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
rr_list.add_at(1,2)
|
197
|
+
rr_list.add_at(1,3)
|
198
|
+
rr_list.add_at(1,4)
|
199
|
+
rr_list.add_at(1,7)
|
200
|
+
|
201
|
+
rr_list.values.should eq [nil, {:value=>4.0, :size=>4}, nil, nil, nil, nil, nil, nil, nil, nil]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should save times" do
|
206
|
+
start_time = Time.utc(2000,"jan",1,20,15,1)
|
207
|
+
end_time = start_time + (3600*24)
|
208
|
+
rr_list = RRList::List.new :size => 24 ,:range => 3600 # 24 hours, 1 hours
|
209
|
+
|
210
|
+
seconds = start_time
|
211
|
+
while seconds < end_time
|
212
|
+
rr_list.add_at(seconds.to_i,seconds.to_s)
|
213
|
+
|
214
|
+
seconds += 1
|
215
|
+
end
|
216
|
+
|
217
|
+
rr_list.values.size.should be 24
|
218
|
+
end
|
219
|
+
|
220
|
+
it "add_at should set cursor at the end" do
|
221
|
+
rr_list = RRList::List.new :size => 10
|
222
|
+
|
223
|
+
rr_list.add_at(15,15)
|
224
|
+
|
225
|
+
rr_list.add("a")
|
226
|
+
rr_list.add("b")
|
227
|
+
|
228
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, 15, "a", "b"]
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should initialize array of size" do
|
232
|
+
rr_list = RRList::List.new :size => 10
|
233
|
+
|
234
|
+
rr_list.values.size.should be 10
|
235
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
|
236
|
+
|
237
|
+
rr_list.add(1)
|
238
|
+
|
239
|
+
rr_list.values.should eq [1, nil, nil, nil, nil, nil, nil, nil, nil, nil]
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should add with range of 5 correctly" do
|
243
|
+
rr_list = RRList::List.new :size => 10, :range => 5
|
244
|
+
|
245
|
+
0.upto(100) do |v|
|
246
|
+
rr_list.add_at(v,v)
|
247
|
+
end
|
248
|
+
|
249
|
+
rr_list.index_size.should eq 50
|
250
|
+
rr_list.max_index.should eq 100
|
251
|
+
rr_list.min_index.should eq 55
|
252
|
+
|
253
|
+
55.upto(104) do |v|
|
254
|
+
rr_list.in_limits?(v).should be true
|
255
|
+
end
|
256
|
+
|
257
|
+
rr_list.in_limits?(52).should be false
|
258
|
+
rr_list.in_limits?(105).should be false
|
259
|
+
|
260
|
+
rr_list.higher?(103).should be false
|
261
|
+
rr_list.higher?(104).should be false
|
262
|
+
rr_list.higher?(105).should be true
|
263
|
+
|
264
|
+
rr_list.lower?(52).should be true
|
265
|
+
rr_list.lower?(53).should be true
|
266
|
+
rr_list.lower?(54).should be true
|
267
|
+
rr_list.lower?(55).should be false
|
268
|
+
|
269
|
+
(55-50+1).upto((104+50-5)) do |v|
|
270
|
+
rr_list.out_of_range?(v).should be false
|
271
|
+
end
|
272
|
+
rr_list.out_of_range?(1).should be true
|
273
|
+
rr_list.out_of_range?(104+50-4).should be true
|
274
|
+
|
275
|
+
rr_list.values.should eq [59, 64, 69, 74, 79, 84, 89, 94, 99, 100]
|
276
|
+
rr_list.add_at(105,105)
|
277
|
+
rr_list.values.should eq [64, 69, 74, 79, 84, 89, 94, 99, 100, 105]
|
278
|
+
rr_list.add_at(1005,1005)
|
279
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, nil, nil, 1005]
|
280
|
+
end
|
281
|
+
|
282
|
+
it "test_add_with_range_of_2" do
|
283
|
+
rr_list = RRList::List.new :size => 10, :range => 2
|
284
|
+
|
285
|
+
0.upto(100) do |v|
|
286
|
+
rr_list.add_at(v,v)
|
287
|
+
end
|
288
|
+
|
289
|
+
rr_list.values.should eq [83, 85, 87, 89, 91, 93, 95, 97, 99, 100]
|
290
|
+
end
|
291
|
+
|
292
|
+
it "question should return valid" do
|
293
|
+
rr_list = RRList::List.new :size => 10
|
294
|
+
|
295
|
+
pop(rr_list)
|
296
|
+
|
297
|
+
rr_list.values.should eq [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
298
|
+
|
299
|
+
rr_list.min_index.should eq 11
|
300
|
+
rr_list.max_index.should eq 20
|
301
|
+
|
302
|
+
11.upto(20) do |v|
|
303
|
+
rr_list.in_limits?(v).should be true
|
304
|
+
end
|
305
|
+
|
306
|
+
rr_list.in_limits?(10).should be false
|
307
|
+
rr_list.in_limits?(22).should be false
|
308
|
+
|
309
|
+
rr_list.higher?(10).should be false
|
310
|
+
rr_list.higher?(20).should be false
|
311
|
+
rr_list.higher?(21).should be true
|
312
|
+
rr_list.higher?(22).should be true
|
313
|
+
|
314
|
+
rr_list.lower?(10).should be true
|
315
|
+
rr_list.lower?(11).should be false
|
316
|
+
rr_list.lower?(21).should be false
|
317
|
+
|
318
|
+
2.upto(29) do |v|
|
319
|
+
rr_list.out_of_range?(v).should be false
|
320
|
+
end
|
321
|
+
rr_list.out_of_range?(1).should be true
|
322
|
+
rr_list.out_of_range?(31).should be true
|
323
|
+
end
|
324
|
+
|
325
|
+
it "test_sequences" do
|
326
|
+
rr_list = RRList::List.new :size => 10
|
327
|
+
|
328
|
+
pop(rr_list)
|
329
|
+
|
330
|
+
rr_list.values.should eq [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
331
|
+
|
332
|
+
rr_list.add_at(87,87)
|
333
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, nil, nil, 87]
|
334
|
+
rr_list.add(88)
|
335
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, nil, 87, 88]
|
336
|
+
rr_list.add_at(90,90)
|
337
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, 87, 88, nil, 90]
|
338
|
+
rr_list.add_at(100,100)
|
339
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, nil,nil, 100]
|
340
|
+
rr_list.add_at(101,101)
|
341
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil,nil, nil,100, 101]
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should insert correctly with a much greater number" do
|
345
|
+
rr_list = RRList::List.new :size => 10
|
346
|
+
|
347
|
+
pop(rr_list)
|
348
|
+
|
349
|
+
rr_list.values.should eq [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
350
|
+
|
351
|
+
rr_list.add_at 122,122
|
352
|
+
|
353
|
+
rr_list.values.should eq [nil, nil, nil, nil, nil, nil, nil, nil, nil, 122]
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
it "add higher number should rotate to left and add nill" do
|
358
|
+
rr_list = RRList::List.new :size => 10
|
359
|
+
|
360
|
+
pop(rr_list)
|
361
|
+
|
362
|
+
rr_list.values.should eq [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
363
|
+
|
364
|
+
rr_list.add_at 22,22
|
365
|
+
|
366
|
+
rr_list.values.should eq [13, 14, 15, 16, 17, 18, 19, 20, nil, 22]
|
367
|
+
end
|
368
|
+
|
369
|
+
it "should set right size and value in position" do
|
370
|
+
rr_list = RRList::List.new :size => 10
|
371
|
+
|
372
|
+
0.upto(25) do |v|
|
373
|
+
rr_list.add(v)
|
374
|
+
end
|
375
|
+
|
376
|
+
vals = rr_list.values
|
377
|
+
|
378
|
+
vals.size.should eq 10
|
379
|
+
vals[0].should eq 16
|
380
|
+
vals[vals.size-1].should eq 25
|
381
|
+
rr_list.max_index.should eq 25
|
382
|
+
end
|
383
|
+
|
384
|
+
context "Array API" do
|
385
|
+
|
386
|
+
it "should set with [index]=value" do
|
387
|
+
subject[35] = 35
|
388
|
+
|
389
|
+
subject.min_index.should be 26
|
390
|
+
subject.max_index.should be 35
|
391
|
+
subject.values.should eq [26, 27, 28, 29, 30, nil, nil, nil, nil, 35]
|
392
|
+
end
|
393
|
+
|
394
|
+
it "should get value with [index]" do
|
395
|
+
subject[22].should be 22
|
396
|
+
subject[23].should be 23
|
397
|
+
subject[24].should be 24
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def pop(rr_list)
|
402
|
+
0.upto(20) do |v|
|
403
|
+
rr_list.add(v)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def dg(rr_list)
|
408
|
+
p "=" * 100
|
409
|
+
p "#{rr_list.min_index},#{rr_list.max_index}"
|
410
|
+
p rr_list.values
|
411
|
+
end
|
412
|
+
|
413
|
+
def days(days)
|
414
|
+
60*60*24*days
|
415
|
+
end
|
416
|
+
end
|