oj 2.10.4 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +18 -11
- data/ext/oj/dump.c +59 -11
- data/ext/oj/odd.c +1 -1
- data/ext/oj/oj.c +52 -7
- data/ext/oj/oj.h +4 -2
- data/lib/oj/active_support_helper.rb +17 -0
- data/lib/oj/version.rb +1 -1
- data/test/_test_mimic_rails.rb +21 -3
- data/test/bug.rb +40 -51
- data/test/bug2.rb +10 -0
- data/test/io.rb +48 -0
- data/test/{test_range.rb → mod.rb} +6 -9
- data/test/struct.rb +29 -0
- data/test/test_serializer.rb +59 -0
- data/test/test_various.rb +83 -20
- data/test/write_timebars.rb +31 -0
- data/test/zip.rb +34 -0
- metadata +11 -6
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
%w(lib ext).each do |dir|
|
5
|
+
$LOAD_PATH.unshift File.expand_path("../../#{dir}", __FILE__)
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'stringio'
|
9
|
+
require 'oj'
|
10
|
+
|
11
|
+
|
12
|
+
filename = File.join(File.dirname(__FILE__), 'day.json')
|
13
|
+
File.open(filename, "w") do |f|
|
14
|
+
w = Oj::StreamWriter.new(f, :indent => -1)
|
15
|
+
390.times do |i|
|
16
|
+
w.push_object()
|
17
|
+
w.push_value(12, 'msgType')
|
18
|
+
w.push_value(1, 'version')
|
19
|
+
w.push_value(1_400_074_200 + i * 60, 'bar')
|
20
|
+
w.push_value('TBC', 'source')
|
21
|
+
w.push_array('timebars')
|
22
|
+
w.push_object()
|
23
|
+
w.push_value('aapl_24', 'asset')
|
24
|
+
w.push_value(91.87, 'close')
|
25
|
+
w.pop()
|
26
|
+
w.pop()
|
27
|
+
w.pop()
|
28
|
+
end
|
29
|
+
f.write("\n")
|
30
|
+
end
|
31
|
+
|
data/test/zip.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(__FILE__)
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
require 'zlib'
|
9
|
+
|
10
|
+
File.open('test.json.gz', 'r') do |file|
|
11
|
+
Zlib::GzipReader.wrap(file) do |f2|
|
12
|
+
puts "*** f2: #{f2}"
|
13
|
+
Oj.load(f2) do |val|
|
14
|
+
puts val
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
=begin
|
20
|
+
And a json file with the following contents (then gzipped):
|
21
|
+
|
22
|
+
{"a":2}
|
23
|
+
{"b":2}
|
24
|
+
The output is:
|
25
|
+
|
26
|
+
{"a"=>2}
|
27
|
+
{"b"=>2}
|
28
|
+
bin/test:8:in `load': undefined method `new' for #<EOFError: end of file reached> (NoMethodError)
|
29
|
+
from bin/test:8:in `block (2 levels) in <main>'
|
30
|
+
from bin/test:7:in `wrap'
|
31
|
+
from bin/test:7:in `block in <main>'
|
32
|
+
from bin/test:6:in `open'
|
33
|
+
from bin/test:6:in `<main>'
|
34
|
+
=end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- ext/oj/val_stack.c
|
95
95
|
- ext/oj/val_stack.h
|
96
96
|
- lib/oj.rb
|
97
|
+
- lib/oj/active_support_helper.rb
|
97
98
|
- lib/oj/bag.rb
|
98
99
|
- lib/oj/error.rb
|
99
100
|
- lib/oj/mimic.rb
|
@@ -102,8 +103,10 @@ files:
|
|
102
103
|
- lib/oj/version.rb
|
103
104
|
- test/_test_mimic_rails.rb
|
104
105
|
- test/bug.rb
|
106
|
+
- test/bug2.rb
|
105
107
|
- test/files.rb
|
106
108
|
- test/helper.rb
|
109
|
+
- test/io.rb
|
107
110
|
- test/isolated/shared.rb
|
108
111
|
- test/isolated/test_mimic_after.rb
|
109
112
|
- test/isolated/test_mimic_alone.rb
|
@@ -111,13 +114,11 @@ files:
|
|
111
114
|
- test/isolated/test_mimic_define.rb
|
112
115
|
- test/isolated/test_mimic_rails_after.rb
|
113
116
|
- test/isolated/test_mimic_rails_before.rb
|
117
|
+
- test/mod.rb
|
114
118
|
- test/perf.rb
|
115
|
-
- test/perf1.rb
|
116
|
-
- test/perf2.rb
|
117
119
|
- test/perf_compat.rb
|
118
120
|
- test/perf_fast.rb
|
119
121
|
- test/perf_file.rb
|
120
|
-
- test/perf_obj_old.rb
|
121
122
|
- test/perf_object.rb
|
122
123
|
- test/perf_saj.rb
|
123
124
|
- test/perf_scp.rb
|
@@ -137,18 +138,21 @@ files:
|
|
137
138
|
- test/sample/shape.rb
|
138
139
|
- test/sample/text.rb
|
139
140
|
- test/sample_json.rb
|
141
|
+
- test/struct.rb
|
140
142
|
- test/test_compat.rb
|
141
143
|
- test/test_debian.rb
|
142
144
|
- test/test_fast.rb
|
143
145
|
- test/test_file.rb
|
144
146
|
- test/test_gc.rb
|
145
147
|
- test/test_object.rb
|
146
|
-
- test/test_range.rb
|
147
148
|
- test/test_saj.rb
|
148
149
|
- test/test_scp.rb
|
150
|
+
- test/test_serializer.rb
|
149
151
|
- test/test_strict.rb
|
150
152
|
- test/test_various.rb
|
151
153
|
- test/test_writer.rb
|
154
|
+
- test/write_timebars.rb
|
155
|
+
- test/zip.rb
|
152
156
|
homepage: http://www.ohler.com/oj
|
153
157
|
licenses:
|
154
158
|
- MIT
|
@@ -177,3 +181,4 @@ signing_key:
|
|
177
181
|
specification_version: 4
|
178
182
|
summary: A fast JSON parser and serializer.
|
179
183
|
test_files: []
|
184
|
+
has_rdoc: true
|
data/test/perf1.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
-
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
-
|
7
|
-
#require 'test/unit'
|
8
|
-
require 'optparse'
|
9
|
-
require 'oj'
|
10
|
-
require 'ox'
|
11
|
-
|
12
|
-
$indent = 2
|
13
|
-
|
14
|
-
opts = OptionParser.new
|
15
|
-
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
16
|
-
files = opts.parse(ARGV)
|
17
|
-
|
18
|
-
iter = 100000
|
19
|
-
s = %{
|
20
|
-
{ "class": "Foo::Bar",
|
21
|
-
"attr1": [ true, [false, [12345, null], 3.967, ["something", false], null]],
|
22
|
-
"attr2": { "one": 1 }
|
23
|
-
}
|
24
|
-
}
|
25
|
-
#s = File.read('sample.json')
|
26
|
-
|
27
|
-
Oj.default_options = { :indent => 0 }
|
28
|
-
|
29
|
-
obj = Oj.load(s)
|
30
|
-
xml = Ox.dump(obj, :indent => 0)
|
31
|
-
|
32
|
-
puts xml
|
33
|
-
|
34
|
-
start = Time.now
|
35
|
-
iter.times do
|
36
|
-
Oj.load(s)
|
37
|
-
end
|
38
|
-
dt = Time.now - start
|
39
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
40
|
-
|
41
|
-
start = Time.now
|
42
|
-
iter.times do
|
43
|
-
Ox.load(xml)
|
44
|
-
end
|
45
|
-
dt = Time.now - start
|
46
|
-
puts "%d Ox.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
47
|
-
|
48
|
-
puts
|
49
|
-
|
50
|
-
start = Time.now
|
51
|
-
iter.times do
|
52
|
-
Oj.dump(obj)
|
53
|
-
end
|
54
|
-
dt = Time.now - start
|
55
|
-
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
56
|
-
|
57
|
-
start = Time.now
|
58
|
-
iter.times do
|
59
|
-
Ox.dump(obj)
|
60
|
-
end
|
61
|
-
dt = Time.now - start
|
62
|
-
puts "%d Ox.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
63
|
-
|
64
|
-
puts
|
data/test/perf2.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
-
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
|
-
|
7
|
-
#require 'test/unit'
|
8
|
-
require 'optparse'
|
9
|
-
require 'yajl'
|
10
|
-
require 'oj'
|
11
|
-
|
12
|
-
$indent = 2
|
13
|
-
|
14
|
-
opts = OptionParser.new
|
15
|
-
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
16
|
-
files = opts.parse(ARGV)
|
17
|
-
|
18
|
-
class Foo
|
19
|
-
def initialize()
|
20
|
-
@x = true
|
21
|
-
@y = 58
|
22
|
-
end
|
23
|
-
def to_json()
|
24
|
-
%{{"x":#{@x},"y":#{@y}}}
|
25
|
-
end
|
26
|
-
def to_hash()
|
27
|
-
{ 'x' => @x, 'y' => @y }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
iter = 100000
|
32
|
-
s = %{
|
33
|
-
{ "class": "Foo::Bar",
|
34
|
-
"attr1": [ true, [false, [12345, null], 3.967, ["something", false], null]],
|
35
|
-
"attr2": { "one": 1 }
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
obj = Oj.load(s)
|
40
|
-
obj["foo"] = Foo.new()
|
41
|
-
|
42
|
-
Oj.default_options = { :indent => 0, :effort => :internal }
|
43
|
-
|
44
|
-
puts
|
45
|
-
|
46
|
-
start = Time.now
|
47
|
-
iter.times do
|
48
|
-
Oj.load(s)
|
49
|
-
end
|
50
|
-
dt = Time.now - start
|
51
|
-
puts "%d Oj.load()s in %0.3f seconds or %0.1f loads/msec" % [iter, dt, iter/dt/1000.0]
|
52
|
-
|
53
|
-
start = Time.now
|
54
|
-
iter.times do
|
55
|
-
Yajl::Parser.parse(s)
|
56
|
-
end
|
57
|
-
dt = Time.now - start
|
58
|
-
puts "%d Yajl::Parser.parse()s in %0.3f seconds or %0.1f parses/msec" % [iter, dt, iter/dt/1000.0]
|
59
|
-
|
60
|
-
puts
|
61
|
-
|
62
|
-
start = Time.now
|
63
|
-
iter.times do
|
64
|
-
Oj.dump(obj)
|
65
|
-
end
|
66
|
-
dt = Time.now - start
|
67
|
-
puts "%d Oj.dump()s in %0.3f seconds or %0.1f dumps/msec" % [iter, dt, iter/dt/1000.0]
|
68
|
-
|
69
|
-
start = Time.now
|
70
|
-
iter.times do
|
71
|
-
Yajl::Encoder.encode(obj)
|
72
|
-
end
|
73
|
-
dt = Time.now - start
|
74
|
-
puts "%d Yajl::Encoder.encode()s in %0.3f seconds or %0.1f encodes/msec" % [iter, dt, iter/dt/1000.0]
|
75
|
-
|
76
|
-
puts
|
data/test/perf_obj_old.rb
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
|
3
|
-
$: << '.'
|
4
|
-
$: << '..'
|
5
|
-
$: << '../lib'
|
6
|
-
$: << '../ext'
|
7
|
-
|
8
|
-
if __FILE__ == $0
|
9
|
-
if (i = ARGV.index('-I'))
|
10
|
-
x,path = ARGV.slice!(i, 2)
|
11
|
-
$: << path
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
require 'optparse'
|
16
|
-
require 'ox'
|
17
|
-
require 'oj'
|
18
|
-
require 'perf'
|
19
|
-
require 'sample'
|
20
|
-
require 'files'
|
21
|
-
|
22
|
-
$verbose = 0
|
23
|
-
$circular = false
|
24
|
-
$indent = 0
|
25
|
-
|
26
|
-
do_sample = false
|
27
|
-
do_files = false
|
28
|
-
|
29
|
-
do_load = false
|
30
|
-
do_dump = false
|
31
|
-
do_read = false
|
32
|
-
do_write = false
|
33
|
-
$iter = 1000
|
34
|
-
|
35
|
-
opts = OptionParser.new
|
36
|
-
opts.on("-v", "increase verbosity") { $verbose += 1 }
|
37
|
-
|
38
|
-
opts.on("-c", "circular options") { $circular = true }
|
39
|
-
|
40
|
-
opts.on("-s", "load and dump as sample Ruby object") { do_sample = true }
|
41
|
-
opts.on("-f", "load and dump as files Ruby object") { do_files = true }
|
42
|
-
|
43
|
-
opts.on("-l", "load") { do_load = true }
|
44
|
-
opts.on("-d", "dump") { do_dump = true }
|
45
|
-
opts.on("-r", "read") { do_read = true }
|
46
|
-
opts.on("-w", "write") { do_write = true }
|
47
|
-
opts.on("-a", "load, dump, read and write") { do_load = true; do_dump = true; do_read = true; do_write = true }
|
48
|
-
|
49
|
-
opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i }
|
50
|
-
|
51
|
-
opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) }
|
52
|
-
files = opts.parse(ARGV)
|
53
|
-
|
54
|
-
if files.empty?
|
55
|
-
data = []
|
56
|
-
obj = do_sample ? sample_doc(2) : files('..')
|
57
|
-
mars = Marshal.dump(obj)
|
58
|
-
xml = Ox.dump(obj, :indent => $indent, circular: $circular)
|
59
|
-
json = Oj.dump(obj, :indent => $indent, circular: $circular)
|
60
|
-
File.open('sample.xml', 'w') { |f| f.write(xml) }
|
61
|
-
File.open('sample.json', 'w') { |f| f.write(json) }
|
62
|
-
File.open('sample.marshal', 'w') { |f| f.write(mars) }
|
63
|
-
data << { :file => 'sample.xml', :obj => obj, :xml => xml, :marshal => mars, :json => json }
|
64
|
-
else
|
65
|
-
puts "loading and parsing #{files}\n\n"
|
66
|
-
# TBD change to allow xml and json
|
67
|
-
data = files.map do |f|
|
68
|
-
xml = File.read(f)
|
69
|
-
obj = Ox.load(xml);
|
70
|
-
mars = Marshal.dump(obj)
|
71
|
-
json = Oj.dump(obj, :indent => $indent, circular: $circular)
|
72
|
-
{ :file => f, :obj => obj, :xml => xml, :marshal => mars, :json => json }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
$ox_load_time = 0
|
77
|
-
$mars_load_time = 0
|
78
|
-
$ox_dump_time = 0
|
79
|
-
$oj_dump_time = 0
|
80
|
-
$mars_dump_time = 0
|
81
|
-
|
82
|
-
def perf_load(d)
|
83
|
-
filename = d[:file]
|
84
|
-
marshal_filename = 'sample.marshal'
|
85
|
-
xml = d[:xml]
|
86
|
-
mars = d[:marshal]
|
87
|
-
json = d[:json]
|
88
|
-
|
89
|
-
if 0 < $verbose
|
90
|
-
obj = Ox.load(xml, :mode => :object, :trace => $verbose)
|
91
|
-
return
|
92
|
-
end
|
93
|
-
start = Time.now
|
94
|
-
(1..$iter).each do
|
95
|
-
obj = Ox.load(xml, :mode => :object)
|
96
|
-
end
|
97
|
-
$ox_load_time = Time.now - start
|
98
|
-
puts "Parsing #{$iter} times with Ox took #{$ox_load_time} seconds."
|
99
|
-
|
100
|
-
start = Time.now
|
101
|
-
(1..$iter).each do
|
102
|
-
obj = Oj.load(json, :mode => :object)
|
103
|
-
end
|
104
|
-
$oj_load_time = Time.now - start
|
105
|
-
puts "Parsing #{$iter} times with Oj took #{$oj_load_time} seconds."
|
106
|
-
|
107
|
-
start = Time.now
|
108
|
-
(1..$iter).each do
|
109
|
-
obj = Marshal.load(mars)
|
110
|
-
end
|
111
|
-
$mars_load_time = Time.now - start
|
112
|
-
puts "Marshalling #{$iter} times took #{$mars_load_time} seconds."
|
113
|
-
puts ">>> Ox is %0.1f faster than Marshal loading.\n\n" % [$mars_load_time/$ox_load_time]
|
114
|
-
end
|
115
|
-
|
116
|
-
def perf_dump(d)
|
117
|
-
obj = d[:obj]
|
118
|
-
|
119
|
-
start = Time.now
|
120
|
-
(1..$iter).each do
|
121
|
-
xml = Ox.dump(obj, :indent => $indent, :circular => $circular)
|
122
|
-
#puts "*** ox:\n#{xml}"
|
123
|
-
end
|
124
|
-
$ox_dump_time = Time.now - start
|
125
|
-
puts "Ox dumping #{$iter} times with ox took #{$ox_dump_time} seconds."
|
126
|
-
|
127
|
-
Oj.default_options = {:indent => $indent}
|
128
|
-
start = Time.now
|
129
|
-
(1..$iter).each do
|
130
|
-
json = Oj.dump(obj)
|
131
|
-
end
|
132
|
-
$oj_dump_time = Time.now - start
|
133
|
-
puts "Oj dumping #{$iter} times with oj took #{$oj_dump_time} seconds."
|
134
|
-
|
135
|
-
obj = d[:obj]
|
136
|
-
start = Time.now
|
137
|
-
(1..$iter).each do
|
138
|
-
m = Marshal.dump(obj)
|
139
|
-
end
|
140
|
-
$mars_dump_time = Time.now - start
|
141
|
-
puts "Marshal dumping #{$iter} times took #{$mars_dump_time} seconds."
|
142
|
-
puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [$mars_dump_time/$ox_dump_time]
|
143
|
-
end
|
144
|
-
|
145
|
-
def perf_read(d)
|
146
|
-
ox_read_time = 0
|
147
|
-
mars_read_time = 0
|
148
|
-
|
149
|
-
filename = d[:file]
|
150
|
-
marshal_filename = 'sample.marshal'
|
151
|
-
xml = d[:xml]
|
152
|
-
mars = d[:marshal]
|
153
|
-
|
154
|
-
# now load from the file
|
155
|
-
start = Time.now
|
156
|
-
(1..$iter).each do
|
157
|
-
obj = Ox.load_file(filename, :mode => :object)
|
158
|
-
end
|
159
|
-
ox_read_time = Time.now - start
|
160
|
-
puts "Loading and parsing #{$iter} times with ox took #{ox_read_time} seconds."
|
161
|
-
|
162
|
-
start = Time.now
|
163
|
-
(1..$iter).each do
|
164
|
-
m = File.read(marshal_filename)
|
165
|
-
obj = Marshal.load(m)
|
166
|
-
end
|
167
|
-
mars_read_time = Time.now - start
|
168
|
-
puts "Reading and marshalling #{$iter} times took #{mars_read_time} seconds."
|
169
|
-
puts ">>> Ox is %0.1f faster than Marshal loading and parsing.\n\n" % [mars_read_time/ox_read_time]
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
def perf_write(d)
|
174
|
-
ox_write_time = 0
|
175
|
-
mars_write_time = 0
|
176
|
-
|
177
|
-
ox_filename = 'out.xml'
|
178
|
-
marshal_filename = 'out.marshal'
|
179
|
-
obj = d[:obj]
|
180
|
-
|
181
|
-
start = Time.now
|
182
|
-
(1..$iter).each do
|
183
|
-
xml = Ox.to_file(ox_filename, obj, :indent => $indent)
|
184
|
-
end
|
185
|
-
ox_write_time = Time.now - start
|
186
|
-
puts "Ox dumping #{$iter} times with ox took #{ox_write_time} seconds."
|
187
|
-
|
188
|
-
start = Time.now
|
189
|
-
(1..$iter).each do
|
190
|
-
m = Marshal.dump(obj, circular: $circular)
|
191
|
-
File.open(marshal_filename, "w") { |f| f.write(m) }
|
192
|
-
end
|
193
|
-
mars_write_time = Time.now - start
|
194
|
-
puts "Marshal dumping and writing #{$iter} times took #{mars_write_time} seconds."
|
195
|
-
puts ">>> Ox is %0.1f faster than Marshal dumping.\n\n" % [mars_write_time/ox_write_time]
|
196
|
-
|
197
|
-
end
|
198
|
-
|
199
|
-
#if do_sample or do_files
|
200
|
-
data.each do |d|
|
201
|
-
puts "Using file #{d[:file]}."
|
202
|
-
|
203
|
-
perf_load(d) if do_load
|
204
|
-
perf_dump(d) if do_dump
|
205
|
-
if do_load and do_dump
|
206
|
-
puts ">>> Ox is %0.1f faster than Marshal dumping and loading.\n\n" % [($mars_load_time + $mars_dump_time)/($ox_load_time + $ox_dump_time)] unless 0 == $mars_load_time
|
207
|
-
end
|
208
|
-
|
209
|
-
perf_read(d) if do_read
|
210
|
-
perf_write(d) if do_write
|
211
|
-
|
212
|
-
end
|
213
|
-
#end
|