ffi-yajl 2.3.1 → 2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +11 -6
- data/ext/ffi_yajl/ext/encoder/extconf.rb +2 -2
- data/ext/ffi_yajl/ext/parser/extconf.rb +2 -2
- data/lib/ffi_yajl.rb +5 -5
- data/lib/ffi_yajl/benchmark/encode.rb +1 -1
- data/lib/ffi_yajl/benchmark/encode_profile.rb +1 -1
- data/lib/ffi_yajl/benchmark/parse.rb +1 -1
- data/lib/ffi_yajl/benchmark/parse_profile.rb +1 -1
- data/lib/ffi_yajl/benchmark/parse_profile_ruby_prof.rb +1 -1
- data/lib/ffi_yajl/benchmark/parse_stream.rb +2 -2
- data/lib/ffi_yajl/ext.rb +3 -3
- data/lib/ffi_yajl/ffi.rb +33 -33
- data/lib/ffi_yajl/ffi/encoder.rb +2 -0
- data/lib/ffi_yajl/ffi/parser.rb +9 -8
- data/lib/ffi_yajl/map_library_name.rb +3 -3
- data/lib/ffi_yajl/version.rb +1 -1
- metadata +3 -9
- data/Rakefile +0 -139
- data/spec/ffi_yajl/encoder_spec.rb +0 -221
- data/spec/ffi_yajl/map_library_name_spec.rb +0 -115
- data/spec/ffi_yajl/parser_spec.rb +0 -569
- data/spec/spec_helper.rb +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3650871b1a2b5266bfd1c14858a9575f168f28ae5db95953e7d57d223ce752e9
|
4
|
+
data.tar.gz: f704c34be8a4ded69a6c55355e7733d3dcde0ae1c8ecebeb34cb282fb5e068fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c3295991eec14b9de4059671482702c76a6d41641ca997cf182b467f532ceb21be55a2de653f0b16f86b54dd655f61705390c4bd2c00dccf9e573803d9f30ff
|
7
|
+
data.tar.gz: d6f6a1fd2e25c80c22682affb258e994a81752e7d9348290a07c53c6a84473b0d949b706df6aad3fd62be45c53e7f53555f6164012088b2e82eb9d41d5383c48
|
data/README.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
# FFI YAJL
|
2
2
|
|
3
|
-
[![Build
|
3
|
+
[![Build status](https://badge.buildkite.com/35c43155d637f5201a5030cd4e7d8025573c0042094e00bbb3.svg?branch=master)](https://buildkite.com/chef-oss/chef-ffi-yajl-master-verify) [![Gem Version](https://badge.fury.io/rb/ffi-yajl.svg)](https://badge.fury.io/rb/ffi-yajl)
|
4
|
+
|
5
|
+
**Umbrella Project**: [Chef Foundation](https://github.com/chef/chef-oss-practices/blob/master/projects/chef-foundation.md)
|
6
|
+
|
7
|
+
**Project State**: [Active](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md#active)
|
8
|
+
|
9
|
+
**Issues [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: 14 days
|
10
|
+
|
11
|
+
**Pull Request [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: 14 days
|
12
|
+
|
4
13
|
|
5
14
|
ffi-yajl is a Ruby adapter for the [yajl](http://lloyd.github.io/yajl/) JSON parser/generator library. ffi-yajl supports multiple Ruby C extension mechanisms, including both MRI native extensions and FFI in order to be compatible with as many Ruby implementations as possible while providing good performance where possible.
|
6
15
|
|
@@ -20,11 +29,7 @@ gem 'ffi-yajl'
|
|
20
29
|
|
21
30
|
## Supported Ruby VMs:
|
22
31
|
|
23
|
-
- Ruby
|
24
|
-
- rbx 2.2.x (possibly earlier)
|
25
|
-
- Jruby 1.7.x (possibly earlier)
|
26
|
-
|
27
|
-
Ruby 1.8.7 support was dropped in 2.2.0
|
32
|
+
- Ruby 2.2+ and compatible rbx or jruby
|
28
33
|
|
29
34
|
## Supported Distros:
|
30
35
|
|
@@ -42,14 +42,14 @@ if !windows? && !find_header("yajl/yajl_tree.h")
|
|
42
42
|
"/usr/local/include", # /usr/local
|
43
43
|
RbConfig::CONFIG["includedir"], # Ruby
|
44
44
|
"/usr/include", # (default)
|
45
|
-
]
|
45
|
+
].freeze
|
46
46
|
|
47
47
|
LIB_DIRS = [
|
48
48
|
"/opt/local/lib", # MacPorts
|
49
49
|
"/usr/local/lib", # /usr/local + Homebrew
|
50
50
|
RbConfig::CONFIG["libdir"], # Ruby
|
51
51
|
"/usr/lib", # (default)
|
52
|
-
]
|
52
|
+
].freeze
|
53
53
|
|
54
54
|
# add --with-yajl-dir, --with-yajl-include, --with-yajl-lib
|
55
55
|
dir_config("yajl", HEADER_DIRS, LIB_DIRS)
|
@@ -42,14 +42,14 @@ if !windows? && !find_header("yajl/yajl_tree.h")
|
|
42
42
|
"/usr/local/include", # /usr/local
|
43
43
|
RbConfig::CONFIG["includedir"], # Ruby
|
44
44
|
"/usr/include", # (default)
|
45
|
-
]
|
45
|
+
].freeze
|
46
46
|
|
47
47
|
LIB_DIRS = [
|
48
48
|
"/opt/local/lib", # MacPorts
|
49
49
|
"/usr/local/lib", # /usr/local + Homebrew
|
50
50
|
RbConfig::CONFIG["libdir"], # Ruby
|
51
51
|
"/usr/lib", # (default)
|
52
|
-
]
|
52
|
+
].freeze
|
53
53
|
|
54
54
|
# add --with-yajl-dir, --with-yajl-include, --with-yajl-lib
|
55
55
|
dir_config("yajl", HEADER_DIRS, LIB_DIRS)
|
data/lib/ffi_yajl.rb
CHANGED
@@ -35,16 +35,16 @@
|
|
35
35
|
# - Then we try the c-ext and rescue into ffi that fails
|
36
36
|
#
|
37
37
|
if ENV["FORCE_FFI_YAJL"] == "ext"
|
38
|
-
|
38
|
+
require_relative "ffi_yajl/ext"
|
39
39
|
elsif ENV["FORCE_FFI_YAJL"] == "ffi"
|
40
|
-
|
40
|
+
require_relative "ffi_yajl/ffi"
|
41
41
|
elsif RUBY_PLATFORM == "java"
|
42
|
-
|
42
|
+
require_relative "ffi_yajl/ffi"
|
43
43
|
else
|
44
44
|
begin
|
45
|
-
|
45
|
+
require_relative "ffi_yajl/ext"
|
46
46
|
rescue LoadError
|
47
47
|
warn "failed to load the ffi-yajl c-extension, falling back to ffi interface"
|
48
|
-
|
48
|
+
require_relative "ffi_yajl/ffi"
|
49
49
|
end
|
50
50
|
end
|
@@ -33,7 +33,7 @@ Benchmark.bmbm do |x|
|
|
33
33
|
puts "JSON.parse"
|
34
34
|
times.times do
|
35
35
|
json.rewind
|
36
|
-
while chunk = json.gets
|
36
|
+
while ( chunk = json.gets )
|
37
37
|
JSON.parse(chunk, max_nesting: false)
|
38
38
|
end
|
39
39
|
end
|
@@ -44,7 +44,7 @@ Benchmark.bmbm do |x|
|
|
44
44
|
puts "ActiveSupport::JSON.decode"
|
45
45
|
times.times do
|
46
46
|
json.rewind
|
47
|
-
while chunk = json.gets
|
47
|
+
while ( chunk = json.gets )
|
48
48
|
ActiveSupport::JSON.decode(chunk)
|
49
49
|
end
|
50
50
|
end
|
data/lib/ffi_yajl/ext.rb
CHANGED
@@ -22,10 +22,10 @@
|
|
22
22
|
|
23
23
|
require "rubygems"
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
require_relative "encoder"
|
26
|
+
require_relative "parser"
|
27
27
|
require "ffi_yajl/ext/dlopen"
|
28
|
-
|
28
|
+
require_relative "map_library_name"
|
29
29
|
|
30
30
|
# needed so the encoder c-code can find these symbols
|
31
31
|
require "stringio"
|
data/lib/ffi_yajl/ffi.rb
CHANGED
@@ -31,7 +31,7 @@ rescue LoadError
|
|
31
31
|
exit 1
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
require_relative "map_library_name"
|
35
35
|
|
36
36
|
module FFI_Yajl
|
37
37
|
extend ::FFI::Library
|
@@ -42,24 +42,24 @@ module FFI_Yajl
|
|
42
42
|
|
43
43
|
class YajlCallbacks < ::FFI::Struct
|
44
44
|
layout :yajl_null, :pointer,
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
:yajl_boolean, :pointer,
|
46
|
+
:yajl_integer, :pointer,
|
47
|
+
:yajl_double, :pointer,
|
48
|
+
:yajl_number, :pointer,
|
49
|
+
:yajl_string, :pointer,
|
50
|
+
:yajl_start_map, :pointer,
|
51
|
+
:yajl_map_key, :pointer,
|
52
|
+
:yajl_end_map, :pointer,
|
53
|
+
:yajl_start_array, :pointer,
|
54
|
+
:yajl_end_array, :pointer
|
55
55
|
end
|
56
56
|
|
57
|
-
enum :yajl_status,
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
57
|
+
enum :yajl_status, %i{
|
58
|
+
yajl_status_ok
|
59
|
+
yajl_status_client_canceled
|
60
|
+
yajl_status_insufficient_data
|
61
|
+
yajl_status_error
|
62
|
+
}
|
63
63
|
|
64
64
|
# FFI::Enums are slow, should remove the rest
|
65
65
|
# enum :yajl_gen_status, [
|
@@ -97,22 +97,22 @@ module FFI_Yajl
|
|
97
97
|
# const char *yajl_status_to_string (yajl_status code)
|
98
98
|
attach_function :yajl_status_to_string, [ :yajl_status ], :string
|
99
99
|
# yajl_handle yajl_alloc(const yajl_callbacks * callbacks, yajl_alloc_funcs * afs, void * ctx)
|
100
|
-
attach_function :yajl_alloc,
|
100
|
+
attach_function :yajl_alloc, %i{pointer pointer pointer}, :yajl_handle
|
101
101
|
# void yajl_free (yajl_handle handle)
|
102
102
|
attach_function :yajl_free, [:yajl_handle], :void
|
103
103
|
# yajl_status yajl_parse (yajl_handle hand, const unsigned char *jsonText, unsigned int jsonTextLength)
|
104
|
-
attach_function :yajl_parse,
|
104
|
+
attach_function :yajl_parse, %i{yajl_handle ustring uint}, :yajl_status
|
105
105
|
# yajl_status yajl_parse_complete (yajl_handle hand)
|
106
106
|
attach_function :yajl_complete_parse, [:yajl_handle], :yajl_status
|
107
107
|
# unsigned char *yajl_get_error (yajl_handle hand, int verbose, const unsigned char *jsonText, unsigned int jsonTextLength)
|
108
|
-
attach_function :yajl_get_error,
|
108
|
+
attach_function :yajl_get_error, %i{yajl_handle int ustring int}, :ustring
|
109
109
|
# void yajl_free_error (yajl_handle hand, unsigned char *str)
|
110
|
-
attach_function :yajl_free_error,
|
110
|
+
attach_function :yajl_free_error, %i{yajl_handle ustring}, :void
|
111
111
|
|
112
112
|
#
|
113
|
-
attach_function :yajl_config,
|
113
|
+
attach_function :yajl_config, %i{yajl_handle yajl_option varargs}, :int
|
114
114
|
|
115
|
-
attach_function :yajl_gen_config,
|
115
|
+
attach_function :yajl_gen_config, %i{yajl_gen yajl_gen_option varargs}, :int
|
116
116
|
|
117
117
|
# yajl_gen yajl_gen_alloc (const yajl_alloc_funcs *allocFuncs)
|
118
118
|
attach_function :yajl_gen_alloc, [:pointer], :yajl_gen
|
@@ -121,33 +121,33 @@ module FFI_Yajl
|
|
121
121
|
# void yajl_gen_free (yajl_gen handle)
|
122
122
|
attach_function :yajl_gen_free, [:yajl_gen], :void
|
123
123
|
|
124
|
-
attach_function :yajl_gen_integer,
|
125
|
-
attach_function :yajl_gen_double,
|
126
|
-
attach_function :yajl_gen_number,
|
127
|
-
attach_function :yajl_gen_string,
|
124
|
+
attach_function :yajl_gen_integer, %i{yajl_gen long_long}, :int
|
125
|
+
attach_function :yajl_gen_double, %i{yajl_gen double}, :int
|
126
|
+
attach_function :yajl_gen_number, %i{yajl_gen ustring int}, :int
|
127
|
+
attach_function :yajl_gen_string, %i{yajl_gen ustring int}, :int
|
128
128
|
attach_function :yajl_gen_null, [:yajl_gen], :int
|
129
|
-
attach_function :yajl_gen_bool,
|
129
|
+
attach_function :yajl_gen_bool, %i{yajl_gen int}, :int
|
130
130
|
attach_function :yajl_gen_map_open, [:yajl_gen], :int
|
131
131
|
attach_function :yajl_gen_map_close, [:yajl_gen], :int
|
132
132
|
attach_function :yajl_gen_array_open, [:yajl_gen], :int
|
133
133
|
attach_function :yajl_gen_array_close, [:yajl_gen], :int
|
134
134
|
# yajl_gen_status yajl_gen_get_buf (yajl_gen hand, const unsigned char **buf, unsigned int *len)
|
135
|
-
attach_function :yajl_gen_get_buf,
|
135
|
+
attach_function :yajl_gen_get_buf, %i{yajl_gen pointer pointer}, :int
|
136
136
|
# void yajl_gen_clear (yajl_gen hand)
|
137
137
|
attach_function :yajl_gen_clear, [:yajl_gen], :void
|
138
138
|
end
|
139
139
|
|
140
|
-
|
141
|
-
|
140
|
+
require_relative "encoder"
|
141
|
+
require_relative "parser"
|
142
142
|
|
143
143
|
module FFI_Yajl
|
144
144
|
class Parser
|
145
|
-
|
145
|
+
require_relative "ffi/parser"
|
146
146
|
include FFI_Yajl::FFI::Parser
|
147
147
|
end
|
148
148
|
|
149
149
|
class Encoder
|
150
|
-
|
150
|
+
require_relative "ffi/encoder"
|
151
151
|
include FFI_Yajl::FFI::Encoder
|
152
152
|
end
|
153
153
|
end
|
data/lib/ffi_yajl/ffi/encoder.rb
CHANGED
@@ -161,6 +161,7 @@ class Integer
|
|
161
161
|
if str == "NaN" || str == "Infinity" || str == "-Infinity"
|
162
162
|
raise ::FFI_Yajl::EncodeError, "'#{str}' is an invalid number"
|
163
163
|
end
|
164
|
+
|
164
165
|
if state[:processing_key]
|
165
166
|
if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
|
166
167
|
FFI_Yajl::Encoder.raise_error_for_status(status, str)
|
@@ -179,6 +180,7 @@ class Float
|
|
179
180
|
if str == "NaN" || str == "Infinity" || str == "-Infinity"
|
180
181
|
raise ::FFI_Yajl::EncodeError, "'#{str}' is an invalid number"
|
181
182
|
end
|
183
|
+
|
182
184
|
if state[:processing_key]
|
183
185
|
if ( status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) ) != 0
|
184
186
|
FFI_Yajl::Encoder.raise_error_for_status(status, str)
|
data/lib/ffi_yajl/ffi/parser.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (c) 2015 Lamont Granquist
|
2
|
-
# Copyright (c) 2015 Chef Software
|
2
|
+
# Copyright (c) 2015-2018, Chef Software Inc.
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -23,13 +23,14 @@
|
|
23
23
|
module FFI_Yajl
|
24
24
|
module FFI
|
25
25
|
module Parser
|
26
|
-
def set_value(val) # rubocop:disable
|
26
|
+
def set_value(val) # rubocop:disable Naming/AccessorMethodName
|
27
27
|
case stack.last
|
28
28
|
when Hash
|
29
29
|
raise FFI_Yajl::ParseError, "internal error: missing key in parse" if key.nil?
|
30
30
|
if @opts[:unique_key_checking] && stack.last.key?(key)
|
31
31
|
raise FFI_Yajl::ParseError, "repeated key: #{key}"
|
32
32
|
end
|
33
|
+
|
33
34
|
stack.last[key] = val
|
34
35
|
when Array
|
35
36
|
stack.last.push(val)
|
@@ -55,15 +56,15 @@ module FFI_Yajl
|
|
55
56
|
set_value(nil)
|
56
57
|
1
|
57
58
|
end
|
58
|
-
@boolean_callback = ::FFI::Function.new(:int,
|
59
|
+
@boolean_callback = ::FFI::Function.new(:int, %i{pointer int}) do |ctx, boolval|
|
59
60
|
set_value(boolval == 1 ? true : false)
|
60
61
|
1
|
61
62
|
end
|
62
|
-
@integer_callback = ::FFI::Function.new(:int,
|
63
|
+
@integer_callback = ::FFI::Function.new(:int, %i{pointer long_long}) do |ctx, intval|
|
63
64
|
set_value(intval)
|
64
65
|
1
|
65
66
|
end
|
66
|
-
@number_callback = ::FFI::Function.new(:int,
|
67
|
+
@number_callback = ::FFI::Function.new(:int, %i{pointer string size_t}) do |ctx, stringval, stringlen|
|
67
68
|
s = stringval.slice(0, stringlen)
|
68
69
|
s.force_encoding("UTF-8") if defined? Encoding
|
69
70
|
# XXX: I can't think of a better way to do this right now. need to call to_f if and only if its a float.
|
@@ -71,11 +72,11 @@ module FFI_Yajl
|
|
71
72
|
set_value(v)
|
72
73
|
1
|
73
74
|
end
|
74
|
-
@double_callback = ::FFI::Function.new(:int,
|
75
|
+
@double_callback = ::FFI::Function.new(:int, %i{pointer double}) do |ctx, doubleval|
|
75
76
|
set_value(doubleval)
|
76
77
|
1
|
77
78
|
end
|
78
|
-
@string_callback = ::FFI::Function.new(:int,
|
79
|
+
@string_callback = ::FFI::Function.new(:int, %i{pointer string size_t}) do |ctx, stringval, stringlen|
|
79
80
|
s = stringval.slice(0, stringlen)
|
80
81
|
s.force_encoding("UTF-8") if defined? Encoding
|
81
82
|
set_value(s)
|
@@ -86,7 +87,7 @@ module FFI_Yajl
|
|
86
87
|
stack.push({})
|
87
88
|
1
|
88
89
|
end
|
89
|
-
@map_key_callback = ::FFI::Function.new(:int,
|
90
|
+
@map_key_callback = ::FFI::Function.new(:int, %i{pointer string size_t}) do |ctx, key, keylen|
|
90
91
|
s = key.slice(0, keylen)
|
91
92
|
s.force_encoding("UTF-8") if defined? Encoding
|
92
93
|
self.key = @opts[:symbolize_keys] ? s.to_sym : s
|
@@ -34,7 +34,7 @@ module FFI_Yajl
|
|
34
34
|
# Stub for tests to override the host_os
|
35
35
|
#
|
36
36
|
# @api private
|
37
|
-
# @return Array<String> lower case ruby host_os string
|
37
|
+
# @return [Array<String>] lower case ruby host_os string
|
38
38
|
def host_os
|
39
39
|
RbConfig::CONFIG["host_os"].downcase
|
40
40
|
end
|
@@ -43,7 +43,7 @@ module FFI_Yajl
|
|
43
43
|
# and Mac may have different names/extensions.
|
44
44
|
#
|
45
45
|
# @api private
|
46
|
-
# @return Array<String> Array of yajl library names for platform
|
46
|
+
# @return [Array<String>] Array of yajl library names for platform
|
47
47
|
def library_names
|
48
48
|
case host_os
|
49
49
|
when /mingw|mswin/
|
@@ -63,7 +63,7 @@ module FFI_Yajl
|
|
63
63
|
# the filesystem. May return an empty array.
|
64
64
|
#
|
65
65
|
# @api private
|
66
|
-
# @return Array<String> Array of full paths to libyajl2 gem libraries
|
66
|
+
# @return [Array<String>] Array of full paths to libyajl2 gem libraries
|
67
67
|
def expanded_library_names
|
68
68
|
library_names.map do |libname|
|
69
69
|
pathname = File.expand_path(File.join(Libyajl2.opt_path, libname))
|
data/lib/ffi_yajl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-yajl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lamont Granquist
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -122,7 +122,6 @@ extra_rdoc_files:
|
|
122
122
|
files:
|
123
123
|
- LICENSE
|
124
124
|
- README.md
|
125
|
-
- Rakefile
|
126
125
|
- bin/ffi-yajl-bench
|
127
126
|
- ext/ffi_yajl/ext/dlopen/dlopen.c
|
128
127
|
- ext/ffi_yajl/ext/dlopen/extconf.rb
|
@@ -161,10 +160,6 @@ files:
|
|
161
160
|
- lib/ffi_yajl/parser.rb
|
162
161
|
- lib/ffi_yajl/platform.rb
|
163
162
|
- lib/ffi_yajl/version.rb
|
164
|
-
- spec/ffi_yajl/encoder_spec.rb
|
165
|
-
- spec/ffi_yajl/map_library_name_spec.rb
|
166
|
-
- spec/ffi_yajl/parser_spec.rb
|
167
|
-
- spec/spec_helper.rb
|
168
163
|
homepage: http://github.com/chef/ffi-yajl
|
169
164
|
licenses:
|
170
165
|
- MIT
|
@@ -184,8 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
179
|
- !ruby/object:Gem::Version
|
185
180
|
version: '0'
|
186
181
|
requirements: []
|
187
|
-
|
188
|
-
rubygems_version: 2.6.11
|
182
|
+
rubygems_version: 3.0.3
|
189
183
|
signing_key:
|
190
184
|
specification_version: 4
|
191
185
|
summary: Ruby FFI wrapper around YAJL 2.x
|