The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 022
MANIFEST 01
META.json 22
META.yml 22
README 2252
SIGNATURE 1415
XS/Boolean.pm 34
XS.pm 3183
XS.xs 154695
bin/cpanel_json_xs 11
t/96_interop.t 042
typemap 01
12 files changed (This is a version diff) 229920
@@ -4,6 +4,28 @@ TODO: maybe detect and croak on more invalid inputs (e.g. +-inf/nan)
 TODO: maybe avoid the reblessing and better support readonly objects.
 TODO: http://stevehanov.ca/blog/index.php?id=104 compression
 
+3.0102 2014-04-17 (rurban + bulk88)
+       - Added PERL_NO_GET_CONTEXT for better performance on threaded Perls (bulk88)
+       - MANIFEST: added t/96_interop.t
+       - Document deprecated functions
+       - Change booleans interop logic for JSON-XS-3.01
+
+3.0101 2014-04-15 (rurban + bulk88)
+       - Added ithreads support (bulk88)
+         Cpanel::JSON::XS is now thread-safe.
+       - const'ed a translation table for memory savings (bulk88)
+       - Fixed booleans for JSON 2.9 and JSON-XS-3.01 interop.
+         JSON does not support JSON::XS booleans anymore, so
+         I cannot think of any reason to still use JSON::XS.
+
+2.3404 2014-01-30 (rurban)
+       - fix interop with JSON::XS booleans
+         the internal boolean objects are now blessed into JSON::XS::Boolean
+         #13 and [cpan #92548] (samuel.c.kaufman)
+       - t/96_interop.t: added
+       - LICENSE section to pod added for t/z_kwalitee.t
+       - README: fixed some pod spelling errors in (David Steinbrunner)
+
 2.3403 2013-11-02 (cpanel)
        - fix json_atof on AIX without HAS_LONG_DOUBLE (powl in libm)
          [cpan #88061] (Ulisse Monari, Reini Urban)
@@ -32,6 +32,7 @@ t/19_incr.t
 t/20_faihu.t
 t/21_evans.t
 t/22_comment_at_eof.t
+t/96_interop.t
 t/97_unshare_hek.t
 t/98_56only.t
 t/99_binary.t
@@ -4,7 +4,7 @@
       "cPanel Inc. <cpan@cpanel.net>"
    ],
    "dynamic_config" : 1,
-   "generated_by" : "ExtUtils::MakeMaker version 6.64, CPAN::Meta::Converter version 2.120921",
+   "generated_by" : "ExtUtils::MakeMaker version 6.88, CPAN::Meta::Converter version 2.132830",
    "license" : [
       "perl_5"
    ],
@@ -54,5 +54,5 @@
          "url" : "https://github.com/rurban/Cpanel-JSON-XS"
       }
    },
-   "version" : "2.3403"
+   "version" : "3.0102"
 }
@@ -7,7 +7,7 @@ build_requires:
 configure_requires:
   ExtUtils::MakeMaker: 0
 dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.64, CPAN::Meta::Converter version 2.120921'
+generated_by: 'ExtUtils::MakeMaker version 6.88, CPAN::Meta::Converter version 2.132830'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -28,4 +28,4 @@ resources:
   homepage: http://software.schmorp.de/pkg/JSON-XS.html
   license: http://dev.perl.org/licenses/
   repository: https://github.com/rurban/Cpanel-JSON-XS
-version: 2.3403
+version: 3.0102
@@ -67,7 +67,7 @@ DESCRIPTION
     *   simple to use
 
         This module has both a simple functional interface as well as an
-        object oriented interface interface.
+        object oriented interface.
 
     *   reasonably versatile output formats
 
@@ -90,20 +90,19 @@ DESCRIPTION
 
     Changes to JSON::XS
 
-    - public maintainance and bugtracker.
-
     - added "binary" extension, non-JSON and non JSON parsable, allows
     "\xNN" and "\NNN" sequences.
 
     - 5.6.2 support; sacrificing some utf8 features (assuming bytes
     all-over), no multi-byte unicode characters.
 
-    - use ppport.h, sanify XS.xs comment styles, harness C coding style
+    - interop for true/false overloading. JSON::XS and JSON::PP
+    representations are accepted and JSON::XS accepts Cpanel::JSON::XS
+    booleans [#13]
 
-    - common::sense is optional. When available it is not used in the
-    published production module, just during development and testing.
+    - ithread support. Cpanel::JSON::XS is thread-safe, JSON::XS not
 
-    - extended testsuite
+    - performance optimizations for threaded Perls
 
     - additional fixes for:
 
@@ -113,6 +112,15 @@ DESCRIPTION
 
       - #7 avoid re-blessing where possible (e.g. SvREADONLY restricted hashes)
 
+    - public maintenance and bugtracker
+
+    - use ppport.h, sanify XS.xs comment styles, harness C coding style
+
+    - common::sense is optional. When available it is not used in the
+    published production module, just during development and testing.
+
+    - extended testsuite
+
 FUNCTIONAL INTERFACE
     The following convenience methods are provided by this module. They are
     exported by default:
@@ -147,6 +155,13 @@ FUNCTIONAL INTERFACE
         See MAPPING, below, for more information on how JSON values are
         mapped to Perl.
 
+DEPRECATED FUNCTIONS
+    from_json
+        from_json has been renamed to encode_json
+
+    to_json
+        to_json has been renamed to encode_json
+
 A FEW NOTES ON UNICODE AND PERL
     Since this often leads to confusion, here are a few very clear words on
     how Unicode works in Perl, modulo bugs.
@@ -729,7 +744,7 @@ INCREMENTAL PARSING
         extract exactly *one* JSON object. If that is successful, it will
         return this object, otherwise it will return "undef". If there is a
         parse error, this method will croak just as "decode" would do (one
-        can then use "incr_skip" to skip the errornous part). This is the
+        can then use "incr_skip" to skip the erroneous part). This is the
         most common way of using the method.
 
         And finally, in list context, it will try to extract as many objects
@@ -768,7 +783,7 @@ INCREMENTAL PARSING
         to reset the parse state.
 
         The difference to "incr_reset" is that only text until the parse
-        error occured is removed.
+        error occurred is removed.
 
     $json->incr_reset
         This completely resets the incremental parser, that is, after this
@@ -962,7 +977,7 @@ MAPPING
         represent it as a numeric (floating point) value if that is possible
         without loss of precision. Otherwise it will preserve the number as
         a string value (in which case you lose roundtripping ability, as the
-        JSON number will be re-encoded toa JSON string).
+        JSON number will be re-encoded to a JSON string).
 
         Numbers containing a fractional or exponential part will always be
         represented as numeric (floating point) values, possibly at a loss
@@ -973,13 +988,13 @@ MAPPING
         Note that precision is not accuracy - binary floating point values
         cannot represent most decimal fractions exactly, and when converting
         from and to floating point, Cpanel::JSON::XS only guarantees
-        precision up to but not including the leats significant bit.
+        precision up to but not including the least significant bit.
 
     true, false
         These JSON atoms become "JSON::XS::true" and "JSON::XS::false",
         respectively. They are overloaded to act almost exactly like the
         numbers 1 and 0. You can check whether a scalar is a JSON boolean by
-        using the "JSON::XS::is_bool" function.
+        using the "Cpanel::JSON::XS::is_bool" function.
 
     null
         A JSON null atom becomes "undef" in Perl.
@@ -1096,7 +1111,7 @@ ENCODING/CODESET FLAG NOTES
         When "utf8" is disabled (the default), then "encode"/"decode"
         generate and expect Unicode strings, that is, characters with high
         ordinal Unicode values (> 255) will be encoded as such characters,
-        and likewise such characters are decoded as-is, no canges to them
+        and likewise such characters are decoded as-is, no changes to them
         will be done, except "(re-)interpreting" them as Unicode codepoints
         or Unicode characters, respectively (to Perl, these are the same
         thing in strings unless you do funny/weird/dumb stuff).
@@ -1223,7 +1238,7 @@ ENCODING/CODESET FLAG NOTES
        $json =~ s/"__proto__"\s*:/"__proto__renamed":/g;
 
     This works because "__proto__" is not valid outside of strings, so every
-    occurence of ""__proto__"\s*:" must be a string used as property name.
+    occurrence of ""__proto__"\s*:" must be a string used as property name.
 
     If you know of other incompatibilities, please let me know.
 
@@ -1347,6 +1362,21 @@ ENCODING/CODESET FLAG NOTES
     refuse to decode or encode properly, so it was impossible to prepare a
     fair comparison table for that case.
 
+INTEROP with JSON and JSON::XS
+    JSON-XS-3.01 broke interoperability with JSON-2.90 with booleans. See
+    JSON.
+
+    Cpanel::JSON::XS needs to know the JSON and JSON::XS versions to be able
+    work with those objects, especially when encoding a booleans like
+    "{"is_true":true}". So you need to load these modules before.
+
+    true/false overloading is supported.
+
+    JSON::XS and JSON::PP representations are accepted and older JSON::XS
+    accepts Cpanel::JSON::XS booleans.
+
+    I cannot think of any reason to still use JSON::XS anymore.
+
 SECURITY CONSIDERATIONS
     When you are using JSON in a protocol, talking to untrusted potentially
     hostile creatures requires relatively few measures.
@@ -1391,14 +1421,8 @@ SECURITY CONSIDERATIONS
     about getting security right).
 
 THREADS
-    This module is *not* guaranteed to be thread safe and there are no plans
-    to change this until Perl gets thread support (as opposed to the
-    horribly slow so-called "threads" which are simply slow and bloated
-    process simulations - use fork, it's *much* faster, cheaper, better).
-
-    (It might actually work, but you have been warned).
-
-    Data::MessagePack in comparison is thread-safe.
+    Cpanel::JSON::XS has experimental ithreads support, unlike JSON::XS. If
+    you encouter any bugs with thread support please report them.
 
 BUGS
     While the goal of the JSON::XS module is to be correct, that
@@ -1416,6 +1440,10 @@ BUGS
 
     <https://rt.cpan.org/Public/Dist/Display.html?Queue=Cpanel-JSON-XS>
 
+LICENSE
+    This module is available under the same licences as perl, the Artistic
+    license and the GPL.
+
 SEE ALSO
     The cpanel_json_xs command line utility for quick experiments.
 
@@ -1423,6 +1451,8 @@ AUTHOR
       Marc Lehmann <schmorp@schmorp.de>
       http://home.schmorp.de/
 
+      cPanel Inc. <cpan@cpanel.net>
+
 MAINTAINER
       cPanel Inc. <cpan@cpanel.net>
 
@@ -15,16 +15,16 @@ not run its Makefile.PL or Build.PL.
 Hash: SHA1
 
 SHA1 9a56f3b919dfc8fced3803e165a2e38de62646e5 COPYING
-SHA1 33915f32204fe7a3a5dbc662a5a24e1871a4f87f Changes
-SHA1 e1d6083482ce56c9b8f623d6b24538a52a2409fd MANIFEST
-SHA1 517827b559db19e3a58257e52600eddbcc1e2dce META.json
-SHA1 40e69997c7cedf812e50ab374855dab0af56d39d META.yml
+SHA1 b76577825aec8a5f7d76e39120efd42445e3310f Changes
+SHA1 9df4ad56d48700aacb7e5106ed08f24233e4df0b MANIFEST
+SHA1 ceaf2fd178e52bf57baec22dc80b58dc7ef4d78b META.json
+SHA1 360c663a79bec320715988456130a2262dad2b55 META.yml
 SHA1 4856ef5cb39bd758f96d2bc3366c299ae80d383e Makefile.PL
-SHA1 1b023c425cd9a3de685826cb7b8f423951fb5824 README
-SHA1 cb66649a0883e46b0f9e04a3e4d552552f0fd5e0 XS.pm
-SHA1 bec3bc20f9f69a2c286f4986c4b8f0ccaa6c4852 XS.xs
-SHA1 6fcbffce8f8bcff0866df582db26ed378fa4ebbe XS/Boolean.pm
-SHA1 0ed4bd2d211390fbd18ebfe429d69536ec894786 bin/cpanel_json_xs
+SHA1 df8f921891271d7ed6bca63b15b5112d18db1a80 README
+SHA1 f5e9434201fefa1cdc5c663aa70e5c4269fce9e6 XS.pm
+SHA1 177d31e014a9ed81d3b82d416c9849dd08d1755a XS.xs
+SHA1 27b0bc7e0cd6fe90876fb3d285065c6a07cca028 XS/Boolean.pm
+SHA1 8fb15e5f4758020b1f5c449f39e2e4015f22ed19 bin/cpanel_json_xs
 SHA1 ea72bbe602baaabdd0004ef1d7e7cc3334b42bb4 eg/bench
 SHA1 d169c475eede0a30a9935619fec7352deeabc8d5 ppport.h
 SHA1 f7101031fd3fde35fe2421a07ab6cee8a822c00c t/00_load.t
@@ -50,6 +50,7 @@ SHA1 33231a52e12866a61c405496947827485ff2a811 t/19_incr.t
 SHA1 8f266979e62b50271f353e5e6905e52d9038834b t/20_faihu.t
 SHA1 1d9c81e5dfc27ff7f790354ce22af335cefe09c2 t/21_evans.t
 SHA1 3d155f37e687f929bd0cae767dc2dbf1993b73c9 t/22_comment_at_eof.t
+SHA1 7a9f219bcfa41571e8056ac247b224b09c965808 t/96_interop.t
 SHA1 3291c73ec3a19df551d0fff59695153616fc982a t/97_unshare_hek.t
 SHA1 1bf6336a76101f747b84c35cca38c4e8bacb9224 t/98_56only.t
 SHA1 a8664530cf040e24256e3bb16def1b5876e1f33c t/99_binary.t
@@ -58,11 +59,11 @@ SHA1 993b3cef8c06a70d99829facf76140864eb57240 t/z_meta.t
 SHA1 ace5e81d6d512c2dd862f56de8d1b0d6ffb6503e t/z_perl_minimum_version.t
 SHA1 1dbe44e2091ab84d8462fda2052e35bf1354d963 t/z_pod-coverage.t
 SHA1 c8aa3903d3aba84c19bbd94d677620c758fa07d5 t/z_pod.t
-SHA1 ca9b00acccf2ae513551dd126ea9b73870c56acb typemap
+SHA1 8ad74139741a687b63c14bc6b4ae109b556f9af7 typemap
 -----BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.15 (GNU/Linux)
+Version: GnuPG v1
 
-iEYEARECAAYFAlJ1FzEACgkQmm2SYo/9yUJtqgCggAsg1EBucY6AFd/s/1+7qUTx
-SDYAn1YnBVFuG03H679fC4huB/Daes8F
-=PYYz
+iEYEARECAAYFAlNQH0EACgkQmm2SYo/9yUIAOQCZAd4b9Y2uaYpCs/EqnumSazns
+GrAAn0vOZAV8HDQ0kNoJpN5BWdI0gwSb
+=Zal/
 -----END PGP SIGNATURE-----
@@ -1,6 +1,6 @@
 =head1 NAME
 
-Cpanel::JSON::XS::Boolean - dummy module providing Cpanel::JSON::XS::Boolean
+Cpanel::JSON::XS::Boolean - dummy module providing JSON::XS::Boolean
 
 =head1 SYNOPSIS
 
@@ -8,8 +8,9 @@ Cpanel::JSON::XS::Boolean - dummy module providing Cpanel::JSON::XS::Boolean
 
 =head1 DESCRIPTION
 
-This module exists only to provide overload resolution for Storable and similar modules. See
-L<Cpanel::JSON::XS> for more info about this class.
+This module exists only to provide overload resolution for Storable and similar modules
+and interop with L<JSON::XS> booleans.
+See L<Cpanel::JSON::XS> for more info about this class.
 
 =cut
 
@@ -69,7 +69,7 @@ this module usually compares favourably in terms of speed, too.
 =item * simple to use
 
 This module has both a simple functional interface as well as an object
-oriented interface interface.
+oriented interface.
 
 =item * reasonably versatile output formats
 
@@ -94,20 +94,18 @@ or        L<https://rt.cpan.org/Public/Dist/Display.html?Queue=Cpanel-JSON-XS>
 
 B<Changes to JSON::XS>
 
-- public maintainance and bugtracker.
-
 - added C<binary> extension, non-JSON and non JSON parsable, allows
   C<\xNN> and C<\NNN> sequences.
 
 - 5.6.2 support; sacrificing some utf8 features (assuming bytes all-over),
   no multi-byte unicode characters.
 
-- use ppport.h, sanify XS.xs comment styles, harness C coding style
+- interop for true/false overloading. JSON::XS and JSON::PP representations
+  are accepted and JSON::XS accepts Cpanel::JSON::XS booleans [#13]
 
-- common::sense is optional. When available it is not used in the published
-  production module, just during development and testing.
+- ithread support. Cpanel::JSON::XS is thread-safe, JSON::XS not
 
-- extended testsuite
+- performance optimizations for threaded Perls
 
 - additional fixes for:
 
@@ -117,11 +115,21 @@ B<Changes to JSON::XS>
 
   - #7 avoid re-blessing where possible (e.g. SvREADONLY restricted hashes)
 
+- public maintenance and bugtracker
+
+- use ppport.h, sanify XS.xs comment styles, harness C coding style
+
+- common::sense is optional. When available it is not used in the published
+  production module, just during development and testing.
+
+- extended testsuite
+
+
 =cut
 
 package Cpanel::JSON::XS;
 
-our $VERSION = '2.3403';
+our $VERSION = '3.0102';
 our @ISA = qw(Exporter);
 
 our @EXPORT = qw(encode_json decode_json to_json from_json);
@@ -188,6 +196,20 @@ Perl.
 
 =back
 
+=head1 DEPRECATED FUNCTIONS
+
+=over
+
+=item from_json
+
+from_json has been renamed to encode_json
+
+=item to_json
+
+to_json has been renamed to encode_json
+
+=back
+
 
 =head1 A FEW NOTES ON UNICODE AND PERL
 
@@ -815,7 +837,7 @@ If the method is called in scalar context, then it will try to extract
 exactly I<one> JSON object. If that is successful, it will return this
 object, otherwise it will return C<undef>. If there is a parse error,
 this method will croak just as C<decode> would do (one can then use
-C<incr_skip> to skip the errornous part). This is the most common way of
+C<incr_skip> to skip the erroneous part). This is the most common way of
 using the method.
 
 And finally, in list context, it will try to extract as many objects
@@ -856,7 +878,7 @@ state is left unchanged, to skip the text parsed so far and to reset the
 parse state.
 
 The difference to C<incr_reset> is that only text until the parse error
-occured is removed.
+occurred is removed.
 
 =item $json->incr_reset
 
@@ -1064,24 +1086,24 @@ it as an integer value. If that fails, it will try to represent it as
 a numeric (floating point) value if that is possible without loss of
 precision. Otherwise it will preserve the number as a string value (in
 which case you lose roundtripping ability, as the JSON number will be
-re-encoded toa JSON string).
+re-encoded to a JSON string).
 
 Numbers containing a fractional or exponential part will always be
 represented as numeric (floating point) values, possibly at a loss of
 precision (in which case you might lose perfect roundtripping ability, but
 the JSON number will still be re-encoded as a JSON number).
 
-Note that precision is not accuracy - binary floating point values cannot
-represent most decimal fractions exactly, and when converting from and to
-floating point, Cpanel::JSON::XS only guarantees precision up to but not including
-the leats significant bit.
+Note that precision is not accuracy - binary floating point values
+cannot represent most decimal fractions exactly, and when converting
+from and to floating point, Cpanel::JSON::XS only guarantees precision
+up to but not including the least significant bit.
 
 =item true, false
 
 These JSON atoms become C<JSON::XS::true> and C<JSON::XS::false>,
 respectively. They are overloaded to act almost exactly like the numbers
 C<1> and C<0>. You can check whether a scalar is a JSON boolean by using
-the C<JSON::XS::is_bool> function.
+the C<Cpanel::JSON::XS::is_bool> function.
 
 =item null
 
@@ -1215,7 +1237,7 @@ the same time, which can be confusing.
 When C<utf8> is disabled (the default), then C<encode>/C<decode> generate
 and expect Unicode strings, that is, characters with high ordinal Unicode
 values (> 255) will be encoded as such characters, and likewise such
-characters are decoded as-is, no canges to them will be done, except
+characters are decoded as-is, no changes to them will be done, except
 "(re-)interpreting" them as Unicode codepoints or Unicode characters,
 respectively (to Perl, these are the same thing in strings unless you do
 funny/weird/dumb stuff).
@@ -1344,7 +1366,7 @@ output for these property strings, e.g.:
    $json =~ s/"__proto__"\s*:/"__proto__renamed":/g;
 
 This works because C<__proto__> is not valid outside of strings, so every
-occurence of C<"__proto__"\s*:> must be a string used as property name.
+occurrence of C<"__proto__"\s*:> must be a string used as property name.
 
 If you know of other incompatibilities, please let me know.
 
@@ -1477,6 +1499,20 @@ will be broken due to missing (or wrong) Unicode handling. Others refuse
 to decode or encode properly, so it was impossible to prepare a fair
 comparison table for that case.
 
+=head1 INTEROP with JSON and JSON::XS
+
+JSON-XS-3.01 broke interoperability with JSON-2.90 with booleans. See L<JSON>.
+
+Cpanel::JSON::XS needs to know the JSON and JSON::XS versions to be able work
+with those objects, especially when encoding a booleans like C<{"is_true":true}>.
+So you need to load these modules before.
+
+true/false overloading is supported.
+
+JSON::XS and JSON::PP representations are accepted and older JSON::XS accepts
+Cpanel::JSON::XS booleans.
+
+I cannot think of any reason to still use JSON::XS anymore.
 
 =head1 SECURITY CONSIDERATIONS
 
@@ -1524,14 +1560,8 @@ security right).
 
 =head1 THREADS
 
-This module is I<not> guaranteed to be thread safe and there are no
-plans to change this until Perl gets thread support (as opposed to the
-horribly slow so-called "threads" which are simply slow and bloated
-process simulations - use fork, it's I<much> faster, cheaper, better).
-
-(It might actually work, but you have been warned).
-
-L<Data::MessagePack> in comparison is thread-safe.
+Cpanel::JSON::XS has experimental ithreads support, unlike JSON::XS. If you
+encouter any bugs with thread support please report them.
 
 =head1 BUGS
 
@@ -1550,22 +1580,42 @@ JSON::XS as our serializer of choice.
 
 L<https://rt.cpan.org/Public/Dist/Display.html?Queue=Cpanel-JSON-XS>
 
+=head1 LICENSE
+
+This module is available under the same licences as perl, the Artistic
+license and the GPL.
+
 =cut
 
-our $true  = do { bless \(my $dummy = 1), "Cpanel::JSON::XS::Boolean" };
-our $false = do { bless \(my $dummy = 0), "Cpanel::JSON::XS::Boolean" };
+our ($true, $false);
+#if ($INC{'JSON.pm'} and $JSON::VERSION ge "2.54") {
+#  $true  = do { bless {'is_true' => 1}, "JSON::PP::Boolean" };
+#  $false = do { bless {'is_true' => 0}, "JSON::PP::Boolean" };
+#} else {
+#  $true  = do { bless \(my $dummy = 1), "JSON::XS::Boolean" };
+#  $false = do { bless \(my $dummy = 0), "JSON::XS::Boolean" };
+#}
+if ($INC{'JSON/XS.pm'} and $JSON::XS::VERSION ge "3.00") {
+  $true  = do { bless {my $dummy => 1}, "Types::Serialiser" };
+  $false = do { bless {my $dummy => 0}, "Types::Serialiser" };
+} else {
+  $true  = do { bless \(my $dummy = 1), "JSON::XS::Boolean" };
+  $false = do { bless \(my $dummy = 0), "JSON::XS::Boolean" };
+}
 
 sub true()  { $true  }
 sub false() { $false }
 
 sub is_bool($) {
-   UNIVERSAL::isa $_[0], "Cpanel::JSON::XS::Boolean"
-#      or UNIVERSAL::isa $_[0], "JSON::Literal"
+  UNIVERSAL::isa($_[0], "JSON::XS::Boolean")
+   or UNIVERSAL::isa($_[0], "JSON::PP::Boolean")
+   or UNIVERSAL::isa($_[0], "Types::Serialiser");
 }
 
 XSLoader::load 'Cpanel::JSON::XS', $VERSION;
 
-package Cpanel::JSON::XS::Boolean;
+package
+  JSON::XS::Boolean;
 
 use overload
    "0+"     => sub { ${$_[0]} },
@@ -1594,6 +1644,8 @@ The F<cpanel_json_xs> command line utility for quick experiments.
   Marc Lehmann <schmorp@schmorp.de>
   http://home.schmorp.de/
 
+  cPanel Inc. <cpan@cpanel.net>
+
 =head1 MAINTAINER
 
   cPanel Inc. <cpan@cpanel.net>
@@ -1,3 +1,4 @@
+#define PERL_NO_GET_CONTEXT
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
@@ -107,16 +108,18 @@
 
 #define ERR_NESTING_EXCEEDED "json text or perl structure exceeds maximum nesting level (max_depth set too low?)"
 
-#ifdef USE_ITHREADS
-# define JSON_SLOW 1
-# define JSON_STASH (json_stash ? json_stash : gv_stashpv ("Cpanel::JSON::XS", 1))
-#else
-# define JSON_SLOW 0
-# define JSON_STASH json_stash
-#endif
+# define JSON_STASH MY_CXT.json_stash
 
-static HV *json_stash, *json_boolean_stash; /* Cpanel::JSON::XS:: */
-static SV *json_true, *json_false;
+#define MY_CXT_KEY "Cpanel::JSON::XS::_guts"
+
+typedef struct {
+HV *json_stash, *json_boolean_stash; /* Cpanel::JSON::XS:: */
+SV *json_true, *json_false;
+} my_cxt_t;
+
+START_MY_CXT
+
+INLINE SV * get_bool (pTHX_ const char *name);
 
 enum {
   INCR_M_WS = 0, /* initial whitespace skipping, must be 0 */
@@ -151,11 +154,25 @@ json_init (JSON *json)
   json->max_depth = 512;
 }
 
+/* dTHX/threads TODO*/
+/* END dtor call not needed, all of these *s refcnts are owned by the stash
+  treem not C code */
+static void
+init_MY_CXT(pTHX_ my_cxt_t * cxt)
+{
+  cxt->json_stash         = gv_stashpv ("Cpanel::JSON::XS", 1);
+  cxt->json_boolean_stash = gv_stashpv ("JSON::XS::Boolean", 1);
+
+  cxt->json_true  = get_bool (aTHX_ "Cpanel::JSON::XS::true");
+  cxt->json_false = get_bool (aTHX_ "Cpanel::JSON::XS::false");
+}
+
+
 /*/////////////////////////////////////////////////////////////////////////// */
 /* utility functions */
 
 INLINE SV *
-get_bool (const char *name)
+get_bool (pTHX_ const char *name)
 {
   SV *sv = get_sv (name, 1);
 
@@ -166,7 +183,7 @@ get_bool (const char *name)
 }
 
 INLINE void
-shrink (SV *sv)
+shrink (pTHX_ SV *sv)
 {
   sv_utf8_downgrade (sv, 1);
 
@@ -186,7 +203,7 @@ shrink (SV *sv)
 /* but use the very good perl function to parse anything else. */
 /* note that we never call this function for a ascii codepoints */
 INLINE UV
-decode_utf8 (unsigned char *s, STRLEN len, STRLEN *clen)
+decode_utf8 (pTHX_ unsigned char *s, STRLEN len, STRLEN *clen)
 {
   if (expect_true (len >= 2
                    && IN_RANGE_INC (char, s[0], 0xc2, 0xdf)
@@ -231,7 +248,7 @@ encode_utf8 (unsigned char *s, UV ch)
 
 /* convert offset pointer to character index, sv must be string */
 static STRLEN
-ptr_to_index (SV *sv, const U8 *offset)
+ptr_to_index (pTHX_ SV *sv, const U8 *offset)
 {
   return SvUTF8 (sv)
          ? utf8_distance ((U8*)offset, (U8*)SvPVX (sv))
@@ -379,7 +396,7 @@ typedef struct
 } enc_t;
 
 INLINE void
-need (enc_t *enc, STRLEN len)
+need (pTHX_ enc_t *enc, STRLEN len)
 {
   if (expect_false (enc->cur + len >= enc->end))
     {
@@ -391,14 +408,14 @@ need (enc_t *enc, STRLEN len)
 }
 
 INLINE void
-encode_ch (enc_t *enc, char ch)
+encode_ch (pTHX_ enc_t *enc, char ch)
 {
-  need (enc, 1);
+  need (aTHX_ enc, 1);
   *enc->cur++ = ch;
 }
 
 static void
-encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
+encode_str (pTHX_ enc_t *enc, char *str, STRLEN len, int is_utf8)
 {
   char *end = str + len;
 
@@ -412,7 +429,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
       end = str + len;
     }
 #endif
-  need (enc, len);
+  need (aTHX_ enc, len);
 
   while (str < end)
     {
@@ -422,13 +439,13 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
         {
           if (expect_false (ch == '"')) /* but with slow exceptions */
             {
-              need (enc, len += 1);
+              need (aTHX_ enc, len += 1);
               *enc->cur++ = '\\';
               *enc->cur++ = '"';
             }
           else if (expect_false (ch == '\\'))
             {
-              need (enc, len += 1);
+              need (aTHX_ enc, len += 1);
               *enc->cur++ = '\\';
               *enc->cur++ = '\\';
             }
@@ -441,11 +458,11 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
         {
           switch (ch)
             {
-              case '\010': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'b'; ++str; break;
-              case '\011': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 't'; ++str; break;
-              case '\012': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'n'; ++str; break;
-              case '\014': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'f'; ++str; break;
-              case '\015': need (enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'r'; ++str; break;
+              case '\010': need (aTHX_ enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'b'; ++str; break;
+              case '\011': need (aTHX_ enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 't'; ++str; break;
+              case '\012': need (aTHX_ enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'n'; ++str; break;
+              case '\014': need (aTHX_ enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'f'; ++str; break;
+              case '\015': need (aTHX_ enc, len += 1); *enc->cur++ = '\\'; *enc->cur++ = 'r'; ++str; break;
 
               default:
                 {
@@ -454,7 +471,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
 
                   if (is_utf8 && !(enc->json.flags & F_BINARY))
                     {
-                      uch = decode_utf8 ((unsigned char *)str, end - str, &clen);
+                      uch = decode_utf8 (aTHX_ (unsigned char *)str, end - str, &clen);
                       if (clen == (STRLEN)-1)
                         croak ("malformed or illegal unicode character in string [%.11s], cannot convert to JSON", str);
                     }
@@ -469,7 +486,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
 		      if (enc->json.flags & F_BINARY)
 			{
                           /* MB cannot arrivehere */
-                          need (enc, len += 3);
+                          need (aTHX_ enc, len += 3);
                           *enc->cur++ = '\\';
                           *enc->cur++ = 'x';
                           *enc->cur++ = PL_hexdigit [(uch >>  4) & 15];
@@ -480,7 +497,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
                           if (uch >= 0x110000UL)
                             croak ("out of range codepoint (0x%lx) encountered, unrepresentable in JSON", (unsigned long)uch);
 
-                          need (enc, len += 11);
+                          need (aTHX_ enc, len += 11);
                           sprintf (enc->cur, "\\u%04x\\u%04x",
                                    (int)((uch - 0x10000) / 0x400 + 0xD800),
                                    (int)((uch - 0x10000) % 0x400 + 0xDC00));
@@ -488,7 +505,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
                         }
 		      else
                         {
-                          need (enc, len += 5);
+                          need (aTHX_ enc, len += 5);
                           *enc->cur++ = '\\';
                           *enc->cur++ = 'u';
                           *enc->cur++ = PL_hexdigit [ uch >> 12      ];
@@ -511,7 +528,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
                     }
                   else if (is_utf8)
                     {
-                      need (enc, len += clen);
+                      need (aTHX_ enc, len += clen);
                       do
                         {
                           *enc->cur++ = *str++;
@@ -520,7 +537,7 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
                     }
                   else
                     {
-                      need (enc, len += UTF8_MAXBYTES - 1); /* never more than 11 bytes needed */
+                      need (aTHX_ enc, len += UTF8_MAXBYTES - 1); /* never more than 11 bytes needed */
                       enc->cur = (char*)encode_utf8 ((U8*)enc->cur, uch);
                       ++str;
                     }
@@ -533,87 +550,87 @@ encode_str (enc_t *enc, char *str, STRLEN len, int is_utf8)
 }
 
 INLINE void
-encode_indent (enc_t *enc)
+encode_indent (pTHX_ enc_t *enc)
 {
   if (enc->json.flags & F_INDENT)
     {
       int spaces = enc->indent * INDENT_STEP;
 
-      need (enc, spaces);
+      need (aTHX_ enc, spaces);
       memset (enc->cur, ' ', spaces);
       enc->cur += spaces;
     }
 }
 
 INLINE void
-encode_space (enc_t *enc)
+encode_space (pTHX_ enc_t *enc)
 {
-  need (enc, 1);
-  encode_ch (enc, ' ');
+  need (aTHX_ enc, 1);
+  encode_ch (aTHX_ enc, ' ');
 }
 
 INLINE void
-encode_nl (enc_t *enc)
+encode_nl (pTHX_ enc_t *enc)
 {
   if (enc->json.flags & F_INDENT)
     {
-      need (enc, 1);
-      encode_ch (enc, '\n');
+      need (aTHX_ enc, 1);
+      encode_ch (aTHX_ enc, '\n');
     }
 }
 
 INLINE void
-encode_comma (enc_t *enc)
+encode_comma (pTHX_ enc_t *enc)
 {
-  encode_ch (enc, ',');
+  encode_ch (aTHX_ enc, ',');
 
   if (enc->json.flags & F_INDENT)
-    encode_nl (enc);
+    encode_nl (aTHX_ enc);
   else if (enc->json.flags & F_SPACE_AFTER)
-    encode_space (enc);
+    encode_space (aTHX_ enc);
 }
 
-static void encode_sv (enc_t *enc, SV *sv);
+static void encode_sv (pTHX_ enc_t *enc, SV *sv);
 
 static void
-encode_av (enc_t *enc, AV *av)
+encode_av (pTHX_ enc_t *enc, AV *av)
 {
   int i, len = av_len (av);
 
   if (enc->indent >= enc->json.max_depth)
     croak (ERR_NESTING_EXCEEDED);
 
-  encode_ch (enc, '[');
+  encode_ch (aTHX_ enc, '[');
   
   if (len >= 0)
     {
-      encode_nl (enc); ++enc->indent;
+      encode_nl (aTHX_ enc); ++enc->indent;
 
       for (i = 0; i <= len; ++i)
         {
           SV **svp = av_fetch (av, i, 0);
 
-          encode_indent (enc);
+          encode_indent (aTHX_ enc);
 
           if (svp)
-            encode_sv (enc, *svp);
+            encode_sv (aTHX_ enc, *svp);
           else
-            encode_str (enc, "null", 4, 0);
+            encode_str (aTHX_ enc, "null", 4, 0);
 
           if (i < len)
-            encode_comma (enc);
+            encode_comma (aTHX_ enc);
         }
 
-      encode_nl (enc); --enc->indent; encode_indent (enc);
+      encode_nl (aTHX_ enc); --enc->indent; encode_indent (aTHX_ enc);
     }
   
-  encode_ch (enc, ']');
+  encode_ch (aTHX_ enc, ']');
 }
 
 static void
-encode_hk (enc_t *enc, HE *he)
+encode_hk (pTHX_ enc_t *enc, HE *he)
 {
-  encode_ch (enc, '"');
+  encode_ch (aTHX_ enc, '"');
 
   if (HeKLEN (he) == HEf_SVKEY)
     {
@@ -624,16 +641,16 @@ encode_hk (enc_t *enc, HE *he)
       SvGETMAGIC (sv);
       str = SvPV (sv, len);
 
-      encode_str (enc, str, len, SvUTF8 (sv));
+      encode_str (aTHX_ enc, str, len, SvUTF8 (sv));
     }
   else
-    encode_str (enc, HeKEY (he), HeKLEN (he), HeKUTF8 (he));
+    encode_str (aTHX_ enc, HeKEY (he), HeKLEN (he), HeKUTF8 (he));
 
-  encode_ch (enc, '"');
+  encode_ch (aTHX_ enc, '"');
 
-  if (enc->json.flags & F_SPACE_BEFORE) encode_space (enc);
-  encode_ch (enc, ':');
-  if (enc->json.flags & F_SPACE_AFTER ) encode_space (enc);
+  if (enc->json.flags & F_SPACE_BEFORE) encode_space (aTHX_ enc);
+  encode_ch (aTHX_ enc, ':');
+  if (enc->json.flags & F_SPACE_AFTER ) encode_space (aTHX_ enc);
 }
 
 /* compare hash entries, used when all keys are bytestrings */
@@ -658,18 +675,19 @@ he_cmp_fast (const void *a_, const void *b_)
 static int
 he_cmp_slow (const void *a, const void *b)
 {
+  dTHX;
   return sv_cmp (HeSVKEY_force (*(HE **)b), HeSVKEY_force (*(HE **)a));
 }
 
 static void
-encode_hv (enc_t *enc, HV *hv)
+encode_hv (pTHX_ enc_t *enc, HV *hv)
 {
   HE *he;
 
   if (enc->indent >= enc->json.max_depth)
     croak (ERR_NESTING_EXCEEDED);
 
-  encode_ch (enc, '{');
+  encode_ch (aTHX_ enc, '{');
 
   /* for canonical output we have to sort by keys first */
   /* actually, this is mostly due to the stupid so-called */
@@ -732,20 +750,20 @@ encode_hv (enc_t *enc, HV *hv)
               LEAVE;
             }
 
-          encode_nl (enc); ++enc->indent;
+          encode_nl (aTHX_ enc); ++enc->indent;
 
           while (count--)
             {
-              encode_indent (enc);
+              encode_indent (aTHX_ enc);
               he = hes [count];
-              encode_hk (enc, he);
-              encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he));
+              encode_hk (aTHX_ enc, he);
+              encode_sv (aTHX_ enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he));
 
               if (count)
-                encode_comma (enc);
+                encode_comma (aTHX_ enc);
             }
 
-          encode_nl (enc); --enc->indent; encode_indent (enc);
+          encode_nl (aTHX_ enc); --enc->indent; encode_indent (aTHX_ enc);
         }
     }
   else
@@ -753,30 +771,30 @@ encode_hv (enc_t *enc, HV *hv)
       if (hv_iterinit (hv) || SvMAGICAL (hv))
         if ((he = hv_iternext (hv)))
           {
-            encode_nl (enc); ++enc->indent;
+            encode_nl (aTHX_ enc); ++enc->indent;
 
             for (;;)
               {
-                encode_indent (enc);
-                encode_hk (enc, he);
-                encode_sv (enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he));
+                encode_indent (aTHX_ enc);
+                encode_hk (aTHX_ enc, he);
+                encode_sv (aTHX_ enc, expect_false (SvMAGICAL (hv)) ? hv_iterval (hv, he) : HeVAL (he));
 
                 if (!(he = hv_iternext (hv)))
                   break;
 
-                encode_comma (enc);
+                encode_comma (aTHX_ enc);
               }
 
-            encode_nl (enc); --enc->indent; encode_indent (enc);
+            encode_nl (aTHX_ enc); --enc->indent; encode_indent (aTHX_ enc);
           }
     }
 
-  encode_ch (enc, '}');
+  encode_ch (aTHX_ enc, '}');
 }
 
 /* encode objects, arrays and special \0=false and \1=true values. */
 static void
-encode_rv (enc_t *enc, SV *sv)
+encode_rv (pTHX_ enc_t *enc, SV *sv)
 {
   svtype svt;
 
@@ -785,16 +803,15 @@ encode_rv (enc_t *enc, SV *sv)
 
   if (expect_false (SvOBJECT (sv)))
     {
-      HV *stash = !JSON_SLOW || json_boolean_stash
-                  ? json_boolean_stash
-                  : gv_stashpv ("Cpanel::JSON::XS::Boolean", 1);
+      dMY_CXT;
+      HV *stash = MY_CXT.json_boolean_stash;
 
       if (SvSTASH (sv) == stash)
         {
           if (SvIV (sv))
-            encode_str (enc, "true", 4, 0);
+            encode_str (aTHX_ enc, "true", 4, 0);
           else
-            encode_str (enc, "false", 5, 0);
+            encode_str (aTHX_ enc, "false", 5, 0);
         }
       else
         {
@@ -812,7 +829,9 @@ encode_rv (enc_t *enc, SV *sv)
                 {
                   dSP;
                   SV *rv;
+#if PERL_VERSION < 10
                   HV *stash;
+#endif
 
                   ENTER; SAVETMPS; PUSHMARK (SP);
 
@@ -838,51 +857,51 @@ encode_rv (enc_t *enc, SV *sv)
                   sv = POPs;
                   PUTBACK;
 
-                  encode_sv (enc, sv);
+                  encode_sv (aTHX_ enc, sv);
 
                   FREETMPS; LEAVE;
                 }
               else if (enc->json.flags & F_ALLOW_BLESSED)
-                encode_str (enc, "null", 4, 0);
+                encode_str (aTHX_ enc, "null", 4, 0);
               else
                 croak ("encountered object '%s', but neither allow_blessed enabled nor TO_JSON method available on it",
                        SvPV_nolen (sv_2mortal (newRV_inc (sv))));
             }
           else if (enc->json.flags & F_ALLOW_BLESSED)
-            encode_str (enc, "null", 4, 0);
+            encode_str (aTHX_ enc, "null", 4, 0);
           else
             croak ("encountered object '%s', but neither allow_blessed nor convert_blessed settings are enabled",
                    SvPV_nolen (sv_2mortal (newRV_inc (sv))));
         }
     }
   else if (svt == SVt_PVHV)
-    encode_hv (enc, (HV *)sv);
+    encode_hv (aTHX_ enc, (HV *)sv);
   else if (svt == SVt_PVAV)
-    encode_av (enc, (AV *)sv);
+    encode_av (aTHX_ enc, (AV *)sv);
   else if (svt < SVt_PVAV)
     {
       STRLEN len = 0;
       char *pv = svt ? SvPV (sv, len) : 0;
 
       if (len == 1 && *pv == '1')
-        encode_str (enc, "true", 4, 0);
+        encode_str (aTHX_ enc, "true", 4, 0);
       else if (len == 1 && *pv == '0')
-        encode_str (enc, "false", 5, 0);
+        encode_str (aTHX_ enc, "false", 5, 0);
       else if (enc->json.flags & F_ALLOW_UNKNOWN)
-        encode_str (enc, "null", 4, 0);
+        encode_str (aTHX_ enc, "null", 4, 0);
       else
         croak ("cannot encode reference to scalar '%s' unless the scalar is 0 or 1",
                SvPV_nolen (sv_2mortal (newRV_inc (sv))));
     }
   else if (enc->json.flags & F_ALLOW_UNKNOWN)
-    encode_str (enc, "null", 4, 0);
+    encode_str (aTHX_ enc, "null", 4, 0);
   else
     croak ("encountered %s, but JSON can only represent references to arrays or hashes",
            SvPV_nolen (sv_2mortal (newRV_inc (sv))));
 }
 
 static void
-encode_sv (enc_t *enc, SV *sv)
+encode_sv (pTHX_ enc_t *enc, SV *sv)
 {
   SvGETMAGIC (sv);
 
@@ -890,14 +909,14 @@ encode_sv (enc_t *enc, SV *sv)
     {
       STRLEN len;
       char *str = SvPV (sv, len);
-      encode_ch (enc, '"');
-      encode_str (enc, str, len, SvUTF8 (sv));
-      encode_ch (enc, '"');
+      encode_ch (aTHX_ enc, '"');
+      encode_str (aTHX_ enc, str, len, SvUTF8 (sv));
+      encode_ch (aTHX_ enc, '"');
     }
   else if (SvNOKp (sv))
     {
       /* trust that perl will do the right thing w.r.t. JSON syntax. */
-      need (enc, NV_DIG + 32);
+      need (aTHX_ enc, NV_DIG + 32);
       Gconvert (SvNVX (sv), NV_DIG, 0, enc->cur);
       enc->cur += strlen (enc->cur);
     }
@@ -916,7 +935,7 @@ encode_sv (enc_t *enc, SV *sv)
           U32 u;
           char digit, nz = 0;
 
-          need (enc, 6);
+          need (aTHX_ enc, 6);
 
           *enc->cur = '-'; enc->cur += i < 0 ? 1 : 0;
           u = i < 0 ? -i : i;
@@ -938,7 +957,7 @@ encode_sv (enc_t *enc, SV *sv)
       else
         {
           /* large integer, use the (rather slow) snprintf way. */
-          need (enc, IVUV_MAXCHARS);
+          need (aTHX_ enc, IVUV_MAXCHARS);
           enc->cur +=
              SvIsUV(sv)
                 ? snprintf (enc->cur, IVUV_MAXCHARS, "%"UVuf, (UV)SvUVX (sv))
@@ -946,16 +965,16 @@ encode_sv (enc_t *enc, SV *sv)
         }
     }
   else if (SvROK (sv))
-    encode_rv (enc, SvRV (sv));
+    encode_rv (aTHX_ enc, SvRV (sv));
   else if (!SvOK (sv) || enc->json.flags & F_ALLOW_UNKNOWN)
-    encode_str (enc, "null", 4, 0);
+    encode_str (aTHX_ enc, "null", 4, 0);
   else
     croak ("encountered perl type (%s,0x%x) that JSON cannot handle, you might want to report this",
            SvPV_nolen (sv), (unsigned int)SvFLAGS (sv));
 }
 
 static SV *
-encode_json (SV *scalar, JSON *json)
+encode_json (pTHX_ SV *scalar, JSON *json)
 {
   enc_t enc;
 
@@ -973,8 +992,8 @@ encode_json (SV *scalar, JSON *json)
                                             : 0x110000UL;
 
   SvPOK_only (enc.sv);
-  encode_sv (&enc, scalar);
-  encode_nl (&enc);
+  encode_sv (aTHX_ &enc, scalar);
+  encode_nl (aTHX_ &enc);
 
   SvCUR_set (enc.sv, enc.cur - SvPVX (enc.sv));
   *SvEND (enc.sv) = 0; /* many xs functions expect a trailing 0 for text strings */
@@ -983,7 +1002,7 @@ encode_json (SV *scalar, JSON *json)
     SvUTF8_on (enc.sv);
 
   if (enc.json.flags & F_SHRINK)
-    shrink (enc.sv);
+    shrink (aTHX_ enc.sv);
 
   return enc.sv;
 }
@@ -1048,9 +1067,531 @@ decode_ws (dec_t *dec)
 #define DEC_INC_DEPTH if (++dec->depth > dec->json.max_depth) ERR (ERR_NESTING_EXCEEDED)
 #define DEC_DEC_DEPTH --dec->depth
 
-static SV *decode_sv (dec_t *dec);
+static SV *decode_sv (pTHX_ dec_t *dec);
 
-static signed char decode_hexdigit[256];
+/* #regen code
+ my $i;
+for ($i = 0; $i < 256; ++$i){
+print
+"    $i >= '0' && $i <= '9' ? $i - '0' : $i >= 'a' && $i <= 'f' ? $i - 'a' + 10
+    : $i >= 'A' && $i <= 'F' ? $i - 'A' + 10 : -1 ,
+";
+}
+*/
+const static signed char decode_hexdigit[256] = {
+    0 >= '0' && 0 <= '9' ? 0 - '0' : 0 >= 'a' && 0 <= 'f' ? 0 - 'a' + 10
+    : 0 >= 'A' && 0 <= 'F' ? 0 - 'A' + 10 : -1 ,
+    1 >= '0' && 1 <= '9' ? 1 - '0' : 1 >= 'a' && 1 <= 'f' ? 1 - 'a' + 10
+    : 1 >= 'A' && 1 <= 'F' ? 1 - 'A' + 10 : -1 ,
+    2 >= '0' && 2 <= '9' ? 2 - '0' : 2 >= 'a' && 2 <= 'f' ? 2 - 'a' + 10
+    : 2 >= 'A' && 2 <= 'F' ? 2 - 'A' + 10 : -1 ,
+    3 >= '0' && 3 <= '9' ? 3 - '0' : 3 >= 'a' && 3 <= 'f' ? 3 - 'a' + 10
+    : 3 >= 'A' && 3 <= 'F' ? 3 - 'A' + 10 : -1 ,
+    4 >= '0' && 4 <= '9' ? 4 - '0' : 4 >= 'a' && 4 <= 'f' ? 4 - 'a' + 10
+    : 4 >= 'A' && 4 <= 'F' ? 4 - 'A' + 10 : -1 ,
+    5 >= '0' && 5 <= '9' ? 5 - '0' : 5 >= 'a' && 5 <= 'f' ? 5 - 'a' + 10
+    : 5 >= 'A' && 5 <= 'F' ? 5 - 'A' + 10 : -1 ,
+    6 >= '0' && 6 <= '9' ? 6 - '0' : 6 >= 'a' && 6 <= 'f' ? 6 - 'a' + 10
+    : 6 >= 'A' && 6 <= 'F' ? 6 - 'A' + 10 : -1 ,
+    7 >= '0' && 7 <= '9' ? 7 - '0' : 7 >= 'a' && 7 <= 'f' ? 7 - 'a' + 10
+    : 7 >= 'A' && 7 <= 'F' ? 7 - 'A' + 10 : -1 ,
+    8 >= '0' && 8 <= '9' ? 8 - '0' : 8 >= 'a' && 8 <= 'f' ? 8 - 'a' + 10
+    : 8 >= 'A' && 8 <= 'F' ? 8 - 'A' + 10 : -1 ,
+    9 >= '0' && 9 <= '9' ? 9 - '0' : 9 >= 'a' && 9 <= 'f' ? 9 - 'a' + 10
+    : 9 >= 'A' && 9 <= 'F' ? 9 - 'A' + 10 : -1 ,
+    10 >= '0' && 10 <= '9' ? 10 - '0' : 10 >= 'a' && 10 <= 'f' ? 10 - 'a' + 10
+    : 10 >= 'A' && 10 <= 'F' ? 10 - 'A' + 10 : -1 ,
+    11 >= '0' && 11 <= '9' ? 11 - '0' : 11 >= 'a' && 11 <= 'f' ? 11 - 'a' + 10
+    : 11 >= 'A' && 11 <= 'F' ? 11 - 'A' + 10 : -1 ,
+    12 >= '0' && 12 <= '9' ? 12 - '0' : 12 >= 'a' && 12 <= 'f' ? 12 - 'a' + 10
+    : 12 >= 'A' && 12 <= 'F' ? 12 - 'A' + 10 : -1 ,
+    13 >= '0' && 13 <= '9' ? 13 - '0' : 13 >= 'a' && 13 <= 'f' ? 13 - 'a' + 10
+    : 13 >= 'A' && 13 <= 'F' ? 13 - 'A' + 10 : -1 ,
+    14 >= '0' && 14 <= '9' ? 14 - '0' : 14 >= 'a' && 14 <= 'f' ? 14 - 'a' + 10
+    : 14 >= 'A' && 14 <= 'F' ? 14 - 'A' + 10 : -1 ,
+    15 >= '0' && 15 <= '9' ? 15 - '0' : 15 >= 'a' && 15 <= 'f' ? 15 - 'a' + 10
+    : 15 >= 'A' && 15 <= 'F' ? 15 - 'A' + 10 : -1 ,
+    16 >= '0' && 16 <= '9' ? 16 - '0' : 16 >= 'a' && 16 <= 'f' ? 16 - 'a' + 10
+    : 16 >= 'A' && 16 <= 'F' ? 16 - 'A' + 10 : -1 ,
+    17 >= '0' && 17 <= '9' ? 17 - '0' : 17 >= 'a' && 17 <= 'f' ? 17 - 'a' + 10
+    : 17 >= 'A' && 17 <= 'F' ? 17 - 'A' + 10 : -1 ,
+    18 >= '0' && 18 <= '9' ? 18 - '0' : 18 >= 'a' && 18 <= 'f' ? 18 - 'a' + 10
+    : 18 >= 'A' && 18 <= 'F' ? 18 - 'A' + 10 : -1 ,
+    19 >= '0' && 19 <= '9' ? 19 - '0' : 19 >= 'a' && 19 <= 'f' ? 19 - 'a' + 10
+    : 19 >= 'A' && 19 <= 'F' ? 19 - 'A' + 10 : -1 ,
+    20 >= '0' && 20 <= '9' ? 20 - '0' : 20 >= 'a' && 20 <= 'f' ? 20 - 'a' + 10
+    : 20 >= 'A' && 20 <= 'F' ? 20 - 'A' + 10 : -1 ,
+    21 >= '0' && 21 <= '9' ? 21 - '0' : 21 >= 'a' && 21 <= 'f' ? 21 - 'a' + 10
+    : 21 >= 'A' && 21 <= 'F' ? 21 - 'A' + 10 : -1 ,
+    22 >= '0' && 22 <= '9' ? 22 - '0' : 22 >= 'a' && 22 <= 'f' ? 22 - 'a' + 10
+    : 22 >= 'A' && 22 <= 'F' ? 22 - 'A' + 10 : -1 ,
+    23 >= '0' && 23 <= '9' ? 23 - '0' : 23 >= 'a' && 23 <= 'f' ? 23 - 'a' + 10
+    : 23 >= 'A' && 23 <= 'F' ? 23 - 'A' + 10 : -1 ,
+    24 >= '0' && 24 <= '9' ? 24 - '0' : 24 >= 'a' && 24 <= 'f' ? 24 - 'a' + 10
+    : 24 >= 'A' && 24 <= 'F' ? 24 - 'A' + 10 : -1 ,
+    25 >= '0' && 25 <= '9' ? 25 - '0' : 25 >= 'a' && 25 <= 'f' ? 25 - 'a' + 10
+    : 25 >= 'A' && 25 <= 'F' ? 25 - 'A' + 10 : -1 ,
+    26 >= '0' && 26 <= '9' ? 26 - '0' : 26 >= 'a' && 26 <= 'f' ? 26 - 'a' + 10
+    : 26 >= 'A' && 26 <= 'F' ? 26 - 'A' + 10 : -1 ,
+    27 >= '0' && 27 <= '9' ? 27 - '0' : 27 >= 'a' && 27 <= 'f' ? 27 - 'a' + 10
+    : 27 >= 'A' && 27 <= 'F' ? 27 - 'A' + 10 : -1 ,
+    28 >= '0' && 28 <= '9' ? 28 - '0' : 28 >= 'a' && 28 <= 'f' ? 28 - 'a' + 10
+    : 28 >= 'A' && 28 <= 'F' ? 28 - 'A' + 10 : -1 ,
+    29 >= '0' && 29 <= '9' ? 29 - '0' : 29 >= 'a' && 29 <= 'f' ? 29 - 'a' + 10
+    : 29 >= 'A' && 29 <= 'F' ? 29 - 'A' + 10 : -1 ,
+    30 >= '0' && 30 <= '9' ? 30 - '0' : 30 >= 'a' && 30 <= 'f' ? 30 - 'a' + 10
+    : 30 >= 'A' && 30 <= 'F' ? 30 - 'A' + 10 : -1 ,
+    31 >= '0' && 31 <= '9' ? 31 - '0' : 31 >= 'a' && 31 <= 'f' ? 31 - 'a' + 10
+    : 31 >= 'A' && 31 <= 'F' ? 31 - 'A' + 10 : -1 ,
+    32 >= '0' && 32 <= '9' ? 32 - '0' : 32 >= 'a' && 32 <= 'f' ? 32 - 'a' + 10
+    : 32 >= 'A' && 32 <= 'F' ? 32 - 'A' + 10 : -1 ,
+    33 >= '0' && 33 <= '9' ? 33 - '0' : 33 >= 'a' && 33 <= 'f' ? 33 - 'a' + 10
+    : 33 >= 'A' && 33 <= 'F' ? 33 - 'A' + 10 : -1 ,
+    34 >= '0' && 34 <= '9' ? 34 - '0' : 34 >= 'a' && 34 <= 'f' ? 34 - 'a' + 10
+    : 34 >= 'A' && 34 <= 'F' ? 34 - 'A' + 10 : -1 ,
+    35 >= '0' && 35 <= '9' ? 35 - '0' : 35 >= 'a' && 35 <= 'f' ? 35 - 'a' + 10
+    : 35 >= 'A' && 35 <= 'F' ? 35 - 'A' + 10 : -1 ,
+    36 >= '0' && 36 <= '9' ? 36 - '0' : 36 >= 'a' && 36 <= 'f' ? 36 - 'a' + 10
+    : 36 >= 'A' && 36 <= 'F' ? 36 - 'A' + 10 : -1 ,
+    37 >= '0' && 37 <= '9' ? 37 - '0' : 37 >= 'a' && 37 <= 'f' ? 37 - 'a' + 10
+    : 37 >= 'A' && 37 <= 'F' ? 37 - 'A' + 10 : -1 ,
+    38 >= '0' && 38 <= '9' ? 38 - '0' : 38 >= 'a' && 38 <= 'f' ? 38 - 'a' + 10
+    : 38 >= 'A' && 38 <= 'F' ? 38 - 'A' + 10 : -1 ,
+    39 >= '0' && 39 <= '9' ? 39 - '0' : 39 >= 'a' && 39 <= 'f' ? 39 - 'a' + 10
+    : 39 >= 'A' && 39 <= 'F' ? 39 - 'A' + 10 : -1 ,
+    40 >= '0' && 40 <= '9' ? 40 - '0' : 40 >= 'a' && 40 <= 'f' ? 40 - 'a' + 10
+    : 40 >= 'A' && 40 <= 'F' ? 40 - 'A' + 10 : -1 ,
+    41 >= '0' && 41 <= '9' ? 41 - '0' : 41 >= 'a' && 41 <= 'f' ? 41 - 'a' + 10
+    : 41 >= 'A' && 41 <= 'F' ? 41 - 'A' + 10 : -1 ,
+    42 >= '0' && 42 <= '9' ? 42 - '0' : 42 >= 'a' && 42 <= 'f' ? 42 - 'a' + 10
+    : 42 >= 'A' && 42 <= 'F' ? 42 - 'A' + 10 : -1 ,
+    43 >= '0' && 43 <= '9' ? 43 - '0' : 43 >= 'a' && 43 <= 'f' ? 43 - 'a' + 10
+    : 43 >= 'A' && 43 <= 'F' ? 43 - 'A' + 10 : -1 ,
+    44 >= '0' && 44 <= '9' ? 44 - '0' : 44 >= 'a' && 44 <= 'f' ? 44 - 'a' + 10
+    : 44 >= 'A' && 44 <= 'F' ? 44 - 'A' + 10 : -1 ,
+    45 >= '0' && 45 <= '9' ? 45 - '0' : 45 >= 'a' && 45 <= 'f' ? 45 - 'a' + 10
+    : 45 >= 'A' && 45 <= 'F' ? 45 - 'A' + 10 : -1 ,
+    46 >= '0' && 46 <= '9' ? 46 - '0' : 46 >= 'a' && 46 <= 'f' ? 46 - 'a' + 10
+    : 46 >= 'A' && 46 <= 'F' ? 46 - 'A' + 10 : -1 ,
+    47 >= '0' && 47 <= '9' ? 47 - '0' : 47 >= 'a' && 47 <= 'f' ? 47 - 'a' + 10
+    : 47 >= 'A' && 47 <= 'F' ? 47 - 'A' + 10 : -1 ,
+    48 >= '0' && 48 <= '9' ? 48 - '0' : 48 >= 'a' && 48 <= 'f' ? 48 - 'a' + 10
+    : 48 >= 'A' && 48 <= 'F' ? 48 - 'A' + 10 : -1 ,
+    49 >= '0' && 49 <= '9' ? 49 - '0' : 49 >= 'a' && 49 <= 'f' ? 49 - 'a' + 10
+    : 49 >= 'A' && 49 <= 'F' ? 49 - 'A' + 10 : -1 ,
+    50 >= '0' && 50 <= '9' ? 50 - '0' : 50 >= 'a' && 50 <= 'f' ? 50 - 'a' + 10
+    : 50 >= 'A' && 50 <= 'F' ? 50 - 'A' + 10 : -1 ,
+    51 >= '0' && 51 <= '9' ? 51 - '0' : 51 >= 'a' && 51 <= 'f' ? 51 - 'a' + 10
+    : 51 >= 'A' && 51 <= 'F' ? 51 - 'A' + 10 : -1 ,
+    52 >= '0' && 52 <= '9' ? 52 - '0' : 52 >= 'a' && 52 <= 'f' ? 52 - 'a' + 10
+    : 52 >= 'A' && 52 <= 'F' ? 52 - 'A' + 10 : -1 ,
+    53 >= '0' && 53 <= '9' ? 53 - '0' : 53 >= 'a' && 53 <= 'f' ? 53 - 'a' + 10
+    : 53 >= 'A' && 53 <= 'F' ? 53 - 'A' + 10 : -1 ,
+    54 >= '0' && 54 <= '9' ? 54 - '0' : 54 >= 'a' && 54 <= 'f' ? 54 - 'a' + 10
+    : 54 >= 'A' && 54 <= 'F' ? 54 - 'A' + 10 : -1 ,
+    55 >= '0' && 55 <= '9' ? 55 - '0' : 55 >= 'a' && 55 <= 'f' ? 55 - 'a' + 10
+    : 55 >= 'A' && 55 <= 'F' ? 55 - 'A' + 10 : -1 ,
+    56 >= '0' && 56 <= '9' ? 56 - '0' : 56 >= 'a' && 56 <= 'f' ? 56 - 'a' + 10
+    : 56 >= 'A' && 56 <= 'F' ? 56 - 'A' + 10 : -1 ,
+    57 >= '0' && 57 <= '9' ? 57 - '0' : 57 >= 'a' && 57 <= 'f' ? 57 - 'a' + 10
+    : 57 >= 'A' && 57 <= 'F' ? 57 - 'A' + 10 : -1 ,
+    58 >= '0' && 58 <= '9' ? 58 - '0' : 58 >= 'a' && 58 <= 'f' ? 58 - 'a' + 10
+    : 58 >= 'A' && 58 <= 'F' ? 58 - 'A' + 10 : -1 ,
+    59 >= '0' && 59 <= '9' ? 59 - '0' : 59 >= 'a' && 59 <= 'f' ? 59 - 'a' + 10
+    : 59 >= 'A' && 59 <= 'F' ? 59 - 'A' + 10 : -1 ,
+    60 >= '0' && 60 <= '9' ? 60 - '0' : 60 >= 'a' && 60 <= 'f' ? 60 - 'a' + 10
+    : 60 >= 'A' && 60 <= 'F' ? 60 - 'A' + 10 : -1 ,
+    61 >= '0' && 61 <= '9' ? 61 - '0' : 61 >= 'a' && 61 <= 'f' ? 61 - 'a' + 10
+    : 61 >= 'A' && 61 <= 'F' ? 61 - 'A' + 10 : -1 ,
+    62 >= '0' && 62 <= '9' ? 62 - '0' : 62 >= 'a' && 62 <= 'f' ? 62 - 'a' + 10
+    : 62 >= 'A' && 62 <= 'F' ? 62 - 'A' + 10 : -1 ,
+    63 >= '0' && 63 <= '9' ? 63 - '0' : 63 >= 'a' && 63 <= 'f' ? 63 - 'a' + 10
+    : 63 >= 'A' && 63 <= 'F' ? 63 - 'A' + 10 : -1 ,
+    64 >= '0' && 64 <= '9' ? 64 - '0' : 64 >= 'a' && 64 <= 'f' ? 64 - 'a' + 10
+    : 64 >= 'A' && 64 <= 'F' ? 64 - 'A' + 10 : -1 ,
+    65 >= '0' && 65 <= '9' ? 65 - '0' : 65 >= 'a' && 65 <= 'f' ? 65 - 'a' + 10
+    : 65 >= 'A' && 65 <= 'F' ? 65 - 'A' + 10 : -1 ,
+    66 >= '0' && 66 <= '9' ? 66 - '0' : 66 >= 'a' && 66 <= 'f' ? 66 - 'a' + 10
+    : 66 >= 'A' && 66 <= 'F' ? 66 - 'A' + 10 : -1 ,
+    67 >= '0' && 67 <= '9' ? 67 - '0' : 67 >= 'a' && 67 <= 'f' ? 67 - 'a' + 10
+    : 67 >= 'A' && 67 <= 'F' ? 67 - 'A' + 10 : -1 ,
+    68 >= '0' && 68 <= '9' ? 68 - '0' : 68 >= 'a' && 68 <= 'f' ? 68 - 'a' + 10
+    : 68 >= 'A' && 68 <= 'F' ? 68 - 'A' + 10 : -1 ,
+    69 >= '0' && 69 <= '9' ? 69 - '0' : 69 >= 'a' && 69 <= 'f' ? 69 - 'a' + 10
+    : 69 >= 'A' && 69 <= 'F' ? 69 - 'A' + 10 : -1 ,
+    70 >= '0' && 70 <= '9' ? 70 - '0' : 70 >= 'a' && 70 <= 'f' ? 70 - 'a' + 10
+    : 70 >= 'A' && 70 <= 'F' ? 70 - 'A' + 10 : -1 ,
+    71 >= '0' && 71 <= '9' ? 71 - '0' : 71 >= 'a' && 71 <= 'f' ? 71 - 'a' + 10
+    : 71 >= 'A' && 71 <= 'F' ? 71 - 'A' + 10 : -1 ,
+    72 >= '0' && 72 <= '9' ? 72 - '0' : 72 >= 'a' && 72 <= 'f' ? 72 - 'a' + 10
+    : 72 >= 'A' && 72 <= 'F' ? 72 - 'A' + 10 : -1 ,
+    73 >= '0' && 73 <= '9' ? 73 - '0' : 73 >= 'a' && 73 <= 'f' ? 73 - 'a' + 10
+    : 73 >= 'A' && 73 <= 'F' ? 73 - 'A' + 10 : -1 ,
+    74 >= '0' && 74 <= '9' ? 74 - '0' : 74 >= 'a' && 74 <= 'f' ? 74 - 'a' + 10
+    : 74 >= 'A' && 74 <= 'F' ? 74 - 'A' + 10 : -1 ,
+    75 >= '0' && 75 <= '9' ? 75 - '0' : 75 >= 'a' && 75 <= 'f' ? 75 - 'a' + 10
+    : 75 >= 'A' && 75 <= 'F' ? 75 - 'A' + 10 : -1 ,
+    76 >= '0' && 76 <= '9' ? 76 - '0' : 76 >= 'a' && 76 <= 'f' ? 76 - 'a' + 10
+    : 76 >= 'A' && 76 <= 'F' ? 76 - 'A' + 10 : -1 ,
+    77 >= '0' && 77 <= '9' ? 77 - '0' : 77 >= 'a' && 77 <= 'f' ? 77 - 'a' + 10
+    : 77 >= 'A' && 77 <= 'F' ? 77 - 'A' + 10 : -1 ,
+    78 >= '0' && 78 <= '9' ? 78 - '0' : 78 >= 'a' && 78 <= 'f' ? 78 - 'a' + 10
+    : 78 >= 'A' && 78 <= 'F' ? 78 - 'A' + 10 : -1 ,
+    79 >= '0' && 79 <= '9' ? 79 - '0' : 79 >= 'a' && 79 <= 'f' ? 79 - 'a' + 10
+    : 79 >= 'A' && 79 <= 'F' ? 79 - 'A' + 10 : -1 ,
+    80 >= '0' && 80 <= '9' ? 80 - '0' : 80 >= 'a' && 80 <= 'f' ? 80 - 'a' + 10
+    : 80 >= 'A' && 80 <= 'F' ? 80 - 'A' + 10 : -1 ,
+    81 >= '0' && 81 <= '9' ? 81 - '0' : 81 >= 'a' && 81 <= 'f' ? 81 - 'a' + 10
+    : 81 >= 'A' && 81 <= 'F' ? 81 - 'A' + 10 : -1 ,
+    82 >= '0' && 82 <= '9' ? 82 - '0' : 82 >= 'a' && 82 <= 'f' ? 82 - 'a' + 10
+    : 82 >= 'A' && 82 <= 'F' ? 82 - 'A' + 10 : -1 ,
+    83 >= '0' && 83 <= '9' ? 83 - '0' : 83 >= 'a' && 83 <= 'f' ? 83 - 'a' + 10
+    : 83 >= 'A' && 83 <= 'F' ? 83 - 'A' + 10 : -1 ,
+    84 >= '0' && 84 <= '9' ? 84 - '0' : 84 >= 'a' && 84 <= 'f' ? 84 - 'a' + 10
+    : 84 >= 'A' && 84 <= 'F' ? 84 - 'A' + 10 : -1 ,
+    85 >= '0' && 85 <= '9' ? 85 - '0' : 85 >= 'a' && 85 <= 'f' ? 85 - 'a' + 10
+    : 85 >= 'A' && 85 <= 'F' ? 85 - 'A' + 10 : -1 ,
+    86 >= '0' && 86 <= '9' ? 86 - '0' : 86 >= 'a' && 86 <= 'f' ? 86 - 'a' + 10
+    : 86 >= 'A' && 86 <= 'F' ? 86 - 'A' + 10 : -1 ,
+    87 >= '0' && 87 <= '9' ? 87 - '0' : 87 >= 'a' && 87 <= 'f' ? 87 - 'a' + 10
+    : 87 >= 'A' && 87 <= 'F' ? 87 - 'A' + 10 : -1 ,
+    88 >= '0' && 88 <= '9' ? 88 - '0' : 88 >= 'a' && 88 <= 'f' ? 88 - 'a' + 10
+    : 88 >= 'A' && 88 <= 'F' ? 88 - 'A' + 10 : -1 ,
+    89 >= '0' && 89 <= '9' ? 89 - '0' : 89 >= 'a' && 89 <= 'f' ? 89 - 'a' + 10
+    : 89 >= 'A' && 89 <= 'F' ? 89 - 'A' + 10 : -1 ,
+    90 >= '0' && 90 <= '9' ? 90 - '0' : 90 >= 'a' && 90 <= 'f' ? 90 - 'a' + 10
+    : 90 >= 'A' && 90 <= 'F' ? 90 - 'A' + 10 : -1 ,
+    91 >= '0' && 91 <= '9' ? 91 - '0' : 91 >= 'a' && 91 <= 'f' ? 91 - 'a' + 10
+    : 91 >= 'A' && 91 <= 'F' ? 91 - 'A' + 10 : -1 ,
+    92 >= '0' && 92 <= '9' ? 92 - '0' : 92 >= 'a' && 92 <= 'f' ? 92 - 'a' + 10
+    : 92 >= 'A' && 92 <= 'F' ? 92 - 'A' + 10 : -1 ,
+    93 >= '0' && 93 <= '9' ? 93 - '0' : 93 >= 'a' && 93 <= 'f' ? 93 - 'a' + 10
+    : 93 >= 'A' && 93 <= 'F' ? 93 - 'A' + 10 : -1 ,
+    94 >= '0' && 94 <= '9' ? 94 - '0' : 94 >= 'a' && 94 <= 'f' ? 94 - 'a' + 10
+    : 94 >= 'A' && 94 <= 'F' ? 94 - 'A' + 10 : -1 ,
+    95 >= '0' && 95 <= '9' ? 95 - '0' : 95 >= 'a' && 95 <= 'f' ? 95 - 'a' + 10
+    : 95 >= 'A' && 95 <= 'F' ? 95 - 'A' + 10 : -1 ,
+    96 >= '0' && 96 <= '9' ? 96 - '0' : 96 >= 'a' && 96 <= 'f' ? 96 - 'a' + 10
+    : 96 >= 'A' && 96 <= 'F' ? 96 - 'A' + 10 : -1 ,
+    97 >= '0' && 97 <= '9' ? 97 - '0' : 97 >= 'a' && 97 <= 'f' ? 97 - 'a' + 10
+    : 97 >= 'A' && 97 <= 'F' ? 97 - 'A' + 10 : -1 ,
+    98 >= '0' && 98 <= '9' ? 98 - '0' : 98 >= 'a' && 98 <= 'f' ? 98 - 'a' + 10
+    : 98 >= 'A' && 98 <= 'F' ? 98 - 'A' + 10 : -1 ,
+    99 >= '0' && 99 <= '9' ? 99 - '0' : 99 >= 'a' && 99 <= 'f' ? 99 - 'a' + 10
+    : 99 >= 'A' && 99 <= 'F' ? 99 - 'A' + 10 : -1 ,
+    100 >= '0' && 100 <= '9' ? 100 - '0' : 100 >= 'a' && 100 <= 'f' ? 100 - 'a' + 10
+    : 100 >= 'A' && 100 <= 'F' ? 100 - 'A' + 10 : -1 ,
+    101 >= '0' && 101 <= '9' ? 101 - '0' : 101 >= 'a' && 101 <= 'f' ? 101 - 'a' + 10
+    : 101 >= 'A' && 101 <= 'F' ? 101 - 'A' + 10 : -1 ,
+    102 >= '0' && 102 <= '9' ? 102 - '0' : 102 >= 'a' && 102 <= 'f' ? 102 - 'a' + 10
+    : 102 >= 'A' && 102 <= 'F' ? 102 - 'A' + 10 : -1 ,
+    103 >= '0' && 103 <= '9' ? 103 - '0' : 103 >= 'a' && 103 <= 'f' ? 103 - 'a' + 10
+    : 103 >= 'A' && 103 <= 'F' ? 103 - 'A' + 10 : -1 ,
+    104 >= '0' && 104 <= '9' ? 104 - '0' : 104 >= 'a' && 104 <= 'f' ? 104 - 'a' + 10
+    : 104 >= 'A' && 104 <= 'F' ? 104 - 'A' + 10 : -1 ,
+    105 >= '0' && 105 <= '9' ? 105 - '0' : 105 >= 'a' && 105 <= 'f' ? 105 - 'a' + 10
+    : 105 >= 'A' && 105 <= 'F' ? 105 - 'A' + 10 : -1 ,
+    106 >= '0' && 106 <= '9' ? 106 - '0' : 106 >= 'a' && 106 <= 'f' ? 106 - 'a' + 10
+    : 106 >= 'A' && 106 <= 'F' ? 106 - 'A' + 10 : -1 ,
+    107 >= '0' && 107 <= '9' ? 107 - '0' : 107 >= 'a' && 107 <= 'f' ? 107 - 'a' + 10
+    : 107 >= 'A' && 107 <= 'F' ? 107 - 'A' + 10 : -1 ,
+    108 >= '0' && 108 <= '9' ? 108 - '0' : 108 >= 'a' && 108 <= 'f' ? 108 - 'a' + 10
+    : 108 >= 'A' && 108 <= 'F' ? 108 - 'A' + 10 : -1 ,
+    109 >= '0' && 109 <= '9' ? 109 - '0' : 109 >= 'a' && 109 <= 'f' ? 109 - 'a' + 10
+    : 109 >= 'A' && 109 <= 'F' ? 109 - 'A' + 10 : -1 ,
+    110 >= '0' && 110 <= '9' ? 110 - '0' : 110 >= 'a' && 110 <= 'f' ? 110 - 'a' + 10
+    : 110 >= 'A' && 110 <= 'F' ? 110 - 'A' + 10 : -1 ,
+    111 >= '0' && 111 <= '9' ? 111 - '0' : 111 >= 'a' && 111 <= 'f' ? 111 - 'a' + 10
+    : 111 >= 'A' && 111 <= 'F' ? 111 - 'A' + 10 : -1 ,
+    112 >= '0' && 112 <= '9' ? 112 - '0' : 112 >= 'a' && 112 <= 'f' ? 112 - 'a' + 10
+    : 112 >= 'A' && 112 <= 'F' ? 112 - 'A' + 10 : -1 ,
+    113 >= '0' && 113 <= '9' ? 113 - '0' : 113 >= 'a' && 113 <= 'f' ? 113 - 'a' + 10
+    : 113 >= 'A' && 113 <= 'F' ? 113 - 'A' + 10 : -1 ,
+    114 >= '0' && 114 <= '9' ? 114 - '0' : 114 >= 'a' && 114 <= 'f' ? 114 - 'a' + 10
+    : 114 >= 'A' && 114 <= 'F' ? 114 - 'A' + 10 : -1 ,
+    115 >= '0' && 115 <= '9' ? 115 - '0' : 115 >= 'a' && 115 <= 'f' ? 115 - 'a' + 10
+    : 115 >= 'A' && 115 <= 'F' ? 115 - 'A' + 10 : -1 ,
+    116 >= '0' && 116 <= '9' ? 116 - '0' : 116 >= 'a' && 116 <= 'f' ? 116 - 'a' + 10
+    : 116 >= 'A' && 116 <= 'F' ? 116 - 'A' + 10 : -1 ,
+    117 >= '0' && 117 <= '9' ? 117 - '0' : 117 >= 'a' && 117 <= 'f' ? 117 - 'a' + 10
+    : 117 >= 'A' && 117 <= 'F' ? 117 - 'A' + 10 : -1 ,
+    118 >= '0' && 118 <= '9' ? 118 - '0' : 118 >= 'a' && 118 <= 'f' ? 118 - 'a' + 10
+    : 118 >= 'A' && 118 <= 'F' ? 118 - 'A' + 10 : -1 ,
+    119 >= '0' && 119 <= '9' ? 119 - '0' : 119 >= 'a' && 119 <= 'f' ? 119 - 'a' + 10
+    : 119 >= 'A' && 119 <= 'F' ? 119 - 'A' + 10 : -1 ,
+    120 >= '0' && 120 <= '9' ? 120 - '0' : 120 >= 'a' && 120 <= 'f' ? 120 - 'a' + 10
+    : 120 >= 'A' && 120 <= 'F' ? 120 - 'A' + 10 : -1 ,
+    121 >= '0' && 121 <= '9' ? 121 - '0' : 121 >= 'a' && 121 <= 'f' ? 121 - 'a' + 10
+    : 121 >= 'A' && 121 <= 'F' ? 121 - 'A' + 10 : -1 ,
+    122 >= '0' && 122 <= '9' ? 122 - '0' : 122 >= 'a' && 122 <= 'f' ? 122 - 'a' + 10
+    : 122 >= 'A' && 122 <= 'F' ? 122 - 'A' + 10 : -1 ,
+    123 >= '0' && 123 <= '9' ? 123 - '0' : 123 >= 'a' && 123 <= 'f' ? 123 - 'a' + 10
+    : 123 >= 'A' && 123 <= 'F' ? 123 - 'A' + 10 : -1 ,
+    124 >= '0' && 124 <= '9' ? 124 - '0' : 124 >= 'a' && 124 <= 'f' ? 124 - 'a' + 10
+    : 124 >= 'A' && 124 <= 'F' ? 124 - 'A' + 10 : -1 ,
+    125 >= '0' && 125 <= '9' ? 125 - '0' : 125 >= 'a' && 125 <= 'f' ? 125 - 'a' + 10
+    : 125 >= 'A' && 125 <= 'F' ? 125 - 'A' + 10 : -1 ,
+    126 >= '0' && 126 <= '9' ? 126 - '0' : 126 >= 'a' && 126 <= 'f' ? 126 - 'a' + 10
+    : 126 >= 'A' && 126 <= 'F' ? 126 - 'A' + 10 : -1 ,
+    127 >= '0' && 127 <= '9' ? 127 - '0' : 127 >= 'a' && 127 <= 'f' ? 127 - 'a' + 10
+    : 127 >= 'A' && 127 <= 'F' ? 127 - 'A' + 10 : -1 ,
+    128 >= '0' && 128 <= '9' ? 128 - '0' : 128 >= 'a' && 128 <= 'f' ? 128 - 'a' + 10
+    : 128 >= 'A' && 128 <= 'F' ? 128 - 'A' + 10 : -1 ,
+    129 >= '0' && 129 <= '9' ? 129 - '0' : 129 >= 'a' && 129 <= 'f' ? 129 - 'a' + 10
+    : 129 >= 'A' && 129 <= 'F' ? 129 - 'A' + 10 : -1 ,
+    130 >= '0' && 130 <= '9' ? 130 - '0' : 130 >= 'a' && 130 <= 'f' ? 130 - 'a' + 10
+    : 130 >= 'A' && 130 <= 'F' ? 130 - 'A' + 10 : -1 ,
+    131 >= '0' && 131 <= '9' ? 131 - '0' : 131 >= 'a' && 131 <= 'f' ? 131 - 'a' + 10
+    : 131 >= 'A' && 131 <= 'F' ? 131 - 'A' + 10 : -1 ,
+    132 >= '0' && 132 <= '9' ? 132 - '0' : 132 >= 'a' && 132 <= 'f' ? 132 - 'a' + 10
+    : 132 >= 'A' && 132 <= 'F' ? 132 - 'A' + 10 : -1 ,
+    133 >= '0' && 133 <= '9' ? 133 - '0' : 133 >= 'a' && 133 <= 'f' ? 133 - 'a' + 10
+    : 133 >= 'A' && 133 <= 'F' ? 133 - 'A' + 10 : -1 ,
+    134 >= '0' && 134 <= '9' ? 134 - '0' : 134 >= 'a' && 134 <= 'f' ? 134 - 'a' + 10
+    : 134 >= 'A' && 134 <= 'F' ? 134 - 'A' + 10 : -1 ,
+    135 >= '0' && 135 <= '9' ? 135 - '0' : 135 >= 'a' && 135 <= 'f' ? 135 - 'a' + 10
+    : 135 >= 'A' && 135 <= 'F' ? 135 - 'A' + 10 : -1 ,
+    136 >= '0' && 136 <= '9' ? 136 - '0' : 136 >= 'a' && 136 <= 'f' ? 136 - 'a' + 10
+    : 136 >= 'A' && 136 <= 'F' ? 136 - 'A' + 10 : -1 ,
+    137 >= '0' && 137 <= '9' ? 137 - '0' : 137 >= 'a' && 137 <= 'f' ? 137 - 'a' + 10
+    : 137 >= 'A' && 137 <= 'F' ? 137 - 'A' + 10 : -1 ,
+    138 >= '0' && 138 <= '9' ? 138 - '0' : 138 >= 'a' && 138 <= 'f' ? 138 - 'a' + 10
+    : 138 >= 'A' && 138 <= 'F' ? 138 - 'A' + 10 : -1 ,
+    139 >= '0' && 139 <= '9' ? 139 - '0' : 139 >= 'a' && 139 <= 'f' ? 139 - 'a' + 10
+    : 139 >= 'A' && 139 <= 'F' ? 139 - 'A' + 10 : -1 ,
+    140 >= '0' && 140 <= '9' ? 140 - '0' : 140 >= 'a' && 140 <= 'f' ? 140 - 'a' + 10
+    : 140 >= 'A' && 140 <= 'F' ? 140 - 'A' + 10 : -1 ,
+    141 >= '0' && 141 <= '9' ? 141 - '0' : 141 >= 'a' && 141 <= 'f' ? 141 - 'a' + 10
+    : 141 >= 'A' && 141 <= 'F' ? 141 - 'A' + 10 : -1 ,
+    142 >= '0' && 142 <= '9' ? 142 - '0' : 142 >= 'a' && 142 <= 'f' ? 142 - 'a' + 10
+    : 142 >= 'A' && 142 <= 'F' ? 142 - 'A' + 10 : -1 ,
+    143 >= '0' && 143 <= '9' ? 143 - '0' : 143 >= 'a' && 143 <= 'f' ? 143 - 'a' + 10
+    : 143 >= 'A' && 143 <= 'F' ? 143 - 'A' + 10 : -1 ,
+    144 >= '0' && 144 <= '9' ? 144 - '0' : 144 >= 'a' && 144 <= 'f' ? 144 - 'a' + 10
+    : 144 >= 'A' && 144 <= 'F' ? 144 - 'A' + 10 : -1 ,
+    145 >= '0' && 145 <= '9' ? 145 - '0' : 145 >= 'a' && 145 <= 'f' ? 145 - 'a' + 10
+    : 145 >= 'A' && 145 <= 'F' ? 145 - 'A' + 10 : -1 ,
+    146 >= '0' && 146 <= '9' ? 146 - '0' : 146 >= 'a' && 146 <= 'f' ? 146 - 'a' + 10
+    : 146 >= 'A' && 146 <= 'F' ? 146 - 'A' + 10 : -1 ,
+    147 >= '0' && 147 <= '9' ? 147 - '0' : 147 >= 'a' && 147 <= 'f' ? 147 - 'a' + 10
+    : 147 >= 'A' && 147 <= 'F' ? 147 - 'A' + 10 : -1 ,
+    148 >= '0' && 148 <= '9' ? 148 - '0' : 148 >= 'a' && 148 <= 'f' ? 148 - 'a' + 10
+    : 148 >= 'A' && 148 <= 'F' ? 148 - 'A' + 10 : -1 ,
+    149 >= '0' && 149 <= '9' ? 149 - '0' : 149 >= 'a' && 149 <= 'f' ? 149 - 'a' + 10
+    : 149 >= 'A' && 149 <= 'F' ? 149 - 'A' + 10 : -1 ,
+    150 >= '0' && 150 <= '9' ? 150 - '0' : 150 >= 'a' && 150 <= 'f' ? 150 - 'a' + 10
+    : 150 >= 'A' && 150 <= 'F' ? 150 - 'A' + 10 : -1 ,
+    151 >= '0' && 151 <= '9' ? 151 - '0' : 151 >= 'a' && 151 <= 'f' ? 151 - 'a' + 10
+    : 151 >= 'A' && 151 <= 'F' ? 151 - 'A' + 10 : -1 ,
+    152 >= '0' && 152 <= '9' ? 152 - '0' : 152 >= 'a' && 152 <= 'f' ? 152 - 'a' + 10
+    : 152 >= 'A' && 152 <= 'F' ? 152 - 'A' + 10 : -1 ,
+    153 >= '0' && 153 <= '9' ? 153 - '0' : 153 >= 'a' && 153 <= 'f' ? 153 - 'a' + 10
+    : 153 >= 'A' && 153 <= 'F' ? 153 - 'A' + 10 : -1 ,
+    154 >= '0' && 154 <= '9' ? 154 - '0' : 154 >= 'a' && 154 <= 'f' ? 154 - 'a' + 10
+    : 154 >= 'A' && 154 <= 'F' ? 154 - 'A' + 10 : -1 ,
+    155 >= '0' && 155 <= '9' ? 155 - '0' : 155 >= 'a' && 155 <= 'f' ? 155 - 'a' + 10
+    : 155 >= 'A' && 155 <= 'F' ? 155 - 'A' + 10 : -1 ,
+    156 >= '0' && 156 <= '9' ? 156 - '0' : 156 >= 'a' && 156 <= 'f' ? 156 - 'a' + 10
+    : 156 >= 'A' && 156 <= 'F' ? 156 - 'A' + 10 : -1 ,
+    157 >= '0' && 157 <= '9' ? 157 - '0' : 157 >= 'a' && 157 <= 'f' ? 157 - 'a' + 10
+    : 157 >= 'A' && 157 <= 'F' ? 157 - 'A' + 10 : -1 ,
+    158 >= '0' && 158 <= '9' ? 158 - '0' : 158 >= 'a' && 158 <= 'f' ? 158 - 'a' + 10
+    : 158 >= 'A' && 158 <= 'F' ? 158 - 'A' + 10 : -1 ,
+    159 >= '0' && 159 <= '9' ? 159 - '0' : 159 >= 'a' && 159 <= 'f' ? 159 - 'a' + 10
+    : 159 >= 'A' && 159 <= 'F' ? 159 - 'A' + 10 : -1 ,
+    160 >= '0' && 160 <= '9' ? 160 - '0' : 160 >= 'a' && 160 <= 'f' ? 160 - 'a' + 10
+    : 160 >= 'A' && 160 <= 'F' ? 160 - 'A' + 10 : -1 ,
+    161 >= '0' && 161 <= '9' ? 161 - '0' : 161 >= 'a' && 161 <= 'f' ? 161 - 'a' + 10
+    : 161 >= 'A' && 161 <= 'F' ? 161 - 'A' + 10 : -1 ,
+    162 >= '0' && 162 <= '9' ? 162 - '0' : 162 >= 'a' && 162 <= 'f' ? 162 - 'a' + 10
+    : 162 >= 'A' && 162 <= 'F' ? 162 - 'A' + 10 : -1 ,
+    163 >= '0' && 163 <= '9' ? 163 - '0' : 163 >= 'a' && 163 <= 'f' ? 163 - 'a' + 10
+    : 163 >= 'A' && 163 <= 'F' ? 163 - 'A' + 10 : -1 ,
+    164 >= '0' && 164 <= '9' ? 164 - '0' : 164 >= 'a' && 164 <= 'f' ? 164 - 'a' + 10
+    : 164 >= 'A' && 164 <= 'F' ? 164 - 'A' + 10 : -1 ,
+    165 >= '0' && 165 <= '9' ? 165 - '0' : 165 >= 'a' && 165 <= 'f' ? 165 - 'a' + 10
+    : 165 >= 'A' && 165 <= 'F' ? 165 - 'A' + 10 : -1 ,
+    166 >= '0' && 166 <= '9' ? 166 - '0' : 166 >= 'a' && 166 <= 'f' ? 166 - 'a' + 10
+    : 166 >= 'A' && 166 <= 'F' ? 166 - 'A' + 10 : -1 ,
+    167 >= '0' && 167 <= '9' ? 167 - '0' : 167 >= 'a' && 167 <= 'f' ? 167 - 'a' + 10
+    : 167 >= 'A' && 167 <= 'F' ? 167 - 'A' + 10 : -1 ,
+    168 >= '0' && 168 <= '9' ? 168 - '0' : 168 >= 'a' && 168 <= 'f' ? 168 - 'a' + 10
+    : 168 >= 'A' && 168 <= 'F' ? 168 - 'A' + 10 : -1 ,
+    169 >= '0' && 169 <= '9' ? 169 - '0' : 169 >= 'a' && 169 <= 'f' ? 169 - 'a' + 10
+    : 169 >= 'A' && 169 <= 'F' ? 169 - 'A' + 10 : -1 ,
+    170 >= '0' && 170 <= '9' ? 170 - '0' : 170 >= 'a' && 170 <= 'f' ? 170 - 'a' + 10
+    : 170 >= 'A' && 170 <= 'F' ? 170 - 'A' + 10 : -1 ,
+    171 >= '0' && 171 <= '9' ? 171 - '0' : 171 >= 'a' && 171 <= 'f' ? 171 - 'a' + 10
+    : 171 >= 'A' && 171 <= 'F' ? 171 - 'A' + 10 : -1 ,
+    172 >= '0' && 172 <= '9' ? 172 - '0' : 172 >= 'a' && 172 <= 'f' ? 172 - 'a' + 10
+    : 172 >= 'A' && 172 <= 'F' ? 172 - 'A' + 10 : -1 ,
+    173 >= '0' && 173 <= '9' ? 173 - '0' : 173 >= 'a' && 173 <= 'f' ? 173 - 'a' + 10
+    : 173 >= 'A' && 173 <= 'F' ? 173 - 'A' + 10 : -1 ,
+    174 >= '0' && 174 <= '9' ? 174 - '0' : 174 >= 'a' && 174 <= 'f' ? 174 - 'a' + 10
+    : 174 >= 'A' && 174 <= 'F' ? 174 - 'A' + 10 : -1 ,
+    175 >= '0' && 175 <= '9' ? 175 - '0' : 175 >= 'a' && 175 <= 'f' ? 175 - 'a' + 10
+    : 175 >= 'A' && 175 <= 'F' ? 175 - 'A' + 10 : -1 ,
+    176 >= '0' && 176 <= '9' ? 176 - '0' : 176 >= 'a' && 176 <= 'f' ? 176 - 'a' + 10
+    : 176 >= 'A' && 176 <= 'F' ? 176 - 'A' + 10 : -1 ,
+    177 >= '0' && 177 <= '9' ? 177 - '0' : 177 >= 'a' && 177 <= 'f' ? 177 - 'a' + 10
+    : 177 >= 'A' && 177 <= 'F' ? 177 - 'A' + 10 : -1 ,
+    178 >= '0' && 178 <= '9' ? 178 - '0' : 178 >= 'a' && 178 <= 'f' ? 178 - 'a' + 10
+    : 178 >= 'A' && 178 <= 'F' ? 178 - 'A' + 10 : -1 ,
+    179 >= '0' && 179 <= '9' ? 179 - '0' : 179 >= 'a' && 179 <= 'f' ? 179 - 'a' + 10
+    : 179 >= 'A' && 179 <= 'F' ? 179 - 'A' + 10 : -1 ,
+    180 >= '0' && 180 <= '9' ? 180 - '0' : 180 >= 'a' && 180 <= 'f' ? 180 - 'a' + 10
+    : 180 >= 'A' && 180 <= 'F' ? 180 - 'A' + 10 : -1 ,
+    181 >= '0' && 181 <= '9' ? 181 - '0' : 181 >= 'a' && 181 <= 'f' ? 181 - 'a' + 10
+    : 181 >= 'A' && 181 <= 'F' ? 181 - 'A' + 10 : -1 ,
+    182 >= '0' && 182 <= '9' ? 182 - '0' : 182 >= 'a' && 182 <= 'f' ? 182 - 'a' + 10
+    : 182 >= 'A' && 182 <= 'F' ? 182 - 'A' + 10 : -1 ,
+    183 >= '0' && 183 <= '9' ? 183 - '0' : 183 >= 'a' && 183 <= 'f' ? 183 - 'a' + 10
+    : 183 >= 'A' && 183 <= 'F' ? 183 - 'A' + 10 : -1 ,
+    184 >= '0' && 184 <= '9' ? 184 - '0' : 184 >= 'a' && 184 <= 'f' ? 184 - 'a' + 10
+    : 184 >= 'A' && 184 <= 'F' ? 184 - 'A' + 10 : -1 ,
+    185 >= '0' && 185 <= '9' ? 185 - '0' : 185 >= 'a' && 185 <= 'f' ? 185 - 'a' + 10
+    : 185 >= 'A' && 185 <= 'F' ? 185 - 'A' + 10 : -1 ,
+    186 >= '0' && 186 <= '9' ? 186 - '0' : 186 >= 'a' && 186 <= 'f' ? 186 - 'a' + 10
+    : 186 >= 'A' && 186 <= 'F' ? 186 - 'A' + 10 : -1 ,
+    187 >= '0' && 187 <= '9' ? 187 - '0' : 187 >= 'a' && 187 <= 'f' ? 187 - 'a' + 10
+    : 187 >= 'A' && 187 <= 'F' ? 187 - 'A' + 10 : -1 ,
+    188 >= '0' && 188 <= '9' ? 188 - '0' : 188 >= 'a' && 188 <= 'f' ? 188 - 'a' + 10
+    : 188 >= 'A' && 188 <= 'F' ? 188 - 'A' + 10 : -1 ,
+    189 >= '0' && 189 <= '9' ? 189 - '0' : 189 >= 'a' && 189 <= 'f' ? 189 - 'a' + 10
+    : 189 >= 'A' && 189 <= 'F' ? 189 - 'A' + 10 : -1 ,
+    190 >= '0' && 190 <= '9' ? 190 - '0' : 190 >= 'a' && 190 <= 'f' ? 190 - 'a' + 10
+    : 190 >= 'A' && 190 <= 'F' ? 190 - 'A' + 10 : -1 ,
+    191 >= '0' && 191 <= '9' ? 191 - '0' : 191 >= 'a' && 191 <= 'f' ? 191 - 'a' + 10
+    : 191 >= 'A' && 191 <= 'F' ? 191 - 'A' + 10 : -1 ,
+    192 >= '0' && 192 <= '9' ? 192 - '0' : 192 >= 'a' && 192 <= 'f' ? 192 - 'a' + 10
+    : 192 >= 'A' && 192 <= 'F' ? 192 - 'A' + 10 : -1 ,
+    193 >= '0' && 193 <= '9' ? 193 - '0' : 193 >= 'a' && 193 <= 'f' ? 193 - 'a' + 10
+    : 193 >= 'A' && 193 <= 'F' ? 193 - 'A' + 10 : -1 ,
+    194 >= '0' && 194 <= '9' ? 194 - '0' : 194 >= 'a' && 194 <= 'f' ? 194 - 'a' + 10
+    : 194 >= 'A' && 194 <= 'F' ? 194 - 'A' + 10 : -1 ,
+    195 >= '0' && 195 <= '9' ? 195 - '0' : 195 >= 'a' && 195 <= 'f' ? 195 - 'a' + 10
+    : 195 >= 'A' && 195 <= 'F' ? 195 - 'A' + 10 : -1 ,
+    196 >= '0' && 196 <= '9' ? 196 - '0' : 196 >= 'a' && 196 <= 'f' ? 196 - 'a' + 10
+    : 196 >= 'A' && 196 <= 'F' ? 196 - 'A' + 10 : -1 ,
+    197 >= '0' && 197 <= '9' ? 197 - '0' : 197 >= 'a' && 197 <= 'f' ? 197 - 'a' + 10
+    : 197 >= 'A' && 197 <= 'F' ? 197 - 'A' + 10 : -1 ,
+    198 >= '0' && 198 <= '9' ? 198 - '0' : 198 >= 'a' && 198 <= 'f' ? 198 - 'a' + 10
+    : 198 >= 'A' && 198 <= 'F' ? 198 - 'A' + 10 : -1 ,
+    199 >= '0' && 199 <= '9' ? 199 - '0' : 199 >= 'a' && 199 <= 'f' ? 199 - 'a' + 10
+    : 199 >= 'A' && 199 <= 'F' ? 199 - 'A' + 10 : -1 ,
+    200 >= '0' && 200 <= '9' ? 200 - '0' : 200 >= 'a' && 200 <= 'f' ? 200 - 'a' + 10
+    : 200 >= 'A' && 200 <= 'F' ? 200 - 'A' + 10 : -1 ,
+    201 >= '0' && 201 <= '9' ? 201 - '0' : 201 >= 'a' && 201 <= 'f' ? 201 - 'a' + 10
+    : 201 >= 'A' && 201 <= 'F' ? 201 - 'A' + 10 : -1 ,
+    202 >= '0' && 202 <= '9' ? 202 - '0' : 202 >= 'a' && 202 <= 'f' ? 202 - 'a' + 10
+    : 202 >= 'A' && 202 <= 'F' ? 202 - 'A' + 10 : -1 ,
+    203 >= '0' && 203 <= '9' ? 203 - '0' : 203 >= 'a' && 203 <= 'f' ? 203 - 'a' + 10
+    : 203 >= 'A' && 203 <= 'F' ? 203 - 'A' + 10 : -1 ,
+    204 >= '0' && 204 <= '9' ? 204 - '0' : 204 >= 'a' && 204 <= 'f' ? 204 - 'a' + 10
+    : 204 >= 'A' && 204 <= 'F' ? 204 - 'A' + 10 : -1 ,
+    205 >= '0' && 205 <= '9' ? 205 - '0' : 205 >= 'a' && 205 <= 'f' ? 205 - 'a' + 10
+    : 205 >= 'A' && 205 <= 'F' ? 205 - 'A' + 10 : -1 ,
+    206 >= '0' && 206 <= '9' ? 206 - '0' : 206 >= 'a' && 206 <= 'f' ? 206 - 'a' + 10
+    : 206 >= 'A' && 206 <= 'F' ? 206 - 'A' + 10 : -1 ,
+    207 >= '0' && 207 <= '9' ? 207 - '0' : 207 >= 'a' && 207 <= 'f' ? 207 - 'a' + 10
+    : 207 >= 'A' && 207 <= 'F' ? 207 - 'A' + 10 : -1 ,
+    208 >= '0' && 208 <= '9' ? 208 - '0' : 208 >= 'a' && 208 <= 'f' ? 208 - 'a' + 10
+    : 208 >= 'A' && 208 <= 'F' ? 208 - 'A' + 10 : -1 ,
+    209 >= '0' && 209 <= '9' ? 209 - '0' : 209 >= 'a' && 209 <= 'f' ? 209 - 'a' + 10
+    : 209 >= 'A' && 209 <= 'F' ? 209 - 'A' + 10 : -1 ,
+    210 >= '0' && 210 <= '9' ? 210 - '0' : 210 >= 'a' && 210 <= 'f' ? 210 - 'a' + 10
+    : 210 >= 'A' && 210 <= 'F' ? 210 - 'A' + 10 : -1 ,
+    211 >= '0' && 211 <= '9' ? 211 - '0' : 211 >= 'a' && 211 <= 'f' ? 211 - 'a' + 10
+    : 211 >= 'A' && 211 <= 'F' ? 211 - 'A' + 10 : -1 ,
+    212 >= '0' && 212 <= '9' ? 212 - '0' : 212 >= 'a' && 212 <= 'f' ? 212 - 'a' + 10
+    : 212 >= 'A' && 212 <= 'F' ? 212 - 'A' + 10 : -1 ,
+    213 >= '0' && 213 <= '9' ? 213 - '0' : 213 >= 'a' && 213 <= 'f' ? 213 - 'a' + 10
+    : 213 >= 'A' && 213 <= 'F' ? 213 - 'A' + 10 : -1 ,
+    214 >= '0' && 214 <= '9' ? 214 - '0' : 214 >= 'a' && 214 <= 'f' ? 214 - 'a' + 10
+    : 214 >= 'A' && 214 <= 'F' ? 214 - 'A' + 10 : -1 ,
+    215 >= '0' && 215 <= '9' ? 215 - '0' : 215 >= 'a' && 215 <= 'f' ? 215 - 'a' + 10
+    : 215 >= 'A' && 215 <= 'F' ? 215 - 'A' + 10 : -1 ,
+    216 >= '0' && 216 <= '9' ? 216 - '0' : 216 >= 'a' && 216 <= 'f' ? 216 - 'a' + 10
+    : 216 >= 'A' && 216 <= 'F' ? 216 - 'A' + 10 : -1 ,
+    217 >= '0' && 217 <= '9' ? 217 - '0' : 217 >= 'a' && 217 <= 'f' ? 217 - 'a' + 10
+    : 217 >= 'A' && 217 <= 'F' ? 217 - 'A' + 10 : -1 ,
+    218 >= '0' && 218 <= '9' ? 218 - '0' : 218 >= 'a' && 218 <= 'f' ? 218 - 'a' + 10
+    : 218 >= 'A' && 218 <= 'F' ? 218 - 'A' + 10 : -1 ,
+    219 >= '0' && 219 <= '9' ? 219 - '0' : 219 >= 'a' && 219 <= 'f' ? 219 - 'a' + 10
+    : 219 >= 'A' && 219 <= 'F' ? 219 - 'A' + 10 : -1 ,
+    220 >= '0' && 220 <= '9' ? 220 - '0' : 220 >= 'a' && 220 <= 'f' ? 220 - 'a' + 10
+    : 220 >= 'A' && 220 <= 'F' ? 220 - 'A' + 10 : -1 ,
+    221 >= '0' && 221 <= '9' ? 221 - '0' : 221 >= 'a' && 221 <= 'f' ? 221 - 'a' + 10
+    : 221 >= 'A' && 221 <= 'F' ? 221 - 'A' + 10 : -1 ,
+    222 >= '0' && 222 <= '9' ? 222 - '0' : 222 >= 'a' && 222 <= 'f' ? 222 - 'a' + 10
+    : 222 >= 'A' && 222 <= 'F' ? 222 - 'A' + 10 : -1 ,
+    223 >= '0' && 223 <= '9' ? 223 - '0' : 223 >= 'a' && 223 <= 'f' ? 223 - 'a' + 10
+    : 223 >= 'A' && 223 <= 'F' ? 223 - 'A' + 10 : -1 ,
+    224 >= '0' && 224 <= '9' ? 224 - '0' : 224 >= 'a' && 224 <= 'f' ? 224 - 'a' + 10
+    : 224 >= 'A' && 224 <= 'F' ? 224 - 'A' + 10 : -1 ,
+    225 >= '0' && 225 <= '9' ? 225 - '0' : 225 >= 'a' && 225 <= 'f' ? 225 - 'a' + 10
+    : 225 >= 'A' && 225 <= 'F' ? 225 - 'A' + 10 : -1 ,
+    226 >= '0' && 226 <= '9' ? 226 - '0' : 226 >= 'a' && 226 <= 'f' ? 226 - 'a' + 10
+    : 226 >= 'A' && 226 <= 'F' ? 226 - 'A' + 10 : -1 ,
+    227 >= '0' && 227 <= '9' ? 227 - '0' : 227 >= 'a' && 227 <= 'f' ? 227 - 'a' + 10
+    : 227 >= 'A' && 227 <= 'F' ? 227 - 'A' + 10 : -1 ,
+    228 >= '0' && 228 <= '9' ? 228 - '0' : 228 >= 'a' && 228 <= 'f' ? 228 - 'a' + 10
+    : 228 >= 'A' && 228 <= 'F' ? 228 - 'A' + 10 : -1 ,
+    229 >= '0' && 229 <= '9' ? 229 - '0' : 229 >= 'a' && 229 <= 'f' ? 229 - 'a' + 10
+    : 229 >= 'A' && 229 <= 'F' ? 229 - 'A' + 10 : -1 ,
+    230 >= '0' && 230 <= '9' ? 230 - '0' : 230 >= 'a' && 230 <= 'f' ? 230 - 'a' + 10
+    : 230 >= 'A' && 230 <= 'F' ? 230 - 'A' + 10 : -1 ,
+    231 >= '0' && 231 <= '9' ? 231 - '0' : 231 >= 'a' && 231 <= 'f' ? 231 - 'a' + 10
+    : 231 >= 'A' && 231 <= 'F' ? 231 - 'A' + 10 : -1 ,
+    232 >= '0' && 232 <= '9' ? 232 - '0' : 232 >= 'a' && 232 <= 'f' ? 232 - 'a' + 10
+    : 232 >= 'A' && 232 <= 'F' ? 232 - 'A' + 10 : -1 ,
+    233 >= '0' && 233 <= '9' ? 233 - '0' : 233 >= 'a' && 233 <= 'f' ? 233 - 'a' + 10
+    : 233 >= 'A' && 233 <= 'F' ? 233 - 'A' + 10 : -1 ,
+    234 >= '0' && 234 <= '9' ? 234 - '0' : 234 >= 'a' && 234 <= 'f' ? 234 - 'a' + 10
+    : 234 >= 'A' && 234 <= 'F' ? 234 - 'A' + 10 : -1 ,
+    235 >= '0' && 235 <= '9' ? 235 - '0' : 235 >= 'a' && 235 <= 'f' ? 235 - 'a' + 10
+    : 235 >= 'A' && 235 <= 'F' ? 235 - 'A' + 10 : -1 ,
+    236 >= '0' && 236 <= '9' ? 236 - '0' : 236 >= 'a' && 236 <= 'f' ? 236 - 'a' + 10
+    : 236 >= 'A' && 236 <= 'F' ? 236 - 'A' + 10 : -1 ,
+    237 >= '0' && 237 <= '9' ? 237 - '0' : 237 >= 'a' && 237 <= 'f' ? 237 - 'a' + 10
+    : 237 >= 'A' && 237 <= 'F' ? 237 - 'A' + 10 : -1 ,
+    238 >= '0' && 238 <= '9' ? 238 - '0' : 238 >= 'a' && 238 <= 'f' ? 238 - 'a' + 10
+    : 238 >= 'A' && 238 <= 'F' ? 238 - 'A' + 10 : -1 ,
+    239 >= '0' && 239 <= '9' ? 239 - '0' : 239 >= 'a' && 239 <= 'f' ? 239 - 'a' + 10
+    : 239 >= 'A' && 239 <= 'F' ? 239 - 'A' + 10 : -1 ,
+    240 >= '0' && 240 <= '9' ? 240 - '0' : 240 >= 'a' && 240 <= 'f' ? 240 - 'a' + 10
+    : 240 >= 'A' && 240 <= 'F' ? 240 - 'A' + 10 : -1 ,
+    241 >= '0' && 241 <= '9' ? 241 - '0' : 241 >= 'a' && 241 <= 'f' ? 241 - 'a' + 10
+    : 241 >= 'A' && 241 <= 'F' ? 241 - 'A' + 10 : -1 ,
+    242 >= '0' && 242 <= '9' ? 242 - '0' : 242 >= 'a' && 242 <= 'f' ? 242 - 'a' + 10
+    : 242 >= 'A' && 242 <= 'F' ? 242 - 'A' + 10 : -1 ,
+    243 >= '0' && 243 <= '9' ? 243 - '0' : 243 >= 'a' && 243 <= 'f' ? 243 - 'a' + 10
+    : 243 >= 'A' && 243 <= 'F' ? 243 - 'A' + 10 : -1 ,
+    244 >= '0' && 244 <= '9' ? 244 - '0' : 244 >= 'a' && 244 <= 'f' ? 244 - 'a' + 10
+    : 244 >= 'A' && 244 <= 'F' ? 244 - 'A' + 10 : -1 ,
+    245 >= '0' && 245 <= '9' ? 245 - '0' : 245 >= 'a' && 245 <= 'f' ? 245 - 'a' + 10
+    : 245 >= 'A' && 245 <= 'F' ? 245 - 'A' + 10 : -1 ,
+    246 >= '0' && 246 <= '9' ? 246 - '0' : 246 >= 'a' && 246 <= 'f' ? 246 - 'a' + 10
+    : 246 >= 'A' && 246 <= 'F' ? 246 - 'A' + 10 : -1 ,
+    247 >= '0' && 247 <= '9' ? 247 - '0' : 247 >= 'a' && 247 <= 'f' ? 247 - 'a' + 10
+    : 247 >= 'A' && 247 <= 'F' ? 247 - 'A' + 10 : -1 ,
+    248 >= '0' && 248 <= '9' ? 248 - '0' : 248 >= 'a' && 248 <= 'f' ? 248 - 'a' + 10
+    : 248 >= 'A' && 248 <= 'F' ? 248 - 'A' + 10 : -1 ,
+    249 >= '0' && 249 <= '9' ? 249 - '0' : 249 >= 'a' && 249 <= 'f' ? 249 - 'a' + 10
+    : 249 >= 'A' && 249 <= 'F' ? 249 - 'A' + 10 : -1 ,
+    250 >= '0' && 250 <= '9' ? 250 - '0' : 250 >= 'a' && 250 <= 'f' ? 250 - 'a' + 10
+    : 250 >= 'A' && 250 <= 'F' ? 250 - 'A' + 10 : -1 ,
+    251 >= '0' && 251 <= '9' ? 251 - '0' : 251 >= 'a' && 251 <= 'f' ? 251 - 'a' + 10
+    : 251 >= 'A' && 251 <= 'F' ? 251 - 'A' + 10 : -1 ,
+    252 >= '0' && 252 <= '9' ? 252 - '0' : 252 >= 'a' && 252 <= 'f' ? 252 - 'a' + 10
+    : 252 >= 'A' && 252 <= 'F' ? 252 - 'A' + 10 : -1 ,
+    253 >= '0' && 253 <= '9' ? 253 - '0' : 253 >= 'a' && 253 <= 'f' ? 253 - 'a' + 10
+    : 253 >= 'A' && 253 <= 'F' ? 253 - 'A' + 10 : -1 ,
+    254 >= '0' && 254 <= '9' ? 254 - '0' : 254 >= 'a' && 254 <= 'f' ? 254 - 'a' + 10
+    : 254 >= 'A' && 254 <= 'F' ? 254 - 'A' + 10 : -1 ,
+    255 >= '0' && 255 <= '9' ? 255 - '0' : 255 >= 'a' && 255 <= 'f' ? 255 - 'a' + 10
+    : 255 >= 'A' && 255 <= 'F' ? 255 - 'A' + 10 : -1
+};
 
 static UV
 decode_4hex (dec_t *dec)
@@ -1105,7 +1646,7 @@ fail:
 }
 
 static SV *
-decode_str (dec_t *dec)
+decode_str (pTHX_ dec_t *dec)
 {
   SV *sv = 0;
   int utf8 = 0;
@@ -1229,7 +1770,7 @@ decode_str (dec_t *dec)
 
               --dec_cur;
 
-              decode_utf8 ((U8*)dec_cur, dec->end - dec_cur, &clen);
+              decode_utf8 (aTHX_ (U8*)dec_cur, dec->end - dec_cur, &clen);
               if (clen == (STRLEN)-1)
                 ERR ("malformed UTF-8 character in JSON string");
 
@@ -1292,7 +1833,7 @@ fail:
 }
 
 static SV *
-decode_num (dec_t *dec)
+decode_num (pTHX_ dec_t *dec)
 {
   int is_nv = 0;
   char *start = dec->cur;
@@ -1414,7 +1955,7 @@ fail:
 }
 
 static SV *
-decode_av (dec_t *dec)
+decode_av (pTHX_ dec_t *dec)
 {
   AV *av = newAV ();
 
@@ -1428,7 +1969,7 @@ decode_av (dec_t *dec)
       {
         SV *value;
 
-        value = decode_sv (dec);
+        value = decode_sv (aTHX_ dec);
         if (!value)
           goto fail;
 
@@ -1466,7 +2007,7 @@ fail:
 }
 
 static SV *
-decode_hv (dec_t *dec)
+decode_hv (pTHX_ dec_t *dec)
 {
   SV *sv;
   HV *hv = newHV ();
@@ -1497,14 +2038,14 @@ decode_hv (dec_t *dec)
               if (p == e || *p < 0x20 || *(U8*)p >= 0x80 || *p == '\\')
                 {
                   /* slow path, back up and use decode_str */
-                  SV *key = decode_str (dec);
+                  SV *key = decode_str (aTHX_ dec);
                   if (!key)
                     goto fail;
 
                   decode_ws (dec); EXPECT_CH (':');
 
                   decode_ws (dec);
-                  value = decode_sv (dec);
+                  value = decode_sv (aTHX_ dec);
                   if (!value)
                     {
                       SvREFCNT_dec (key);
@@ -1526,7 +2067,7 @@ decode_hv (dec_t *dec)
                   decode_ws (dec); EXPECT_CH (':');
 
                   decode_ws (dec);
-                  value = decode_sv (dec);
+                  value = decode_sv (aTHX_ dec);
                   if (!value)
                     goto fail;
 
@@ -1633,29 +2174,29 @@ fail:
 }
 
 static SV *
-decode_sv (dec_t *dec)
+decode_sv (pTHX_ dec_t *dec)
 {
   /* the beauty of JSON: you need exactly one character lookahead */
   /* to parse everything. */
   switch (*dec->cur)
     {
-      case '"': ++dec->cur; return decode_str (dec); 
-      case '[': ++dec->cur; return decode_av  (dec); 
-      case '{': ++dec->cur; return decode_hv  (dec);
+      case '"': ++dec->cur; return decode_str (aTHX_ dec);
+      case '[': ++dec->cur; return decode_av  (aTHX_ dec);
+      case '{': ++dec->cur; return decode_hv  (aTHX_ dec);
 
       case '-':
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
-        return decode_num (dec);
+        return decode_num (aTHX_ dec);
 
       case 't':
         if (dec->end - dec->cur >= 4 && !memcmp (dec->cur, "true", 4))
           {
             dec->cur += 4;
-#if JSON_SLOW
-            json_true = get_bool ("Cpanel::JSON::XS::true");
-#endif
-            return newSVsv (json_true);
+            {
+              dMY_CXT;
+              return newSVsv (MY_CXT.json_true);
+            }
           }
         else
           ERR ("'true' expected");
@@ -1666,10 +2207,10 @@ decode_sv (dec_t *dec)
         if (dec->end - dec->cur >= 5 && !memcmp (dec->cur, "false", 5))
           {
             dec->cur += 5;
-#if JSON_SLOW
-            json_false = get_bool ("Cpanel::JSON::XS::false");
-#endif
-            return newSVsv (json_false);
+            {
+              dMY_CXT;
+              return newSVsv (MY_CXT.json_false);
+            }
           }
         else
           ERR ("'false' expected");
@@ -1697,7 +2238,7 @@ fail:
 }
 
 static SV *
-decode_json (SV *string, JSON *json, U8 **offset_return)
+decode_json (pTHX_ SV *string, JSON *json, U8 **offset_return)
 {
   dec_t dec;
   SV *sv;
@@ -1756,7 +2297,7 @@ decode_json (SV *string, JSON *json, U8 **offset_return)
   *dec.end = 0; /* this should basically be a nop, too, but make sure it's there */
 
   decode_ws (&dec);
-  sv = decode_sv (&dec);
+  sv = decode_sv (aTHX_ &dec);
 
   if (offset_return)
     *offset_return = (U8*)dec.cur;
@@ -1790,7 +2331,7 @@ decode_json (SV *string, JSON *json, U8 **offset_return)
 #endif
       croak ("%s, at character offset %d (before \"%s\")",
              dec.err,
-             (int)ptr_to_index (string, (U8*)dec.cur),
+             (int)ptr_to_index (aTHX_ string, (U8*)dec.cur),
              dec.cur != dec.end ? SvPV_nolen (uni) : "(end of string)");
     }
 
@@ -1962,34 +2503,34 @@ MODULE = Cpanel::JSON::XS		PACKAGE = Cpanel::JSON::XS
 
 BOOT:
 {
-	int i;
-
-        for (i = 0; i < 256; ++i)
-          decode_hexdigit [i] =
-            i >= '0' && i <= '9' ? i - '0'
-            : i >= 'a' && i <= 'f' ? i - 'a' + 10
-            : i >= 'A' && i <= 'F' ? i - 'A' + 10
-            : -1;
-
-	json_stash         = gv_stashpv ("Cpanel::JSON::XS"         , 1);
-	json_boolean_stash = gv_stashpv ("Cpanel::JSON::XS::Boolean", 1);
-
-        json_true  = get_bool ("Cpanel::JSON::XS::true");
-        json_false = get_bool ("Cpanel::JSON::XS::false");
+        MY_CXT_INIT;
+        init_MY_CXT(aTHX_ &MY_CXT);
 
         CvNODEBUG_on (get_cv ("Cpanel::JSON::XS::incr_text", 0)); /* the debugger completely breaks lvalue subs */
 }
 
 PROTOTYPES: DISABLE
 
+
+#_if PERL_IMPLICIT_CONTEXT for embedding, but no ithreads, then CLONE is never
+# called
+
+#ifdef USE_ITHREADS
+
 void CLONE (...)
 	CODE:
-        json_stash         = 0;
-        json_boolean_stash = 0;
+{
+        MY_CXT_CLONE; /* possible declaration */
+        init_MY_CXT(aTHX_ &MY_CXT);
+        return; /* skip implicit PUTBACK, returning @_ to caller, more efficient*/
+}
+
+#endif
 
 void new (char *klass)
 	PPCODE:
 {
+        dMY_CXT;
   	SV *pv = NEWSV (0, sizeof (JSON));
         SvPOK_only (pv);
         json_init ((JSON *)SvPVX (pv));
@@ -2100,12 +2641,12 @@ void filter_json_single_key_object (JSON *self, SV *key, SV *cb = &PL_sv_undef)
 
 void encode (JSON *self, SV *scalar)
 	PPCODE:
-        PUTBACK; scalar = encode_json (scalar, self); SPAGAIN;
+        PUTBACK; scalar = encode_json (aTHX_ scalar, self); SPAGAIN;
         XPUSHs (scalar);
 
 void decode (JSON *self, SV *jsonstr)
 	PPCODE:
-        PUTBACK; jsonstr = decode_json (jsonstr, self, 0); SPAGAIN;
+        PUTBACK; jsonstr = decode_json (aTHX_ jsonstr, self, 0); SPAGAIN;
         XPUSHs (jsonstr);
 
 void decode_prefix (JSON *self, SV *jsonstr)
@@ -2113,10 +2654,10 @@ void decode_prefix (JSON *self, SV *jsonstr)
 {
 	SV *sv;
         U8 *offset;
-        PUTBACK; sv = decode_json (jsonstr, self, &offset); SPAGAIN;
+        PUTBACK; sv = decode_json (aTHX_ jsonstr, self, &offset); SPAGAIN;
         EXTEND (SP, 2);
         PUSHs (sv);
-        PUSHs (sv_2mortal (newSVuv (ptr_to_index (jsonstr, offset))));
+        PUSHs (sv_2mortal (newSVuv (ptr_to_index (aTHX_ jsonstr, offset))));
 }
 
 void incr_parse (JSON *self, SV *jsonstr = 0)
@@ -2198,7 +2739,7 @@ void incr_parse (JSON *self, SV *jsonstr = 0)
                     }
                 }
 
-              PUTBACK; sv = decode_json (self->incr_text, self, &offset); SPAGAIN;
+              PUTBACK; sv = decode_json (aTHX_ self->incr_text, self, &offset); SPAGAIN;
               XPUSHs (sv);
 
               self->incr_pos -= offset - (U8*)SvPVX (self->incr_text);
@@ -2281,7 +2822,7 @@ void encode_json (SV *scalar)
         JSON json;
         json_init (&json);
         json.flags |= ix;
-        PUTBACK; scalar = encode_json (scalar, &json); SPAGAIN;
+        PUTBACK; scalar = encode_json (aTHX_ scalar, &json); SPAGAIN;
         XPUSHs (scalar);
 }
 
@@ -2294,7 +2835,7 @@ void decode_json (SV *jsonstr)
         JSON json;
         json_init (&json);
         json.flags |= ix;
-        PUTBACK; jsonstr = decode_json (jsonstr, &json, 0); SPAGAIN;
+        PUTBACK; jsonstr = decode_json (aTHX_ jsonstr, &json, 0); SPAGAIN;
         XPUSHs (jsonstr);
 }
 
@@ -46,7 +46,7 @@ C<fromformat> can be one of:
 
 =item yaml - YAML (avoid at all costs, requires the YAML module :)
 
-=item string - do not attempt to decode te file data
+=item string - do not attempt to decode the file data
 
 =item none - nothing is read, creates an C<undef> scalar - mainly useful with C<-e>
 
@@ -0,0 +1,42 @@
+use Test::More;
+eval "use JSON::XS (); require JSON;";
+if ($@) {
+  plan skip_all => "JSON::XS and JSON required for testing interop";
+  exit 0;
+} else {
+  plan tests => 3;
+}
+
+use JSON (); # limitation: for interop with JSON load JSON before Cpanel::JSON::XS
+use Cpanel::JSON::XS ();
+
+my $boolstring = q({"is_true":true});
+my $js;
+{
+    require JSON::XS;
+    my $json = JSON::XS->new;
+    $js = $json->decode( $boolstring );
+    # bless { is_true => 1}, "JSON::PP::Boolean"
+}
+my $cjson = Cpanel::JSON::XS->new->allow_blessed;
+
+is($cjson->encode( $js ), $boolstring) or diag "\$JSON::XS::VERSION=$JSON::XS::VERSION";
+
+{
+    local $ENV{PERL_JSON_BACKEND} = 'JSON::PP';
+    my $json = JSON->new;
+    $js = $json->decode( $boolstring );
+    # bless { is_true => 1}, "JSON::PP::Boolean"
+}
+
+is($cjson->encode( $js ), $boolstring) or diag "\$JSON::VERSION=$JSON::VERSION";
+
+{
+    local $ENV{PERL_JSON_BACKEND} = 'JSON::XS';
+    my $json = JSON->new;
+    $js = $json->decode( $boolstring );
+    # bless { is_true => 1}, "JSON::PP::Boolean"
+}
+
+is($cjson->encode( $js ), $boolstring) or diag "\$JSON::VERSION=$JSON::VERSION";
+
@@ -3,6 +3,7 @@ JSON *		T_JSON
 INPUT
 
 T_JSON
+        dMY_CXT;
 	if (!(
            SvROK ($arg)
            && SvOBJECT (SvRV ($arg))