text:
"""
```
eqcond(m::JPT)
```
 Expresses the equilibrium conditions in canonical form using Γ0, Γ1, C, Ψ, and Π matrices.
Using the mappings of states/equations to integers defined in jpt.jl, coefficients are
specified in their proper positions.

Γ0 (n_states x n_states) holds coefficients of current time states.
Γ1 (n_states x n_states) holds coefficients of lagged states.
C  (n_states x 1) is a vector of constants
Ψ  (n_states x n_shocks_exogenous) holds coefficients of iid shocks.
Π  (n_states x n_states_expectational) holds coefficients of expectational states.
"""
function eqcond(m::JPT)
    endo = m.endogenous_states
    exo  = m.exogenous_shocks
    ex   = m.expected_shocks
    eq   = m.equilibrium_conditions

    Γ0 = zeros(n_states(m), n_states(m))
    Γ1 = zeros(n_states(m), n_states(m))
    C  = zeros(n_states(m))
    Ψ  = zeros(n_states(m), n_shocks_exogenous(m))
    Π  = zeros(n_states(m), n_shocks_expectational(m))

    ### ENDOGENOUS STATES ###

    ### 1. Production function

    # Sticky prices
    Γ0[eq[:eq_y], endo[:y_t]] = 1.
    Γ0[eq[:eq_y], endo[:k_t]] = -((m[:y_ss] + m[:F]) / m[:y_s]) * m[:α]
    Γ0[eq[:eq_y], endo[:L_t]] = -((m[:y_ss] + m[:F]) / m[:y_s]) * (1. - m[:α])

    # Flexible prices
    Γ0[eq[:eq_y_f], endo[:y_f_t]] = 1.
    Γ0[eq[:eq_y_f], endo[:k_f_t]] = -((m[:y_ss] + m[:F]) / m[:y_s]) * m[:α]
    Γ0[eq[:eq_y_f], endo[:L_f_t]] = -((m[:y_ss] + m[:F]) / m[:y_s]) * (1. - m[:α])

    ### 2. Cost minimization

    # Sticky prices
    Γ0[eq[:eq_L], endo[:Rk_t]] = 1.
    Γ0[eq[:eq_L], endo[:k_t]]  = 1.
    Γ0[eq[:eq_L], endo[:w_t]]  = -1.
    Γ0[eq[:eq_L], endo[:L_t]]  = -1.

    # Flexible prices
    Γ0[eq[:eq_L_f], endo[:Rk_f_t]] = 1.
    Γ0[eq[:eq_L_f], endo[:k_f_t]]  = 1.
    Γ0[eq[:eq_L_f], endo[:w_f_t]]  = -1.
    Γ0[eq[:eq_L_f], endo[:L_f_t]]  = -1.

    ### 3. Marginal cost

    # Sticky prices
    Γ0[eq[:eq_s], endo[:s_t]]  = 1.
    Γ0[eq[:eq_s], endo[:Rk_t]] = -m[:α]
    Γ0[eq[:eq_s], endo[:w_t]]  = -(1. - m[:α])

    # Flexible prices
    Γ0[eq[:eq_s_f], endo[:s_f_t]]  = 1.
    Γ0[eq[:eq_s_f], endo[:Rk_f_t]] = -m[:α]
    Γ0[eq[:eq_s_f], endo[:w_f_t]]  = -(1. - m[:α])

    ### 4. Phillips Curve

    # Sticky prices
    Γ0[eq[:eq_π], endo[:π_t]]   = 1.
    Γ0[eq[:eq_π], endo[:Eπ_t]]  = -m[:β] / (1 + m[:ι_p] * m[:β])
    Γ1[eq[:eq_π], endo[:π_t]]   = m[:ι_p] / (1 + m[:ι_p] * m[:β])
    Γ0[eq[:eq_π], endo[:s_t]]   = -(1. - m[:β] * m[:ξ_p]) * (1. - m[:ξ_p]) / ((1 + m[:ι_p] * m[:β]) * m[:ξ_p])
    Γ0[eq[:eq_π], endo[:λ_p_t]] = -1.

    # Flexible prices
    Γ0[eq[:eq_R_f], endo[:s_f_t]] = 1.

    ### 5. Consumption FOC

    # Sticky prices
    expγ = exp(m[:γ])
    Γ0[eq[:eq_c], endo[:λ_t]]  = (expγ - m[:h] * m[:β]) * (expγ - m[:h])
    Γ0[eq[:eq_c], endo[:b_t]]  = -(expγ - m[:h] * m[:β] * m[:ρ_b]) * (expγ - m[:h]) /
        ((1. - m[:ρ_b]) * (expγ - m[:h] * m[:β] * m[:ρ_b]) * (expγ - m[:h]) /
         (expγ * m[:h] + expγ ^ 2 + m[:β] * m[:h] ^ 2))
    Γ0[eq[:eq_c], endo[:z_t]]  = -(m[:β] * m[:h] * expγ * m[:rho_z] - m[:h] * expγ)
    Γ0[eq[:eq_c], endo[:c_t]]  = expγ ^ 2 + m[:β] * m[:h] ^ 2
    Γ0[eq[:eq_c], endo[:Ec_t]] = -m[:β] * m[:h] * expγ
    Γ1[eq[:eq_c], endo[:c_t]]  = m[:h] * expγ

    # Flexible prices
    expγ = exp(m[:γ])
    Γ0[eq[:eq_c_f], endo[:λ_f_t]]  = (expγ - m[:h] * m[:β]) * (expγ - m[:h])
    Γ0[eq[:eq_c_f], endo[:b_t]]  = -(expγ - m[:h] * m[:β] * m[:ρ_b]) * (expγ - m[:h]) /
        ((1. - m[:ρ_b]) * (expγ - m[:h] * m[:β] * m[:ρ_b]) * (expγ - m[:h]) /
         (expγ * m[:h] + expγ ^ 2 + m[:β] * m[:h] ^ 2))
    Γ0[eq[:eq_c_f], endo[:z_t]]  = -(m[:β] * m[:h] * expγ * m[:rho_z] - m[:h] * expγ)
    Γ0[eq[:eq_c_f], endo[:c_f_t]]  = expγ ^ 2 + m[:β] * m[:h] ^ 2
    Γ0[eq[:eq_c_f], endo[:Ec_f_t]] = -m[:β] * m[:h] * expγ
    Γ1[eq[:eq_c_f], endo[:c_f_t]]  = m[:h] * expγ

    ### 6. Euler equation

    # Sticky prices
    Γ0[eq[:eq_λ], endo[:λ_t]]  = 1.
    Γ0[eq[:eq_λ], endo[:R_t]]  = -1.
    Γ0[eq[:eq_λ], endo[:Eλ_t]] = -1.
    Γ0[eq[:eq_λ], endo[:Eπ_t]] = 1.
    Γ0[eq[:eq_λ], endo[:z_t]]  = m[:ρ_z]

    # Flexible prices
    Γ0[eq[:eq_λ_f], endo[:λ_f_t]]  = 1.
    Γ0[eq[:eq_λ_f], endo[:R_f_t]]  = -1.
    Γ0[eq[:eq_λ_f], endo[:Eλ_f_t]] = -1.
    Γ0[eq[:eq_λ_f], endo[:z_f_t]]  = m[:ρ_z]

    ### 7. Capital utilization FOC

    # Sticky prices
    Γ0[eq[:eq_Rk], endo[:Rk_t]] = 1.
    Γ0[eq[:eq_Rk], endo[:u_t]]  = -m[:χ]

    # Flexible prices

    return Γ0, Γ1, C, Ψ, Π
end

max_stars_repo_name: rsarfati/THANK

max_issues_repo_name: rsarfati/THANK

max_forks_repo_name: rsarfati/THANK


ext: jl

max_stars_repo_path: test/4 Trig functions/4.5 Secant/4.5.10 (c+d x)^m (a+b sec)^n.jl


text:
using PFKernels
using PFKernels.PowerSystem
using PFKernels.ForwardDiff

AT = PFKernels.AT

function identity(x)
    t1s{N} = ForwardDiff.Dual{Nothing,Float64, N} where N
    FT = t1s{2}
    V = Vector
    F = copy(x)
    adF = V{FT}(undef, length(F))
    adx = V{FT}(undef, length(x))
    ForwardDiff.seed!(adx, x, one(ForwardDiff.Partials{2,Float64}))
    dF = AT(adF)
    dx = AT(adx)
    PFKernels.kernel!(PFKernels.backend, dF, dx)
    function pvalues(x)
        return x.values
    end
    return Array(ForwardDiff.values.(dF)), Array(pvalues.(ForwardDiff.partials.(dF)))
end

# Inject GPU kernels
PFKernels.include(joinpath(dirname(@__FILE__), "kernels.jl"))

x = ones(10)
@show x
F, dF = identity(x)
# Value should be value of x = 1.0
@assert(F == ones(10))
# Partials of x will be set to 1.0, so dF should be 1.0 too. x is set to have 2 partials
@show dF
@assert(dF == [(1.0,1.0) for i in 1:10])


text:
export sass_make_file_compiler
export sass_make_data_compiler
export sass_compiler_parse
export sass_compiler_execute
export sass_delete_compiler

function sass_make_file_compiler(sass_context)
    ccall((:sass_make_file_compiler, libsass_so),
        Ptr{Cvoid}, (Ptr{Cvoid},), sass_context)
end

function sass_make_data_compiler(sass_context)
    ccall((:sass_make_data_compiler, libsass_so),
        Ptr{Cvoid}, (Ptr{Cvoid},), sass_context)
end

function sass_compiler_parse(compiler)
    ccall((:sass_compiler_parse, libsass_so),
        Cvoid, (Ptr{Cvoid},), compiler)
end

function sass_compiler_execute(compiler)
    ccall((:sass_compiler_execute, libsass_so),
        Cvoid, (Ptr{Cvoid},), compiler)
end

function sass_delete_compiler(compiler)
    ccall((:sass_delete_compiler, libsass_so),
        Cvoid, (Ptr{Cvoid},), compiler)
end


text:
using QuantumCumulants
using SymbolicUtils
using Test

@testset "nlevel" begin

# Symbolic levels
ha = NLevelSpace(:atom, (:g,:e))
@test ha.GS == :g

σ = Transition(ha, :σ, :g,:e)
@test σ' == Transition(ha, :σ, :e, :g)
σee = Transition(ha, :σ, :e,:e)
@test σee'==σee

@test σ'*σ == σee

ex = σ*σ'
@test isequal(simplify(σ*σ'), simplify(1 - σee))

sz = σ'*σ - σ*σ'
@test isequal(simplify(sz),simplify(2*σee - 1))

# Integer levels
ha = NLevelSpace(:atom, 2)
@test ha.GS == 1

@test_throws AssertionError Transition(ha, :σ, :g,:e)
σ = Transition(ha, :σ, 1, 2)
@test σ' == Transition(ha, :σ, 2,1)
σee = Transition(ha, :σ, :2,2)
@test σee'==σee

@test σ'*σ == σee

ex = σ*σ'
σgg = Transition(ha, :σ,1,1)
@test isequal(ex, σgg)

sz = σ'*σ - σ*σ'
@test isequal(simplify(sz),simplify(2*σee - one(σgg)))

# Product space
ha1 = NLevelSpace(:atom, (:g,:e))
ha2 = NLevelSpace(:atom, 2)
@test ha1 != ha2

hprod = ha1⊗ha2
σ1 = Transition(hprod,:σ,:g,:e,1)
σ2 = Transition(hprod,:σ,1,2,2)
@test σ1'*σ1==Transition(hprod,:σ,:e,:e,1)
@test isequal(simplify(σ2*σ2'), simplify(1 - Transition(hprod,:σ,2,2,2)))
@test isequal(simplify(σ1*σ2), σ1*σ2)

@test_throws ErrorException Transition(hprod,:σ,:g,:e)
@test Transition(hprod,:σ,:g,:e,1)==σ1
@test Transition(hprod,:σ,1,2,2)==σ2
@test_throws AssertionError Transition(hprod,:σ,1,2,1)

# Callable constructor
@test_throws ErrorException Transition(hprod,:σ)
s = Transition(hprod,:σ,1)
@test s isa QuantumCumulants.CallableTransition
@test s(:g,:e) == σ1
@test acts_on(Transition(ha2,:s))==1

end # testset


text:
# Parser tests
@test parse_line_auv("1.0 a b",1.0)==(0.5,1.5,"a","b")
@test parse_line_auv("0.0 b a",0.5)==(-0.25,0.25,"b","a")
@test parse_line_auv("6.0 node1 node2",2.0)==(5.0,7.0,"node1","node2")
@test parse_line_auv("0.0 b a")==(-0.5,0.5,"b","a")
@test parse_line_auv("1.0 a b")==parse_line_auv("1.0 a b",1.0)
@test parse_line_abuv("0.0 1.0 a b")==(0.0,1.0,"a","b")
@test parse_line_abuv("-0.5 0.5 c b")==(-0.5,0.5,"c","b")
@test parse_line_abuv("0.0 1.0 a b",2.0)==(0.0,1.0,"a","b")
@test parse_line("1.0 a b","auv")==(0.5,1.5,"a","b")
@test parse_line("1.0 a b","auv",1.0)==(0.5,1.5,"a","b")
@test parse_line("1.0 a b","auv",2.0)==(0.0,2.0,"a","b")
@test parse_line("0.0 1.0 a b","abuv")==(0.0,1.0,"a","b")
@test parse_line("0.0 1.0 a b","abuv",2.0)==(0.0,1.0,"a","b")

events=parse_to_events("./test_data/auv_test_1.txt","auv",0.05)
@test length(events)==8
@test events[1]==LinkEvent(-0.025,true,("a","b"))
@test string(events[1])=="-0.025 + a b"
@test events[2]==LinkEvent(0.025,false,("a","b"))
@test string(events[2])=="0.025 - a b"
@test events[3]==LinkEvent(0.475,true,("a","c"))
@test string(events[3])=="0.475 + a c"
@test events[4]==LinkEvent(0.525,false,("a","c"))
@test string(events[4])=="0.525 - a c"
@test events[5]==LinkEvent(0.575,true,("a","c"))
@test events[6]==LinkEvent(0.625,false,("a","c"))
@test events[7]==LinkEvent(0.975,true,("a","b"))
@test events[8]==LinkEvent(1.025,false,("a","b"))
tc=TimeCursor(State(0.0,0.0,Set(),Set()),Dict{Float64,Transition}())
load!(tc,events)
next!(tc)
@test tc.S.t0==-0.025
@test tc.S.t1==0.025
@test links(tc)==Set([("a","b")])

events=parse_to_events("./test_data/auv_test_1.txt","auv",0.1)
@test length(events)==6
@test events[1]==LinkEvent(-0.05,true,("a","b"))
@test events[2]==LinkEvent(0.05,false,("a","b"))
@test events[3]==LinkEvent(0.45,true,("a","c"))
@test events[4]==LinkEvent(0.65,false,("a","c"))
@test events[5]==LinkEvent(0.95,true,("a","b"))
@test events[6]==LinkEvent(1.05,false,("a","b"))

events=parse_to_events("./test_data/auv_test_1.txt","auv",1.0)
@test length(events)==4
@test events[1]==LinkEvent(-0.5,true,("a","b"))
@test events[2]==LinkEvent(0.0,true,("a","c"))
@test events[3]==LinkEvent(1.1,false,("a","c"))
@test events[4]==LinkEvent(1.5,false,("a","b"))


text:
using Test

include(joinpath(@__DIR__, "../src/wkb.jl"))

pt2d = (type="Point", coordinates=[0.0, 1.0])
pt2d_wkb = WKB("\x01"*  # little endian
               "\x01\x00\x00\x00"*  # type
               "\x00\x00\x00\x00\x00\x00\x00\x00"*
               "\x00\x00\x00\x00\x00\x00\xf0?")
ptz = (type="Point", coordinates=[0.0, 1.0, 2.0])
ptz_wkb = WKB( "\x00"*  # big endian
               "\x00\x00\x03\xe9"*  # type
               "\x00\x00\x00\x00\x00\x00\x00\x00"*
               "?\xf0\x00\x00\x00\x00\x00\x00"*
               "@\x00\x00\x00\x00\x00\x00\x00")
ptm_wkb = WKB("\x00"*  # big endian
              "\x00\x00\x07\xd1"*  # type
              "\x00\x00\x00\x00\x00\x00\x00\x00"*
              "?\xf0\x00\x00\x00\x00\x00\x00"*
              "@\x00\x00\x00\x00\x00\x00\x00")
ptzm = (type="Point", coordinates=[0.0, 1.0, 2.0, 4.0])
ptzm_wkb = WKB("\x01"*  # little endian
               "\xb9\x0b\x00\x00"*  # type
               "\x00\x00\x00\x00\x00\x00\x00\x00"*
               "\x00\x00\x00\x00\x00\x00\xf0?"*
               "\x00\x00\x00\x00\x00\x00\x00@"*
               "\x00\x00\x00\x00\x00\x00\x10@")
pt2d_srid4326 = (type="Point", coordinates=[0.0, 1.0],
                 meta=(srid=4326,),
                 crs=(type="name", properties=(name="EPSG4326",)))
pt2d_srid4326_wkb = WKB("\x01"*  # little endian
                        "\x01\x00\x00\x20"*  # type, with SRID flag set (0x20)
                        "\xe6\x10\x00\x00"*  # SRID=4326
                        "\x00\x00\x00\x00\x00\x00\x00\x00"*
                        "\x00\x00\x00\x00\x00\x00\xf0?")

@testset "Point" begin
    @test read(pt2d_wkb) == pt2d
    @test read(ptz_wkb) == ptz
    @test read(ptm_wkb) == ptz
    @test read(ptzm_wkb) == ptzm
    @test read(pt2d_srid4326_wkb) == pt2d_srid4326
end

ls2d = (type="LineString", coordinates=[[2.2, 4.4], [3.1, 5.1]])
ls2d_wkb = WKB("\x00"*  # big endian
               "\x00\x00\x00\x02"*  # type
               "\x00\x00\x00\x02"*  # 2 vertices
               "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
               "@\x11\x99\x99\x99\x99\x99\x9a"*  # 4.4
               "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
               "@\x14ffffff") # 5.1
lsz = (type="LineString", coordinates=[[2.2, 4.4, 10.0],[3.1, 5.1, 20.0]])
lsz_wkb = WKB("\x01"*  # little endian
              "\xea\x03\x00\x00"*  # type
              "\x02\x00\x00\x00"*  # 2 vertices
              "\x9a\x99\x99\x99\x99\x99\x01@"*  # 2.2
              "\x9a\x99\x99\x99\x99\x99\x11@"*  # 4.4
              "\x00\x00\x00\x00\x00\x00\$@"*     # 10.0
              "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*  # 3.1
              "ffffff\x14@"*                   # 5.1
              "\x00\x00\x00\x00\x00\x004@")     # 20.0
lsm_wkb = WKB("\x01"*  # little endian
              "\xd2\x07\x00\x00"*  # type
              "\x02\x00\x00\x00"*  # 2 vertices
              "\x9a\x99\x99\x99\x99\x99\x01@"*  # 2.2
              "\x9a\x99\x99\x99\x99\x99\x11@"*  # 4.4
              "\x00\x00\x00\x00\x00\x00\$@"*     # 10.0
              "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*  # 3.1
              "ffffff\x14@"*                   # 5.1
              "\x00\x00\x00\x00\x00\x004@")     # 20.0
lszm = (type="LineString", coordinates=[[2.2, -4.4, -10.0, 0.1],
                                        [-3.1, 5.1, 20.0, -0.9]])
lszm_wkb = WKB("\x00"*  # big endian
               "\x00\x00\x0b\xba"*  # type
               "\x00\x00\x00\x02"*  # 2 vertices
               "@\x01\x99\x99\x99\x99\x99\x9a"*     # 2.2
               "\xc0\x11\x99\x99\x99\x99\x99\x9a"*  # -4.4
               "\xc0\$\x00\x00\x00\x00\x00\x00"*     # -10.0
               "?\xb9\x99\x99\x99\x99\x99\x9a"*     # 0.1
               "\xc0\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # -3.1
               "@\x14ffffff"*                       # 5.1
               "@4\x00\x00\x00\x00\x00\x00"*        # 20.0
               "\xbf\xec\xcc\xcc\xcc\xcc\xcc\xcd")  # -0.9
ls2d_srid1234 = (type="LineString",
                 coordinates=[[2.2, 4.4], [3.1, 5.1]],
                 meta=(srid=1234,),
                 crs=(type="name", properties=(name="EPSG1234",)))
ls2d_srid1234_wkb = WKB("\x00"*  # big endian
                        "\x20\x00\x00\x02"*  # type with SRID flag set
                        "\x00\x00\x04\xd2"*  # srid
                        "\x00\x00\x00\x02"*  # 2 vertices
                        "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
                        "@\x11\x99\x99\x99\x99\x99\x9a"*  # 4.4
                        "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
                        "@\x14ffffff")                    # 5.1

@testset "LineString" begin
    @test read(ls2d_wkb) == ls2d
    @test read(lsz_wkb) == lsz
    @test read(lsm_wkb) == lsz
    @test read(lszm_wkb) == lszm
    @test read(ls2d_srid1234_wkb) == ls2d_srid1234
end

pg2d = (type="Polygon", coordinates=[
    [[100.001, 0.001], [101.12345, 0.001], [101.001, 1.001], [100.001, 0.001]],
    [[100.201, 0.201], [100.801, 0.201], [100.801, 0.801], [100.201, 0.201]]
])
pg2d_wkb = WKB( "\x00"*
                "\x00\x00\x00\x03"*  # type
                    # number of rings, 4 byte int
                "\x00\x00\x00\x02"*
                    # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                    # coords
                "@Y\x00\x10bM\xd2\xf2"*     # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*     # 0.001
                "@YG\xe6\x9a\xd4,="*        # 101.12345
                "?PbM\xd2\xf1\xa9\xfc"*     # 0.001
                "@Y@\x10bM\xd2\xf2"*        # 101.001
                "?\xf0\x04\x18\x93t\xbcj"*  # 1.001
                "@Y\x00\x10bM\xd2\xf2"*     # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*     # 0.001
                    # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                    # coords
                "@Y\x0c\xdd/\x1a\x9f\xbe"*     # 100.201
                "?\xc9\xba^5?|\xee"*           # 0.201
                "@Y3C\x95\x81\x06%"*           # 100.801
                "?\xc9\xba^5?|\xee"*           # 0.201
                "@Y3C\x95\x81\x06%"*           # 100.801
                "?\xe9\xa1\xca\xc0\x83\x12o"*  # 0.801
                "@Y\x0c\xdd/\x1a\x9f\xbe"*     # 100.201
                "?\xc9\xba^5?|\xee") # 0.201
pgz = (type="Polygon", coordinates=[
    [[100.001, 0.001, 0.0], [101.12345, 0.001, 1.0], [101.001, 1.001, 2.0], [100.001, 0.001, 0.0]],
    [[100.201, 0.201, 0.0], [100.801, 0.201, 1.0], [100.801, 0.801, 2.0], [100.201, 0.201, 0.0]]
])
pgz_wkb = WKB(  "\x00"*
                "\x00\x00\x03\xeb"*  # type
                # number of rings, 4 byte int
                "\x00\x00\x00\x02"*
                # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                # coords
                "@Y\x00\x10bM\xd2\xf2"*              # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@YG\xe6\x9a\xd4,="*                 # 101.12345
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "@Y@\x10bM\xd2\xf2"*                 # 101.001
                "?\xf0\x04\x18\x93t\xbcj"*           # 1.001
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "@Y\x00\x10bM\xd2\xf2"*              # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                # coords
                "@Y\x0c\xdd/\x1a\x9f\xbe"*           # 100.201
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@Y3C\x95\x81\x06%"*                 # 100.801
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "@Y3C\x95\x81\x06%"*                 # 100.801
                "?\xe9\xa1\xca\xc0\x83\x12o"*        # 0.801
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "@Y\x0c\xdd/\x1a\x9f\xbe"*           # 100.201
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "\x00\x00\x00\x00\x00\x00\x00\x00")  # 0.0
pgm_wkb = WKB(  "\x00"*
                "\x00\x00\x07\xd3"*  # type
                # number of rings, 4 byte int
                "\x00\x00\x00\x02"*
                # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                # coords
                "@Y\x00\x10bM\xd2\xf2"*              # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@YG\xe6\x9a\xd4,="*                 # 101.12345
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "@Y@\x10bM\xd2\xf2"*                 # 101.001
                "?\xf0\x04\x18\x93t\xbcj"*           # 1.001
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "@Y\x00\x10bM\xd2\xf2"*              # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                # coords
                "@Y\x0c\xdd/\x1a\x9f\xbe"*           # 100.201
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@Y3C\x95\x81\x06%"*                 # 100.801
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "@Y3C\x95\x81\x06%"*                 # 100.801
                "?\xe9\xa1\xca\xc0\x83\x12o"*        # 0.801
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "@Y\x0c\xdd/\x1a\x9f\xbe"*           # 100.201
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "\x00\x00\x00\x00\x00\x00\x00\x00")  # 0.0
pgzm = (type="Polygon", coordinates=[
    [[100.001, 0.001, 0.0, 0.0], [101.12345, 0.001, 1.0, 1.0], [101.001, 1.001, 2.0, 2.0], [100.001, 0.001, 0.0, 0.0]],
    [[100.201, 0.201, 0.0, 0.0], [100.801, 0.201, 1.0, 0.0], [100.801, 0.801, 2.0, 1.0], [100.201, 0.201, 0.0, 0.0]],
])
pgzm_wkb = WKB( "\x00"*
                "\x00\x00\x0b\xbb"*  # type
                # number of rings, 4 byte int
                "\x00\x00\x00\x02"*
                # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                # coords
                "@Y\x00\x10bM\xd2\xf2"*              # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@YG\xe6\x9a\xd4,="*                 # 101.12345
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "@Y@\x10bM\xd2\xf2"*                 # 101.001
                "?\xf0\x04\x18\x93t\xbcj"*           # 1.001
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "@Y\x00\x10bM\xd2\xf2"*              # 100.001
                "?PbM\xd2\xf1\xa9\xfc"*              # 0.001
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                # number of verts in ring (4)
                "\x00\x00\x00\x04"*
                # coords
                "@Y\x0c\xdd/\x1a\x9f\xbe"*           # 100.201
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@Y3C\x95\x81\x06%"*                 # 100.801
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "@Y3C\x95\x81\x06%"*                 # 100.801
                "?\xe9\xa1\xca\xc0\x83\x12o"*        # 0.801
                "@\x00\x00\x00\x00\x00\x00\x00"*     # 2.0
                "?\xf0\x00\x00\x00\x00\x00\x00"*     # 1.0
                "@Y\x0c\xdd/\x1a\x9f\xbe"*           # 100.201
                "?\xc9\xba^5?|\xee"*                 # 0.201
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "\x00\x00\x00\x00\x00\x00\x00\x00")  # 0.0
pg2d_srid26918 = (type="Polygon", coordinates=[
        [[100.001, 0.001], [101.12345, 0.001], [101.001, 1.001],
         [100.001, 0.001]],
        [[100.201, 0.201], [100.801, 0.201], [100.801, 0.801],
         [100.201, 0.201]]
    ],
    meta=(srid=26918,),
    crs=(type="name", properties=(name="EPSG26918",)))
pg2d_srid26918_wkb = WKB(   "\x00"*  # big endian
                            "\x20\x00\x00\x03"*  # type, with SRID flag set (0x20)
                            "\x00\x00\x69\x26"*  # 4 bytes containing SRID (SRID=26918)
                            # number of rings, 4 byte int
                            "\x00\x00\x00\x02"*
                            # number of verts in ring (4)
                            "\x00\x00\x00\x04"*
                            # coords
                            "@Y\x00\x10bM\xd2\xf2"*     # 100.001
                            "?PbM\xd2\xf1\xa9\xfc"*     # 0.001
                            "@YG\xe6\x9a\xd4,="*        # 101.12345
                            "?PbM\xd2\xf1\xa9\xfc"*     # 0.001
                            "@Y@\x10bM\xd2\xf2"*        # 101.001
                            "?\xf0\x04\x18\x93t\xbcj"*  # 1.001
                            "@Y\x00\x10bM\xd2\xf2"*     # 100.001
                            "?PbM\xd2\xf1\xa9\xfc"*     # 0.001
                            # number of verts in ring (4)
                            "\x00\x00\x00\x04"*
                            # coords
                            "@Y\x0c\xdd/\x1a\x9f\xbe"*     # 100.201
                            "?\xc9\xba^5?|\xee"*           # 0.201
                            "@Y3C\x95\x81\x06%"*           # 100.801
                            "?\xc9\xba^5?|\xee"*           # 0.201
                            "@Y3C\x95\x81\x06%"*           # 100.801
                            "?\xe9\xa1\xca\xc0\x83\x12o"*  # 0.801
                            "@Y\x0c\xdd/\x1a\x9f\xbe"*     # 100.201
                            "?\xc9\xba^5?|\xee")           # 0.201

@testset "Polygon" begin
    @test read(pg2d_wkb) == pg2d
    @test read(pgz_wkb) == pgz
    @test read(pgm_wkb) == pgz
    @test read(pgzm_wkb) == pgzm
    @test read(pg2d_srid26918_wkb) == pg2d_srid26918
end

mpt2d = (type="MultiPoint", coordinates=[[2.2, 4.4], [10.0, 3.1], [5.1, 20.0]])
        (type = "MultiPoint", coordinates =[(type = "Point", coordinates = [2.2, 4.4]), (type = "Point", coordinates = [10.0, 3.1]), (type
= "Point", coordinates = [5.1, 20.0])]) == (type = "MultiPoint", coordinates = Array{Float64,1}[[2.2, 4.4], [10.0, 3.1], [5.1, 20.0]])
mpt2d_wkb = WKB("\x01"*  # little endian
                "\x04\x00\x00\x00"*
                # number of points: 3
                "\x03\x00\x00\x00"*
                # point 2d
                "\x01"*  # little endian
                "\x01\x00\x00\x00"*
                "\x9a\x99\x99\x99\x99\x99\x01@"*  # 2.2
                "\x9a\x99\x99\x99\x99\x99\x11@"*  # 4.4
                # point 2d
                "\x01"*  # little endian
                "\x01\x00\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\$@"*     # 10.0
                "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*  # 3.1
                # point 2d
                "\x01"*  # little endian
                "\x01\x00\x00\x00"*
                "ffffff\x14@"*                    # 5.1
                "\x00\x00\x00\x00\x00\x004@")     # 20.0
mptz = (type="MultiPoint",
        coordinates=[[2.2, 4.4, 3.0], [10.0, 3.1, 2.0], [5.1, 20.0, 4.4]])
mptz_wkb = WKB( "\x01"*  # little endian
                "\xec\x03\x00\x00"*
                # number of points: 3
                "\x03\x00\x00\x00"*
                # point 3d
                "\x01"*  # little endian
                "\xe9\x03\x00\x00"*
                "\x9a\x99\x99\x99\x99\x99\x01@"*  # 2.2
                "\x9a\x99\x99\x99\x99\x99\x11@"*  # 4.4
                "\x00\x00\x00\x00\x00\x00\x08@"*  # 3.0
                # point 3d
                "\x01"*  # little endian
                "\xe9\x03\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\$@"*     # 10.0
                "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*  # 3.1
                "\x00\x00\x00\x00\x00\x00\x00@"*  # 2.0
                # point 3d
                "\x01"*  # little endian
                "\xe9\x03\x00\x00"*
                "ffffff\x14@"*                    # 5.1
                "\x00\x00\x00\x00\x00\x004@"*     # 20.0
                "\x9a\x99\x99\x99\x99\x99\x11@")  # 4.4
mptm_wkb = WKB( "\x01"*  # little endian
                "\xd4\x07\x00\x00"*
                # number of points: 3
                "\x03\x00\x00\x00"*
                # point m
                "\x01"*  # little endian
                "\xe9\x03\x00\x00"*
                "\x9a\x99\x99\x99\x99\x99\x01@"*  # 2.2
                "\x9a\x99\x99\x99\x99\x99\x11@"*  # 4.4
                "\x00\x00\x00\x00\x00\x00\x08@"*  # 3.0
                # point m
                "\x01"*  # little endian
                "\xe9\x03\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\$@"*     # 10.0
                "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*  # 3.1
                "\x00\x00\x00\x00\x00\x00\x00@"*  # 2.0
                # point m
                "\x01"*  # little endian
                "\xe9\x03\x00\x00"*
                "ffffff\x14@"*                    # 5.1
                "\x00\x00\x00\x00\x00\x004@"*     # 20.0
                "\x9a\x99\x99\x99\x99\x99\x11@")  # 4.4
mptzm = (type="MultiPoint",
        coordinates=[[2.2, 4.4, 0.0, 3.0], [10.0, 3.1, 0.0, 2.0], [5.1, 20.0, 0.0, 4.4]])
mptzm_wkb = WKB("\x01"*  # little endian
            "\xbc\x0b\x00\x00"*
            # number of points: 3
            "\x03\x00\x00\x00"*
            # point 4d
            "\x01"*  # little endian
            "\xb9\x0b\x00\x00"*
            "\x9a\x99\x99\x99\x99\x99\x01@"*     # 2.2
            "\x9a\x99\x99\x99\x99\x99\x11@"*     # 4.4
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "\x00\x00\x00\x00\x00\x00\x08@"*     # 3.0
            # point 4d
            "\x01"*  # little endian
            "\xb9\x0b\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\$@"*        # 10.0
            "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*     # 3.1
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "\x00\x00\x00\x00\x00\x00\x00@"*     # 2.0
            # point 4d
            "\x01"*  # little endian
            "\xb9\x0b\x00\x00"*
            "ffffff\x14@"*                       # 5.1
            "\x00\x00\x00\x00\x00\x004@"*        # 20.0
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "\x9a\x99\x99\x99\x99\x99\x11@")     # 4.4
mpt2d_srid664 = (type="MultiPoint",
                coordinates=[[2.2, 4.4], [10.0, 3.1], [5.1, 20.0]],
                meta=(srid=664,),
                crs=(type="name", properties=(name="EPSG664",)))
mpt2d_srid664_wkb = WKB(
            "\x01"*  # little endian
            "\x04\x00\x00\x20"*  # type with SRID flag set
            "\x98\x02\x00\x00"*  # SRID 664
            # number of points: 3
            "\x03\x00\x00\x00"*
            # point 2d
            "\x01"*  # little endian
            "\x01\x00\x00\x00"*
            "\x9a\x99\x99\x99\x99\x99\x01@"*  # 2.2
            "\x9a\x99\x99\x99\x99\x99\x11@"*  # 4.4
            # point 2d
            "\x01"*  # little endian
            "\x01\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\$@"*     # 10.0
            "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*  # 3.1
            # point 2d
            "\x01"*  # little endian
            "\x01\x00\x00\x00"*
            "ffffff\x14@"*                    # 5.1
            "\x00\x00\x00\x00\x00\x004@")     # 20.0

@testset "MultiPoint" begin
    @test read(mpt2d_wkb) == mpt2d
    @test read(mptz_wkb) == mptz
    @test read(mptm_wkb) == mptz
    @test read(mptzm_wkb) == mptzm
    @test read(mpt2d_srid664_wkb) == mpt2d_srid664
end

mls2d = (type="MultiLineString",
        coordinates=[[[2.2, 4.4], [3.1, 5.1], [5.1, 20.0]],
                    [[20.0, 2.2], [3.1, 4.4]],])
mls2d_wkb = WKB("\x00"*
                "\x00\x00\x00\x05"*
                "\x00\x00\x00\x02"*  # number of linestrings
                "\x00"*
                "\x00\x00\x00\x02"*
                "\x00\x00\x00\x03"*
                "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
                "@\x11\x99\x99\x99\x99\x99\x9a"*  # 4.4
                "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
                "@\x14ffffff"*                    # 5.1
                "@\x14ffffff"*                    # 5.1
                "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
                "\x00"*
                "\x00\x00\x00\x02"*
                "\x00\x00\x00\x02"*
                "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
                "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
                "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
                "@\x11\x99\x99\x99\x99\x99\x9a")  # 4.4
mlsz = (type="MultiLineString",
        coordinates=[
                    [[2.2, 0.0, 4.4], [3.1, 5.1, 5.1], [5.1, 20.0, 0.0]],
                    [[20.0, 2.2, 2.2], [0.0, 3.1, 4.4]],])
mlsz_wkb = WKB(
            "\x00"*
            "\x00\x00\x03\xed"*
            "\x00\x00\x00\x02"*  # number of linestrings
            "\x00"*
            "\x00\x00\x03\xea"*
            "\x00\x00\x00\x03"*
            "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "@\x11\x99\x99\x99\x99\x99\x9a"*  # 4.4
            "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
            "@\x14ffffff"*                    # 5.1
            "@\x14ffffff"*                    # 5.1
            "@\x14ffffff"*                    # 5.1
            "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "\x00"*
            "\x00\x00\x03\xea"*
            "\x00\x00\x00\x02"*
            "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
            "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
            "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
            "@\x11\x99\x99\x99\x99\x99\x9a")  # 4.4
mlsm_wkb = WKB(
            "\x00"*
            "\x00\x00\x07\xd5"*
            "\x00\x00\x00\x02"*  # number of linestrings
            "\x00"*
            "\x00\x00\x03\xea"*
            "\x00\x00\x00\x03"*
            "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "@\x11\x99\x99\x99\x99\x99\x9a"*  # 4.4
            "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
            "@\x14ffffff"*                    # 5.1
            "@\x14ffffff"*                    # 5.1
            "@\x14ffffff"*                    # 5.1
            "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "\x00"*
            "\x00\x00\x03\xea"*
            "\x00\x00\x00\x02"*
            "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
            "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
            "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
            "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
            "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
            "@\x11\x99\x99\x99\x99\x99\x9a")  # 4.4
mlszm = (type="MultiLineString",
        coordinates=[[[2.2, 4.4, 0.0, 3.0], [10.0, 0.0, 3.1, 2.0]],
                    [[0.0, 5.1, 20.0, 4.4]],])
mlszm_wkb = WKB("\x01"*
                "\xbd\x0b\x00\x00"*
                "\x02\x00\x00\x00"*  # two linestrings
                "\x01"*
                "\xba\x0b\x00\x00"*
                "\x02\x00\x00\x00"*  # two points
                "\x9a\x99\x99\x99\x99\x99\x01@"*     # 2.2
                "\x9a\x99\x99\x99\x99\x99\x11@"*     # 4.4
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "\x00\x00\x00\x00\x00\x00\x08@"*     # 3.0
                "\x00\x00\x00\x00\x00\x00\$@"*        # 10.0
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "\xcd\xcc\xcc\xcc\xcc\xcc\x08@"*     # 3.1
                "\x00\x00\x00\x00\x00\x00\x00@"*     # 2.0
                "\x01"*
                "\xba\x0b\x00\x00"*
                "\x01\x00\x00\x00"*  # one point
                "\x00\x00\x00\x00\x00\x00\x00\x00"*  # 0.0
                "ffffff\x14@"*                       # 5.1
                "\x00\x00\x00\x00\x00\x004@"*        # 20.0
                "\x9a\x99\x99\x99\x99\x99\x11@")     # 4.4
mls2d_srid4326 = (  type="MultiLineString",
                    coordinates=[[[2.2, 4.4], [3.1, 5.1], [5.1, 20.0]],
                                 [[20.0, 2.2], [3.1, 4.4]]],
                    meta=(srid=4326,),
                    crs=(type="name", properties=(name="EPSG4326",)))
mls2d_srid4326_wkb = WKB("\x00"*
                        "\x20\x00\x00\x05"*  # type with SRID flag set
                        "\x00\x00\x10\xe6"*  # SRID 4326
                        "\x00\x00\x00\x02"*  # number of linestrings
                        "\x00"*
                        "\x00\x00\x00\x02"*
                        "\x00\x00\x00\x03"*
                        "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
                        "@\x11\x99\x99\x99\x99\x99\x9a"*  # 4.4
                        "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
                        "@\x14ffffff"*                    # 5.1
                        "@\x14ffffff"*                    # 5.1
                        "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
                        "\x00"*
                        "\x00\x00\x00\x02"*
                        "\x00\x00\x00\x02"*
                        "@4\x00\x00\x00\x00\x00\x00"*     # 20.0
                        "@\x01\x99\x99\x99\x99\x99\x9a"*  # 2.2
                        "@\x08\xcc\xcc\xcc\xcc\xcc\xcd"*  # 3.1
                        "@\x11\x99\x99\x99\x99\x99\x9a")  # 4.4

@testset "MultiLineString" begin
    @test read(mls2d_wkb) == mls2d
    @test read(mlsz_wkb) == mlsz
    @test read(mlsm_wkb) == mlsz
    @test read(mlszm_wkb) == mlszm
    @test read(mls2d_srid4326_wkb) == mls2d_srid4326
end

mpg2d = (type="MultiPolygon",
        coordinates=[
            [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0],
              [102.0, 2.0]]],
            [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0],
              [100.0, 0.0]],
             [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8],
              [100.2, 0.2]]],
        ])
mpg2d_wkb = WKB("\x01"*  # little endian
            "\x06\x00\x00\x00"*  # 2d multipolygon
            "\x02\x00\x00\x00"*  # two polygons
            "\x01"*  # little endian
            "\x03\x00\x00\x00"*  # 2d polygon
            "\x01\x00\x00\x00"*  # 1 ring
            "\x05\x00\x00\x00"*  # 5 vertices
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x01"*  # little endian
            "\x03\x00\x00\x00"*  # 2d polygon
            "\x02\x00\x00\x00"*  # 2 rings
            "\x05\x00\x00\x00"*  # first ring, 5 vertices
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00@Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00@Y@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x05\x00\x00\x00"*  # second ring, 5 vertices
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "333333Y@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "333333Y@"*
            "\x9a\x99\x99\x99\x99\x99\xe9?"*
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xe9?"*
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?")
mpgz = (type="MultiPolygon", coordinates=[
    [[[102.0, 2.0, 0.0], [103.0, 2.0, 1.0], [103.0, 3.0, 2.0], [102.0, 3.0, 3.0], [102.0, 2.0, 4.0]]],
    [[[100.0, 0.0, 5.0], [101.0, 0.0, 6.0], [101.0, 1.0, 7.0], [100.0, 1.0, 8.0], [100.0, 0.0, 9.0]],
     [[100.2, 0.2, 10.0], [100.8, 0.2, 11.0], [100.8, 0.8, 12.0], [100.2, 0.8, 13.0], [100.2, 0.2, 14.0]]],
])
mpgz_wkb = WKB(
            "\x01"*  # little endian
            "\xee\x03\x00\x00"*  # 3d multipolygon
            "\x02\x00\x00\x00"*  # two polygons
            "\x01"*  # little endian
            "\xeb\x03\x00\x00"*  # 3d polygon
            "\x01\x00\x00\x00"*  # 1 ring
            "\x05\x00\x00\x00"*  # 5 vertices
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\x10@"*
            "\x01"*  # little endian
            "\xeb\x03\x00\x00"*  # 3d polygon
            "\x02\x00\x00\x00"*  # 2 rings
            "\x05\x00\x00\x00"*  # first ring, 5 vertices
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\x14@"*
            "\x00\x00\x00\x00\x00@Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\x18@"*
            "\x00\x00\x00\x00\x00@Y@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00\x1c@"*
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00 @"*
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\"@"*
            "\x05\x00\x00\x00"*  # second ring, 5 vertices
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "\x00\x00\x00\x00\x00\x00\$@"*
            "333333Y@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "\x00\x00\x00\x00\x00\x00&@"*
            "333333Y@"*
            "\x9a\x99\x99\x99\x99\x99\xe9?"*
            "\x00\x00\x00\x00\x00\x00(@"*
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xe9?"*
            "\x00\x00\x00\x00\x00\x00*@"*
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "\x00\x00\x00\x00\x00\x00,@")
mpgm_wkb = WKB(
            "\x01"*  # little endian
            "\xd6\x07\x00\x00"*  # m multipolygon
            "\x02\x00\x00\x00"*  # two polygons
            "\x01"*  # little endian
            "\xeb\x03\x00\x00"*  # m polygon
            "\x01\x00\x00\x00"*  # 1 ring
            "\x05\x00\x00\x00"*  # 5 vertices
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\x10@"*
            "\x01"*  # little endian
            "\xeb\x03\x00\x00"*  # m polygon
            "\x02\x00\x00\x00"*  # 2 rings
            "\x05\x00\x00\x00"*  # first ring, 5 vertices
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\x14@"*
            "\x00\x00\x00\x00\x00@Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\x18@"*
            "\x00\x00\x00\x00\x00@Y@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00\x1c@"*
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00 @"*
            "\x00\x00\x00\x00\x00\x00Y@"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\"@"*
            "\x05\x00\x00\x00"*  # second ring, 5 vertices
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "\x00\x00\x00\x00\x00\x00\$@"*
            "333333Y@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "\x00\x00\x00\x00\x00\x00&@"*
            "333333Y@"*
            "\x9a\x99\x99\x99\x99\x99\xe9?"*
            "\x00\x00\x00\x00\x00\x00(@"*
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xe9?"*
            "\x00\x00\x00\x00\x00\x00*@"*
            "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
            "\x9a\x99\x99\x99\x99\x99\xc9?"*
            "\x00\x00\x00\x00\x00\x00,@")
mpgzm = (type="MultiPolygon",
        coordinates=[
            [[[102.0, 2.0, 0.0, 14.0], [103.0, 2.0, 1.0, 13.0],
              [103.0, 3.0, 2.0, 12.0], [102.0, 3.0, 3.0, 11.0],
              [102.0, 2.0, 4.0, 10.0]]],
            [[[100.0, 0.0, 5.0, 9.0], [101.0, 0.0, 6.0, 8.0],
              [101.0, 1.0, 7.0, 7.0], [100.0, 1.0, 8.0, 6.0],
              [100.0, 0.0, 9.0, 5.0]],
             [[100.2, 0.2, 10.0, 4.0], [100.8, 0.2, 11.0, 3.0],
              [100.8, 0.8, 12.0, 2.0], [100.2, 0.8, 13.0, 1.0],
              [100.2, 0.2, 14.0, 0.0]]],
        ])
mpgzm_wkb = WKB("\x01"*  # little endian
                "\xbe\x0b\x00\x00"*  # 4d multipolygon
                "\x02\x00\x00\x00"*  # two polygons
                "\x01"*  # little endian
                "\xbb\x0b\x00\x00"*  # 4d polygon
                "\x01\x00\x00\x00"*  # 1 ring
                "\x05\x00\x00\x00"*  # 5 vertices
                "\x00\x00\x00\x00\x00\x80Y@"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\x00\x00\x00\x00\x00\x00\x00\x00"*
                "\x00\x00\x00\x00\x00\x00,@"*
                "\x00\x00\x00\x00\x00\xc0Y@"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\x00\x00\x00\x00\x00\x00\xf0?"*
                "\x00\x00\x00\x00\x00\x00*@"*
                "\x00\x00\x00\x00\x00\xc0Y@"*
                "\x00\x00\x00\x00\x00\x00\x08@"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\x00\x00\x00\x00\x00\x00(@"*
                "\x00\x00\x00\x00\x00\x80Y@"*
                "\x00\x00\x00\x00\x00\x00\x08@"*
                "\x00\x00\x00\x00\x00\x00\x08@"*
                "\x00\x00\x00\x00\x00\x00&@"*
                "\x00\x00\x00\x00\x00\x80Y@"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\x00\x00\x00\x00\x00\x00\x10@"*
                "\x00\x00\x00\x00\x00\x00\$@"*
                "\x01"*  # little endian
                "\xbb\x0b\x00\x00"*  # 4d polygon
                "\x02\x00\x00\x00"*  # 2 rings
                "\x05\x00\x00\x00"*  # first ring, 5 vertices
                "\x00\x00\x00\x00\x00\x00Y@"*
                "\x00\x00\x00\x00\x00\x00\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\x14@"*
                "\x00\x00\x00\x00\x00\x00\"@"*
                "\x00\x00\x00\x00\x00@Y@"*
                "\x00\x00\x00\x00\x00\x00\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\x18@"*
                "\x00\x00\x00\x00\x00\x00 @"*
                "\x00\x00\x00\x00\x00@Y@"*
                "\x00\x00\x00\x00\x00\x00\xf0?"*
                "\x00\x00\x00\x00\x00\x00\x1c@"*
                "\x00\x00\x00\x00\x00\x00\x1c@"*
                "\x00\x00\x00\x00\x00\x00Y@"*
                "\x00\x00\x00\x00\x00\x00\xf0?"*
                "\x00\x00\x00\x00\x00\x00 @"*
                "\x00\x00\x00\x00\x00\x00\x18@"*
                "\x00\x00\x00\x00\x00\x00Y@"*
                "\x00\x00\x00\x00\x00\x00\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\"@"*
                "\x00\x00\x00\x00\x00\x00\x14@"*
                "\x05\x00\x00\x00"*  # second ring, 5 vertices
                "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
                "\x9a\x99\x99\x99\x99\x99\xc9?"*
                "\x00\x00\x00\x00\x00\x00\$@"*
                "\x00\x00\x00\x00\x00\x00\x10@"*
                "333333Y@"*
                "\x9a\x99\x99\x99\x99\x99\xc9?"*
                "\x00\x00\x00\x00\x00\x00&@"*
                "\x00\x00\x00\x00\x00\x00\x08@"*
                "333333Y@"*
                "\x9a\x99\x99\x99\x99\x99\xe9?"*
                "\x00\x00\x00\x00\x00\x00(@"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
                "\x9a\x99\x99\x99\x99\x99\xe9?"*
                "\x00\x00\x00\x00\x00\x00*@"*
                "\x00\x00\x00\x00\x00\x00\xf0?"*
                "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
                "\x9a\x99\x99\x99\x99\x99\xc9?"*
                "\x00\x00\x00\x00\x00\x00,@"*
                "\x00\x00\x00\x00\x00\x00\x00\x00")
mpg2d_srid4326 = (
    type="MultiPolygon",
    coordinates=[
        [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0],
          [102.0, 2.0]]],
        [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0],
          [100.0, 0.0]],
         [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8],
          [100.2, 0.2]]],
    ],
    meta=(srid=4326,),
    crs=(type="name", properties=(name="EPSG4326",)),
)
mpg2d_srid4326_wkb = WKB("\x01"*  # little endian
                        "\x06\x00\x00\x20"*  # 2d multipolygon wth SRID flag
                        "\xe6\x10\x00\x00"*  # 4 bytes containing SRID (SRID=4326)
                        "\x02\x00\x00\x00"*  # two polygons
                        "\x01"*  # little endian
                        "\x03\x00\x00\x00"*  # 2d polygon
                        "\x01\x00\x00\x00"*  # 1 ring
                        "\x05\x00\x00\x00"*  # 5 vertices
                        "\x00\x00\x00\x00\x00\x80Y@"*
                        "\x00\x00\x00\x00\x00\x00\x00@"*
                        "\x00\x00\x00\x00\x00\xc0Y@"*
                        "\x00\x00\x00\x00\x00\x00\x00@"*
                        "\x00\x00\x00\x00\x00\xc0Y@"*
                        "\x00\x00\x00\x00\x00\x00\x08@"*
                        "\x00\x00\x00\x00\x00\x80Y@"*
                        "\x00\x00\x00\x00\x00\x00\x08@"*
                        "\x00\x00\x00\x00\x00\x80Y@"*
                        "\x00\x00\x00\x00\x00\x00\x00@"*
                        "\x01"*  # little endian
                        "\x03\x00\x00\x00"*  # 2d polygon
                        "\x02\x00\x00\x00"*  # 2 rings
                        "\x05\x00\x00\x00"*  # first ring, 5 vertices
                        "\x00\x00\x00\x00\x00\x00Y@"*
                        "\x00\x00\x00\x00\x00\x00\x00\x00"*
                        "\x00\x00\x00\x00\x00@Y@"*
                        "\x00\x00\x00\x00\x00\x00\x00\x00"*
                        "\x00\x00\x00\x00\x00@Y@"*
                        "\x00\x00\x00\x00\x00\x00\xf0?"*
                        "\x00\x00\x00\x00\x00\x00Y@"*
                        "\x00\x00\x00\x00\x00\x00\xf0?"*
                        "\x00\x00\x00\x00\x00\x00Y@"*
                        "\x00\x00\x00\x00\x00\x00\x00\x00"*
                        "\x05\x00\x00\x00"*  # second ring, 5 vertices
                        "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
                        "\x9a\x99\x99\x99\x99\x99\xc9?"*
                        "333333Y@"*
                        "\x9a\x99\x99\x99\x99\x99\xc9?"*
                        "333333Y@"*
                        "\x9a\x99\x99\x99\x99\x99\xe9?"*
                        "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
                        "\x9a\x99\x99\x99\x99\x99\xe9?"*
                        "\xcd\xcc\xcc\xcc\xcc\x0cY@"*
                        "\x9a\x99\x99\x99\x99\x99\xc9?")

@testset "MultiPolygon" begin
    @test read(mpg2d_wkb) == mpg2d
    @test read(mpgz_wkb) == mpgz
    @test read(mpgm_wkb) == mpgz
    @test read(mpgzm_wkb) == mpgzm
    @test read(mpg2d_srid4326_wkb) == mpg2d_srid4326
end

gc2d = (type="GeometryCollection",
        geometries=[
            (type="Point", coordinates=[0.0, 1.0]),
            (type="LineString", coordinates=[
                [102.0, 2.0], [103.0, 3.0], [104.0, 4.0]
            ]),
        ])
gc2d_wkb = WKB( "\x00"*  # big endian
                "\x00\x00\x00\x07"*  # 2d geometry collection
                "\x00\x00\x00\x02"*  # 2 geometries in the collection
                "\x00"*
                "\x00\x00\x00\x01"*  # 2d point
                "\x00\x00\x00\x00\x00\x00\x00\x00"*
                "?\xf0\x00\x00\x00\x00\x00\x00"*
                "\x00"*
                "\x00\x00\x00\x02"*  # 2d linestring
                "\x00\x00\x00\x03"*  # 3 vertices
                "@Y\x80\x00\x00\x00\x00\x00"*
                "@\x00\x00\x00\x00\x00\x00\x00"*
                "@Y\xc0\x00\x00\x00\x00\x00"*
                "@\x08\x00\x00\x00\x00\x00\x00"*
                "@Z\x00\x00\x00\x00\x00\x00"*
                "@\x10\x00\x00\x00\x00\x00\x00")
gcz = (type="GeometryCollection",
        geometries=[
            (type="Point", coordinates=[0.0, 1.0, 2.0]),
            (type="LineString", coordinates=[
                [102.0, 2.0, 6.0], [103.0, 3.0, 7.0], [104.0, 4.0, 8.0]
            ]),
        ])
gcz_wkb = WKB( "\x01"*  # little endian
                "\xef\x03\x00\x00"*  # 3d geometry collection
                "\x02\x00\x00\x00"*  # 2 geometries in the collection
                "\x01"*
                "\xe9\x03\x00\x00"*  # 3d point
                "\x00\x00\x00\x00\x00\x00\x00\x00"*
                "\x00\x00\x00\x00\x00\x00\xf0?"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\x01"*
                "\xea\x03\x00\x00"*  # 3d linestring
                "\x03\x00\x00\x00"*  # 3 vertices
                "\x00\x00\x00\x00\x00\x80Y@"*
                "\x00\x00\x00\x00\x00\x00\x00@"*
                "\x00\x00\x00\x00\x00\x00\x18@"*
                "\x00\x00\x00\x00\x00\xc0Y@"*
                "\x00\x00\x00\x00\x00\x00\x08@"*
                "\x00\x00\x00\x00\x00\x00\x1c@"*
                "\x00\x00\x00\x00\x00\x00Z@"*
                "\x00\x00\x00\x00\x00\x00\x10@"*
                "\x00\x00\x00\x00\x00\x00 @")
gcm_wkb = WKB(
            "\x01"*  # little endian
            "\xd7\x07\x00\x00"*
            "\x02\x00\x00\x00"*  # 2 geometries in the collection
            "\x01"*
            "\xd1\x07\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "\x00\x00\x00\x00\x00\x00\xf0?"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x01"*
            "\xd2\x07\x00\x00"*
            "\x03\x00\x00\x00"*  # 3 vertices
            "\x00\x00\x00\x00\x00\x80Y@"*
            "\x00\x00\x00\x00\x00\x00\x00@"*
            "\x00\x00\x00\x00\x00\x00\x18@"*
            "\x00\x00\x00\x00\x00\xc0Y@"*
            "\x00\x00\x00\x00\x00\x00\x08@"*
            "\x00\x00\x00\x00\x00\x00\x1c@"*
            "\x00\x00\x00\x00\x00\x00Z@"*
            "\x00\x00\x00\x00\x00\x00\x10@"*
            "\x00\x00\x00\x00\x00\x00 @")
gczm = (type="GeometryCollection", geometries=[
            (type="Point", coordinates=[0.0, 1.0, 2.0, 3.0]),
            (type="LineString", coordinates=[
                [102.0, 2.0, 6.0, 10.0], [103.0, 3.0, 7.0, 11.0],
                [104.0, 4.0, 8.0, 12.0]
            ]),
        ])
gczm_wkb = WKB(
            "\x00"*  # big endian
            "\x00\x00\x0b\xbf"*  # 4d geometry collection
            "\x00\x00\x00\x02"*  # 2 geometries in the collection
            "\x00"*
            "\x00\x00\x0b\xb9"*  # 4d point
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "?\xf0\x00\x00\x00\x00\x00\x00"*
            "@\x00\x00\x00\x00\x00\x00\x00"*
            "@\x08\x00\x00\x00\x00\x00\x00"*
            "\x00"*
            "\x00\x00\x0b\xba"*  # 4d linestring
            "\x00\x00\x00\x03"*  # 3 vertices
            "@Y\x80\x00\x00\x00\x00\x00"*
            "@\x00\x00\x00\x00\x00\x00\x00"*
            "@\x18\x00\x00\x00\x00\x00\x00"*
            "@\$\x00\x00\x00\x00\x00\x00"*
            "@Y\xc0\x00\x00\x00\x00\x00"*
            "@\x08\x00\x00\x00\x00\x00\x00"*
            "@\x1c\x00\x00\x00\x00\x00\x00"*
            "@&\x00\x00\x00\x00\x00\x00"*
            "@Z\x00\x00\x00\x00\x00\x00"*
            "@\x10\x00\x00\x00\x00\x00\x00"*
            "@ \x00\x00\x00\x00\x00\x00"*
            "@(\x00\x00\x00\x00\x00\x00")
gc2d_srid1234 = (type="GeometryCollection",
                geometries=[
                    (type="Point", coordinates=[0.0, 1.0]),
                    (type="LineString", coordinates=[
                        [102.0, 2.0], [103.0, 3.0], [104.0, 4.0]
                    ]),
                ],
                meta=(srid=1234,),
                crs=(type="name", properties=(name="EPSG1234",)))
gc2d_srid1234_wkb = WKB(
            "\x00"*  # big endian
            "\x20\x00\x00\x07"*  # 2d geometry collection
            "\x00\x00\x04\xd2"*  # srid 1234
            "\x00\x00\x00\x02"*  # 2 geometries in the collection
            "\x00"*  # big endian
            "\x00\x00\x00\x01"*  # 2d point
            "\x00\x00\x00\x00\x00\x00\x00\x00"*
            "?\xf0\x00\x00\x00\x00\x00\x00"*
            "\x00"*  # big endian
            "\x00\x00\x00\x02"*  # 2d linestring
            "\x00\x00\x00\x03"*  # 3 vertices
            "@Y\x80\x00\x00\x00\x00\x00"*
            "@\x00\x00\x00\x00\x00\x00\x00"*
            "@Y\xc0\x00\x00\x00\x00\x00"*
            "@\x08\x00\x00\x00\x00\x00\x00"*
            "@Z\x00\x00\x00\x00\x00\x00"*
            "@\x10\x00\x00\x00\x00\x00\x00")

@testset "GeometryCollection" begin
    @test read(gc2d_wkb) == gc2d
    @test read(gcz_wkb) == gcz
    @test read(gcm_wkb) == gcz
    @test read(gczm_wkb) == gczm
    @test read(gc2d_srid1234_wkb) == gc2d_srid1234
end


text:
using GeoInterface
using LibGEOS

using LinearAlgebra
using LaTeXStrings
using Formatting
import PyPlot; plt=PyPlot
cbbPalette = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7"]
# using ..NYC: read_distr_reprpoints
using Distributions: MultivariateNormal
using Statistics: mean
using GaussianProcesses: predict_f
using PyCall
# mplot3d = pyimport("mpl_toolkits.mplot3d")

function plot_polygon(poly_coords, facecolor, alpha;
                      edgecolor="none", linestyle="None", linewidth=0.0, kwargs...)
    ax = plt.gca()
    poly_array = Array{Float64}(undef, length(poly_coords), 2)
    for i in 1:length(poly_coords)
        poly_array[i, :] = poly_coords[i]
    end
    polygon = plt.plt.Polygon(poly_array, true; facecolor=facecolor, kwargs...)
    p = ax.add_patch(polygon)
    p.set_edgecolor(edgecolor)
    p.set_linestyle(linestyle)
    p.set_linewidth(linewidth)
    p.set_alpha(alpha)
end

function plot_buffer(shape, border, color, dist, alpha; kwargs...)
    # a buffer zone around the border:
    border_buffer = LibGEOS.buffer(border, dist)
    # prevents a ring self-intersection bug (bad shapefile?):
    shape_rectified = LibGEOS.buffer(shape, 0.0)
    # the part of the buffer on the `shape` side of the border:
    shape_buffer = LibGEOS.intersection(border_buffer, shape_rectified)
    if typeof(shape_buffer) <: LibGEOS.Polygon
        poly_coords = GeoInterface.coordinates(shape_buffer)[1]
        plot_polygon(poly_coords, color, alpha; kwargs...)
    elseif typeof(shape_buffer) <: LibGEOS.MultiPolygon
        mpoly_coords = GeoInterface.coordinates(shape_buffer)
        for poly_coords in mpoly_coords
            plot_polygon(poly_coords[1], color, alpha; kwargs...)
        end
    else
        println(typeof(shape_buffer))
    end
end

function plot_schdistr_labels(;fontsize=12.0, labelcolor="black")
    plt.rc("text", usetex=false)
    # where to place the school district labels:
    schdistr_represent = Dict{SchDistr, Tuple{Float64, Float64}}(25 => (1035426.576356058, 215708.47750849032), 20 => (980957.6301213544, 166113.83169550286), 3 => (992826.0954164147, 226695.6766967253), 4 => (1000248.2836855762, 228298.3092956051), 16 => (1004214.0439845352, 188657.53201288398), 23 => (1008819.7413809987, 183460.7804870081), 18 => (1008787.3316119347, 173443.51080316756), 26 => (1054423.2425350049, 212717.9963988735), 32 => (1006895.1698167967, 192470.89239496225), 1 => (988952.4509786353, 202318.4309997029), 2 => (987095.1379395023, 210542.70410151145), 24 => (1013178.9222047399, 202219.43350214284), 28 => (1036851.1969587662, 195628.9613036562), 10 => (1008845.8110727321, 258295.0202941391), 9 => (1008189.8006258132, 245065.8830871096), 7 => (1006949.3221918349, 235790.44049067114), 30 => (1011393.8551870013, 216959.78259271727), 12 => (1017667.4294655474, 243924.23712153034), 8 => (1022714.7969213917, 237308.7890929639), 14 => (998121.9324939251, 199650.8938903253), 31 => (947923.9119948001, 147916.42111200799), 17 => (997069.2552085526, 180290.71820062993), 13 => (994552.5771594604, 190230.17111200746), 15 => (987418.7441204586, 181218.70071406086), 22 => (1001740.2660473757, 162368.14001459582), 21 => (991081.0983826279, 157637.68869012795), 11 => (1026344.6177574333, 256966.2814940873), 29 => (1055388.4397568335, 188398.91879267507), 19 => (1017942.166879338, 181833.5946349586), 27 => (1040711.4984081909, 178979.62564887386), 5 => (996548.0388532034, 237031.53149408224), 6 => (1001541.6608069859, 248002.3049010716))
    xmin,xmax = plt.xlim()
    ymin,ymax = plt.ylim()
    ax = plt.gca()
    for schdistr in keys(schdistr_represent)
        center_x, center_y = schdistr_represent[schdistr]

        if !(xmin < center_x < xmax)
            continue
        elseif !(ymin < center_y < ymax)
            continue
        end

        ax.annotate(
            @sprintf("%d", schdistr),
            xy=(center_x, center_y),
            xycoords="data",
            xytext=(0,0),
            textcoords="offset points",
            horizontalalignment="center",
            verticalalignment="center",
            fontweight="black",
            color=labelcolor,
            alpha=1.0,
            fontsize = fontsize,
            zorder=3,
            annotation_clip=true,
        )
        ax.annotate(
            @sprintf("%d", schdistr),
            xy=(center_x, center_y),
            xycoords="data",
            xytext=(0,0),
            textcoords="offset points",
            horizontalalignment="center",
            verticalalignment="center",
            fontweight="black",
            color=labelcolor,
            alpha=0.5,
            fontsize = fontsize,
            zorder=20,
            annotation_clip=true,
        )
    end
    plt.rc("text", usetex=true)
end

function plot_all_pairs(τpost_pairs::Dict{Tuple{SchDistr,SchDistr}}, regionData_dict::Dict{SchDistr,GeoRDD.RegionData}; scaleup=200.0, zorder="none")
    for distr_pair in keys(τpost_pairs)
        distrA, distrB = distr_pair

        τpost = τpost_pairs[distr_pair]
        # eff_size = abs(mean(τpost)) / std(τpost) * 2
        # if eff_size < 2.0
            # continue
        # end

        if distrA ∈ (1,2) || distrB ∈ (1,2)
            # don't do Manhattan, it's weird
            continue
        end

        # skip districts that aren't on the map
        if distrA ∉ (13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32)
            continue
        end
        if distrB ∉ (13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32)
            continue
        end

        if distrA >= distrB
            continue
        end

        shapeA = regionData_dict[distrA].shape
        shapeB = regionData_dict[distrB].shape
        border = GeoRDD.get_border(shapeA, shapeB, 10.0)

        border_coords = GeoInterface.coordinates(border)
        if typeof(border) <: LibGEOS.MultiLineString
        else
            border_coords = [border_coords]
        end
        ax = plt.gca()

        if mean(τpost) < 0
            cheaper_shape = shapeA
            pricier_shape = shapeB
        else
            cheaper_shape = shapeB
            pricier_shape = shapeA
        end
        plot_buffer(pricier_shape, border, cbbPalette[2], (abs(mean(τpost)) + std(τpost))*scaleup, 1.0, zorder=zorder-1)
        plot_buffer(pricier_shape, border, cbbPalette[1], abs(mean(τpost))*scaleup, 1.0, zorder=zorder)
    end
end

function plot_streets(;zoom=11, brighten=30, rgb=(200, 200, 200), zorder=-9)
    ax = plt.gca()
    ax.set_autoscale_on(false)
    ax.set_autoscalex_on(false)
    ax.set_autoscaley_on(false)
    EPSG=2263 # projection
    topleft =  (40.75, -74.01)
    botright = (40.58, -73.60)
    py"""
    import matplotlib.pyplot as plt

    import geopandas as gpd
    import tilemapbase
    import pyproj
    import PIL.Image as _Image

    def bounds(plotter, epsg):
        epsg_proj = pyproj.Proj('epsg:%d' % epsg, preserve_units=True)
        epsg_3857 = pyproj.Proj('epsg:%d' % tilemapbase.mapping._WEB_MERCATOR)
        self = plotter
        scale = 2 ** self.zoom
        x0, y0 = self.xtilemin / scale, self.ytilemin / scale # in tile space
        x1, y1 = (self.xtilemax + 1) / scale, (self.ytilemax + 1) / scale
        x0_ll, y0_ll = tilemapbase.to_lonlat(x0, y0)
        x1_ll, y1_ll = tilemapbase.to_lonlat(x1, y1)
        y0_ll, y1_ll = y1_ll, y0_ll # for some reason that I don't understand
        print(y0_ll)
        print(y1_ll)
        x0_epsg, y0_epsg = epsg_proj(x0_ll, y0_ll)
        x1_epsg, y1_epsg = epsg_proj(x1_ll, y1_ll)
        return x0_epsg, x1_epsg, y0_epsg, y1_epsg

    def brighten(img, factor):
        # split the image into individual bands
        source = img.split()
        R, G, B, A = 0, 1, 2, 3

        # process each band separately
        out_R = source[R].point(lambda x: min(x+factor, 256))
        out_G = source[G].point(lambda x: min(x+factor, 256))
        out_B = source[B].point(lambda x: min(x+factor, 256))

        # build a new multiband image
        brightened = _Image.merge(img.mode, (out_R, out_G, out_B, source[A]))
        return brightened

    def makecolor(img, rgb):
        # split the image into individual bands
        source = img.split()
        R, G, B, A = 0, 1, 2, 3

        # process each band separately
        out_R = source[R].point(lambda x: rgb[0])
        out_G = source[G].point(lambda x: rgb[1])
        out_B = source[B].point(lambda x: rgb[2])

        # build a new multiband image
        new_im = _Image.merge(img.mode, (out_R, out_G, out_B, source[A]))
        return new_im

    tilemapbase.start_logging()
    tilemapbase.init("/Users/imolk/tmp/tilemapbase.cache", create=True)

    extent = tilemapbase.Extent.from_lonlat($topleft[1], $botright[1],
                      $botright[0], $topleft[0])
    # plotter_ln = tilemapbase.Plotter(extent,tilemapbase.tiles.Carto_Dark_No_Labels, zoom=$zoom)
    plotter_ln = tilemapbase.Plotter(extent,tilemapbase.tiles.Stamen_Terrain_Lines, zoom=$zoom)
    plotter = plotter_ln
    # tile = brighten(plotter.as_one_image(), $brighten)
    tile = makecolor(plotter.as_one_image(), $rgb)
    $ax.imshow(tile, interpolation="lanczos", extent=bounds(plotter, $EPSG), origin="upper", zorder=$zorder)
    """
end

function ticks(xmin, xmax, tickdist)
    return tickdist * (ceil(xmin/tickdist):1.0:floor(xmax/tickdist))
end
function ticks_km(tickdist::Float64)
    _xlim = plt.xlim()
    _ylim = plt.ylim()
    km_in_ft = 3280.84
    _xlim_km = _xlim ./ km_in_ft
    _ylim_km = _ylim ./ km_in_ft
    _xtick_km = ticks(_xlim_km[1], _xlim_km[2], tickdist)
    _ytick_km = ticks(_ylim_km[1], _ylim_km[2], tickdist)
    _xtick_ft = _xtick_km .* km_in_ft
    _ytick_ft = _ytick_km .* km_in_ft
    plt.xticks(_xtick_ft, [@sprintf("%.0f", x) for x in _xtick_km])
    plt.yticks(_ytick_ft, [@sprintf("%.0f", x) for x in _ytick_km])
    plt.xlabel("Eastings (km)")
    plt.ylabel("Northings (km)")
end

function plot_sales(filtered, missing_sqft; edgecolor="black", labelsize=12.0, labelcolor="black", colorbar=true, tickdist=5.0)
    fig=plt.figure()
    background_schdistrs(plt.gca(),
                color="#AAAAAA",
                edgecolor=edgecolor,
                alpha=1.0,
                linestyle="-",
                zorder=-10
                )
    background_schdistrs(plt.gca(),
                color="none",
                edgecolor=edgecolor,
                alpha=1.0,
                linestyle="-",
                linewidth=0.5,
                zorder=11)
    _xlim = (0.98e6, 1.06e6)
    _ylim = (1.5e5, 2.2e5)
    plt.plot(
        missing_sqft[!,:XCoord],
        missing_sqft[!,:YCoord],
        color="white",
        marker="x",
        markersize=1.0,
        linestyle="",
        zorder=8,
        alpha=0.7,
        linewidth=0.1,
        markeredgewidth=0.3,
    )
    plt.scatter(
        filtered[!,:XCoord], filtered[!,:YCoord],
        c=filtered[!,:logSalePricePerSQFT],
        cmap="jet",
        edgecolors="None",
        zorder=10,
        marker="o",
    #     vmin=4.0,
    #     vmax=8.0,
        alpha=1.0,
        s=1,
        )
    # plt.xlim(np.percentile(sales_geocoded_ggl["XCoord"].dropna(), [1,99]))
    # plt.ylim(np.percentile(sales_geocoded_ggl["YCoord"].dropna(), [1,99]))
    # plt.axis("off")
    # plt.title("log(Property Price per SQFT) in New York")
    ax = plt.gca()
    ax.set(aspect="equal", adjustable="box")
    # ax.get_xaxis().set_ticks([])
    # ax.get_yaxis().set_ticks([])
    plt.xlim(_xlim)
    plt.ylim(_ylim)
    ticks_km(tickdist)

    ax.set_facecolor("#B0DAEE")
    if colorbar
        cbar = plt.colorbar(label="Square foot prices (\\\$ per sqft)")
        ax = cbar.ax
        tick_template = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        labeled = [10, 100, 1000, 10^4]
        ax.set_yticks(log.(labeled))
        ax.set_yticks(log.([tick_template; tick_template.*10; tick_template.*100; tick_template.*1000]),
                               minor=true)
        ax.set_yticklabels([format(x, commas=true) for x in labeled])
    end

    ax.set_autoscale_on(false)
    ax.set_autoscalex_on(false)
    ax.set_autoscaley_on(false)
    plot_schdistr_labels(fontsize=labelsize, labelcolor=labelcolor)
end
function plot_cliffface(μ, Σ, color; ndraws::Int=10, label=L"posterior of $\tau(x)$ on residuals")
    plt.plot(μ, color=color, ".", label=label)
    msize=10
    plt.plot(1,μ[1], color=cbbPalette[5],
        markersize=msize, marker="o")
    plt.plot(length(μ),μ[end], color=cbbPalette[4],
        markersize=msize, marker="o")
    posterior_sd = sqrt.(diag(Σ))
    plt.fill_between(1:length(μ), μ.-2*posterior_sd, μ.+2*posterior_sd,
        color=color,
        alpha=0.3,
        linewidth=0,
        zorder=-2,
        )
    posterior_distr = MultivariateNormal(μ, Σ)
    for _ in 1:ndraws
        plt.plot(1:length(μ), rand(posterior_distr), "-", color="white", alpha=0.4, linewidth=1.5, zorder=-1)
    end
    plt.xlim(1,length(μ))
    plt.ylim(minimum(μ.-2*posterior_sd), maximum(μ.+2*posterior_sd))

    # second y-axis for percentage price increase
    ax = plt.gca()
    y1, y2=ax.get_ylim()
    x1, x2=ax.get_xlim()
    ax2=ax.twinx()
    ax2.set_ylim(y1, y2)
    yticks_frac = collect(0.5: 0.1 : 2.0)
    yticks_log = log.(yticks_frac)
    in_window = y1 .< yticks_log .< y2
    ax2.set_yticks(yticks_log[in_window])
    ylabels = [@sprintf("%.0f\\%%", y*100) for y in yticks_frac[in_window]]
    ax2.set_yticklabels(ylabels)

    plt.sca(ax)
end

# plotting convenience functions
function yaxis_right()
    ax = plt.gca()
    ax.yaxis.tick_right()
    ax.yaxis.set_label_position("right")
end
function title_in_axis(s, leftright)
    if leftright == :left
        plt.text(0.05, 0.95, s,
             horizontalalignment="left",
             verticalalignment="top",
             transform = plt.gca().transAxes)
    elseif leftright == :right
        plt.text(0.95, 0.95, s,
             horizontalalignment="right",
             verticalalignment="top",
             transform = plt.gca().transAxes)
    else
        throw("left or right?")
    end
end
function hide_xaxis()
    plt.gca().xaxis.set_ticklabels([])
    plt.xlabel("")
end
function pval_yticks()
    ax = plt.gca()
    plt.ylim(0,1)
    ax.set_yticks(0:0.1:1, minor=true)
    ax.set_yticks(0:0.2:1, minor=false)
end

# NYC_dir is GeoRDD/examples/NYC and is expected to be defined
# in the module that loads this file
NYSD_FILENAME = joinpath(NYC_dir, "NYC_data/nysd_16c/nysd.json")
py"""
import matplotlib.pyplot as plt
import pandas as pd
import geopandas as gpd
plot_dataframe = gpd.plotting.plot_dataframe
import numpy as np
import itertools
plt.interactive(False)

EPSG=2263 # projection
# import os
# dirname = os.path.dirname(__file__)
# nysd_filename = os.path.join(dirname, "NYC_data/nysd_16c/nysd.json")
nycdistrs=gpd.read_file($(NYSD_FILENAME)).to_crs(epsg=EPSG)

def background_schdistrs(ax, **kwargs):
    plot_dataframe(nycdistrs, ax=ax, **kwargs)
    return None
"""
background_schdistrs = py"background_schdistrs"


text:
inv_logit(x) = 1/(1 + exp(-x))
softmax(A) = exp.(A) ./ sum(exp.(A))

function wcdraw!(account, pars::PityTimerParameters)::Tuple{Int64,Int64,Int64}
    p = zeros(Float64, 4)

    p[2] = pars.rare_wild_card_base + pars.rare_wild_card_increment * max(account.pitytimer[3] - pars.change_point, 0)^pars.ptpower
    p[4] = pars.mythic_wild_card_base + pars.mythic_wild_card_increment * max(account.pitytimer[4] - pars.change_point,0)^pars.ptpower

    p[1] = pars.rare_card
    p[3] = pars.mythic_card

    raredraw = rand(Categorical(softmax(p)))

    if raredraw == 2
        account.pitytimer[3] = 0
        account.wc_count[3] += 1
    else
        account.pitytimer[3] += 1
    end

    if raredraw == 4
        account.pitytimer[4] = 0
        account.wc_count[4] += 1
    else
        account.pitytimer[4] += 1
    end

    pc = inv_logit(pars.common_wild_card_base + pars.common_wild_card_increment * account.pitytimer[1])
    pu = inv_logit(pars.uncommon_wild_card_base + pars.uncommon_wild_card_increment * account.pitytimer[2])

    commondraw = rand(Bernoulli(pc))
    uncommondraw = rand(Bernoulli(pu))

    if commondraw == 1
        account.pitytimer[1] = 0
        account.wc_count[1] += 1
    else
        account.pitytimer[1] += 1
    end

    if uncommondraw == 1
        account.pitytimer[2] = 0
        account.wc_count[2] += 1
    else
        account.pitytimer[2] += 1
    end

    commondraw, uncommondraw, raredraw
end

function open_pack!(pack_contents; set,  collection, pitytimer_parameters, account,
     openable_cards, parameters, logging_vector, output, rep)

    common_wc, uncommon_wc, rareslot = wcdraw!(account, pitytimer_parameters)

    for r in 1:4
        if !isempty(openable_cards.by_set_rarity[(set,r)])
            rand!(pack_contents[r], openable_cards.by_set_rarity[(set,r)])
        else
            fill!(pack_contents[r], 0)
            if r == 1 || r == 2 || (r == 3 && rareslot == 1) || (r == 4 && rareslot == 3)
                length_correction = (r == 1 && common_wc == 1) || (r == 2 & uncommon_wc == 1) ? 1 : 0
                account.vault_pct += parameters.duplicate_vpct[r] * (length(pack_contents[r]) - length_correction)
            end
        end
    end

    if common_wc == 1
        pack_contents[1][1] = 0
        output.total_pack_wcs[rep,1] += 1
    end
    if uncommon_wc == 1
        pack_contents[2][1] = 0
        output.total_pack_wcs[rep,2] += 1
    end

    if rareslot == 1 # Rare card
        fill!(pack_contents[4], 0)
    elseif rareslot == 3 # Mythic card
        fill!(pack_contents[3], 0)
    else # Wildcard
        fill!(pack_contents[4], 0)
        fill!(pack_contents[3], 0)
    end

    if rareslot == 2
        output.total_pack_wcs[rep,3] += 1
    end

    if rareslot == 4
        output.total_pack_wcs[rep,4] += 1
    end

    pack_to_collection!(collection; pack_contents = pack_contents, set = set,
     account = account, parameters = parameters, logging_vector = logging_vector, openable_cards = openable_cards)

     output.total_packs[rep] += 1

end

function pack_to_collection!(collection; pack_contents, account,
     parameters, logging_vector, openable_cards, set)
    for r in 1:4
        for card in pack_contents[r]
            if card > 0
                if collection[card] < 4
                    collection[card] += 1
                    push!(logging_vector, card)

                    if collection[card] >= 4 && parameters.prevent_duplicates
                        remove_fully_collected!(card, set, r; openable_cards = openable_cards )
                    end
                else
                    account.vault_pct += parameters.duplicate_vpct[r]
                end
            end
        end
    end
end

max_stars_repo_name: asieev/ArenaSim

max_issues_repo_name: asieev/ArenaSim

max_forks_repo_name: asieev/ArenaSim


text:
const TOKEN_PREFIX = '/'

macro j_str(token)
    Pointer(token)
end

"""
    Pointer(token)

A JSON Pointer is a Unicode string containing a sequence of zero or more reference tokens, each prefixed
by a '/' (%x2F) character.

Follows IETF JavaScript Object Notation (JSON) Pointer https://tools.ietf.org/html/rfc6901

- Index numbers starts from '1' instead of '0'
- User can declare type with '::T' notation at the end

# Arguments
- `shift_index` : shift given index by 1 for compatibility with original JSONPointer

"""
struct Pointer{T}
    token::Tuple

    Pointer{T}(token::Tuple) where T = new{T}(token)
    function Pointer(token::AbstractString; shift_index = false)
        # URI Fragment
        if startswith(token, "#")
            token = token[2:end]
            token = unescape_jpath(token)
        end

        if isempty(token)
            return Pointer{Nothing}(tuple(""))
        end
        if !startswith(token, TOKEN_PREFIX)
            throw(ArgumentError("JSONPointer must starts with '$TOKEN_PREFIX' prefix"))
        end

        T = Any
        jk = convert(Array{Any, 1}, split(chop(token; head=1, tail=0), TOKEN_PREFIX))
        if occursin("::", jk[end])
            x = split(jk[end], "::")
            jk[end] = x[1]
            T = (x[2] == "Vector" ? "Vector{Any}" : x[2]) |> Meta.parse |> eval
        end
        @inbounds for i in 1:length(jk)
            if occursin(r"^\d+$", jk[i]) # index of a array
                jk[i] = if shift_index
                    parse(Int, string(jk[i])) + 1
                else
                    parse(Int, string(jk[i]))
                end

                if iszero(jk[i])
                    throw(ArgumentError("Julia uses 1-based indexing, use '1' instead of '0'"))
                end
            elseif occursin(r"^\\\d+$", jk[i]) # literal string for a number
                jk[i] = chop(jk[i]; head=1, tail=0)
            elseif occursin("~", jk[i])
                jk[i] = replace(replace(jk[i], "~0" => "~"), "~1" => "/")
            end
        end
        new{T}(tuple(jk...))
    end
end

"""
    unescape_jpath(raw::String)

Transform escaped characters in JPaths back to their original value.
https://tools.ietf.org/html/rfc6901
"""
function unescape_jpath(raw::AbstractString)
    m = match(r"%([0-9A-F]{2})", raw)
    if m !== nothing
        for c in m.captures
            raw = replace(raw, "%$(c)" => Char(parse(UInt8, "0x$(c)")))
        end
    end
    return raw
end

"""
    null_value(p::Pointer{T}) where T
    null_value(::Type{T}) where T

provide appropriate value for 'T'
'Real' return 'zero(T)' and 'AbstractString' returns '""'

If user wants different null value for 'T' override 'null_value(::Type{T})' method

"""
null_value(p::Pointer) = null_value(eltype(p))
null_value(::Type{T}) where T = missing
function null_value(::Type{T}) where T <: Array
    eltype(T) <: Real ? eltype(T)[] :
    eltype(T) <: AbstractString ? eltype(T)[] :
    Any[]
end

for T in (Dict, OrderedDict)
    @eval begin
        function $T{K,V}(kv::Pair{<:Pointer,V}...) where K<:Pointer where V
            $T{String,Any}()
        end

        Base.haskey(dict::$T{K,V}, p::Pointer) where {K, V} = haskey_by_pointer(dict, p)
        Base.getindex(dict::$T{K,V}, p::Pointer) where {K, V} = getindex_by_pointer(dict, p)
        Base.setindex!(dict::$T{K,V}, v, p::Pointer) where {K, V} = setindex_by_pointer!(dict, v, p)
        Base.get(dict::$T{K,V}, p::Pointer, default) where {K, V} = get_by_pointer(dict, p, default)

        # Base.setindex!(dict::$T{K,V}, v, p::Pointer) where {K <: Integer, V} = setindex_by_pointer!(dict, v, p)
    end
end
Base.getindex(A::AbstractArray, p::Pointer{Any}) = getindex_by_pointer(A, p)
Base.haskey(A::AbstractArray, p::Pointer) = getindex_by_pointer(A, p)

function Base.unique(arr::Array{Pointer, N}) where N
    out = deepcopy(arr)
    if isempty(arr)
        return out
    end

    pointers = getfield.(arr, :token)
    if allunique(pointers)
        return out
    end

    delete_target = Int[]
    @inbounds for p in pointers
        indicies = findall(el -> el == p, pointers)
        if length(indicies) > 1
            append!(delete_target, indicies[1:end-1])
        end
    end
    deleteat!(out, unique(delete_target))
end

haskey_by_pointer(collection, p::Pointer{Nothing}) = true
function haskey_by_pointer(collection, p::Pointer)::Bool
    b = true
    val = collection
    @inbounds for (i, k) in enumerate(p.token)
        if haskey_by_pointer(val, k)
            val = getindex(val, k)
        else
            b = false
            break
        end
    end
    return b
end
function haskey_by_pointer(collection, k)::Bool
    b = false
    if isa(collection, Array)
        if isa(k, Integer)
            if length(collection) >= k
                b = true
            end
        end
    else
        if !isa(k, Integer)
            if haskey(collection, k)
                b = true
            end
        end
    end
    return b
end

function getindex_by_pointer(collection, p::Pointer{Nothing})
    collection
end
function getindex_by_pointer(collection, p::Pointer)
    getindex_by_pointer(collection, p.token)
end

function getindex_by_pointer(collection, tokens::Tuple{<:Any})
    getindex(collection, tokens[1])
end
function getindex_by_pointer(collection, tokens::Tuple{<:Any, <:Any})
    getindex(getindex(collection, tokens[1]), tokens[2])
end
function getindex_by_pointer(collection, tokens::Tuple{<:Any, <:Any, <:Any})
    getindex(getindex(getindex(collection, tokens[1]), tokens[2]), tokens[3])
end
function getindex_by_pointer(collection, tokens::Tuple{<:Any, <:Any, <:Any, <:Any})
    getindex(getindex(getindex(getindex(collection, tokens[1]), tokens[2]), tokens[3]), tokens[4])
end
function getindex_by_pointer(collection, tokens::Tuple{<:Any, <:Any, <:Any, <:Any, <:Any})
    getindex(getindex(getindex(getindex(getindex(collection, tokens[1]), tokens[2]), tokens[3]), tokens[4]), tokens[5])
end
function getindex_by_pointer(collection, tokens::Tuple{<:Any, <:Any, <:Any, <:Any, <:Any, <:Any})
    getindex(getindex(getindex(getindex(getindex(getindex(collection, tokens[1]), tokens[2]), tokens[3]), tokens[4]), tokens[5]), tokens[6])
end
function getindex_by_pointer(collection, tokens::Tuple)
    val = getindex_by_pointer(collection, tokens[1:6])
    for i in 7:length(tokens)
        val = getindex(val, tokens[i])
    end
    val
end

function get_by_pointer(collection, p::Pointer, default)
    if haskey_by_pointer(collection, p)
        getindex_by_pointer(collection, p)
    else
        default
    end
end

function setindex_by_pointer!(collection::T, v, p::Pointer{U}) where {T <: AbstractDict, U}
    v = ismissing(v) ? null_value(p) : v
    if !isa(v, U) &&
        try
            v = convert(eltype(p), v)
        catch e
            msg = isa(v, Array) ? "Vector" : "Any"
            error("$v is not valid value for $p use '::$msg' if you don't need static type")
            throw(e)
        end
    end
    prev = collection

    @inbounds for (i, k) in enumerate(p.token)
        if typeof(prev) <: AbstractDict
            DT = typeof(prev)
        else
            DT = OrderedDict{String, Any}
        end

        if isa(prev, Array)
            if !isa(k, Integer)
                throw(MethodError(setindex!, k))
            end
            grow_array!(prev, k)
        else
            if isa(k, Integer)
                throw(MethodError(setindex!, k))
            end
            if !haskey(prev, k)
                setindex!(prev, missing, k)
            end
        end

        if i < length(p)
            tmp = getindex(prev, k)
            if ismissing(tmp)
                next_key = p.token[i+1]
                if isa(next_key, Integer)
                    new_data = Array{Any,1}(missing, next_key)
                else
                    new_data = DT(next_key => missing)
                end
                setindex!(prev, new_data, k)
            end
            prev = getindex(prev, k)
        end
    end
    setindex!(prev, v, p.token[end])
end

function grow_array!(arr::Array{T, N}, target_size) where T where N
    x = target_size - length(arr)
    if x > 0
        if T <: Real
            new_arr = similar(arr, x)
            new_arr .= zero(T)
        elseif T == Any
            new_arr = similar(arr, x)
            new_arr .= missing
        else
            new_arr = Array{Union{T, Missing}}(undef, x)
            new_arr .= missing
        end
        append!(arr, new_arr)
    end
    return arr
end

Base.length(x::Pointer) = length(x.token)
Base.eltype(x::Pointer{T}) where T = T

function Base.show(io::IO, x::Pointer{T}) where T
    print(io,
    "JSONPointer{", T, "}(\"/", join(x.token, "/"), "\")")
end

function Base.show(io::IO, x::Pointer{Nothing})
    print(io, "JSONPointer{Nothing}(\"\")")
end


text:
@testset "Problem" begin

    # Test Penalty
    T = Float64
    pen0 = Penalty{T}(SVector{1,T}(1.0), SVector{1,T}(1.0))
    pen1 = Penalty(1.0)
    @test pen0.ρ == pen1.ρ
    @test pen0.ρ_trial == pen1.ρ_trial

    # Test GameProblem
    T = Float64
    N = 10
    dt = 0.1
    p = 3
    model = UnicycleGame(p=p)
    probsize = ProblemSize(N,model)
    x0 = rand(SVector{model.n,T})
    opts = Options()

    Q = [Diagonal(rand(SVector{model.ni[i],T})) for i=1:p]
    R = [Diagonal(rand(SVector{model.mi[i],T})) for i=1:p]
    xf = [i*ones(SVector{model.ni[i],T}) for i=1:p]
    uf = [2i*ones(SVector{model.mi[i],T}) for i=1:p]
    game_obj = GameObjective(Q,R,xf,uf,N,model)

    game_con = GameConstraintValues(probsize)
    prob = GameProblem(N, dt, x0, model, opts, game_obj, game_con)
    @test typeof(prob) <: GameProblem

end


text:
@testset "Iteration" begin
    dna_seq = dna"ACTG"
    dna_vec = [DNA_A, DNA_C, DNA_T, DNA_G]
    @test all([nt === dna_vec[i] for (i, nt) in enumerate(dna_seq)])

    rna_seq = rna"ACUG"
    rna_vec = [RNA_A, RNA_C, RNA_U, RNA_G]
    @test all([nt === rna_vec[i] for (i, nt) in enumerate(rna_seq)])

    aa_seq = aa"ARNPS"
    aa_vec = [AA_A, AA_R, AA_N, AA_P, AA_S]
    @test all([aa == aa_vec[i] for (i, aa) in enumerate(aa_seq)])
end


text:
using CUDArt

const libnvrtc = Libdl.find_library(["libnvrtc"])

const saxpy = """
extern "C" __global__
void saxpy(float a, float *x, float *y, float *out, size_t n)
{
  size_t tid = blockIdx.x * blockDim.x + threadIdx.x;
  if (tid < n) {
    out[tid] = a * x[tid] + y[tid];
  }
}
"""

const Cptr = Ptr{Nothing}

progP = Cptr[1]

ccall((:nvrtcCreateProgram,libnvrtc),Cint,(Ptr{Cptr},Ptr{Cchar},Ptr{Cchar},Cint,Cptr,Cptr),progP,saxpy,"saxpy.cu",Cint(0),C_NULL,C_NULL)

prog = progP[1]

ccall((:nvrtcCompileProgram,libnvrtc),Cint,(nvrtcProgram,Cint,Cptr),prog,0,C_NULL)

ptxSizeP = Csize_t[1]

ccall((:nvrtcGetPTXSize,libnvrtc),Cint,(nvrtcProgram,Ptr{Csize_t}),prog,ptxSizeP)

ptxSize = ptxSizeP[1]
ptx = Array{Cchar}(undef,ptxSize)

ccall((:nvrtcGetPTX,libnvrtc),Cint,(nvrtcProgram,Ptr{Cchar}),prog,ptx)

ccall((:nvrtcDestroyProgram,libnvrtc),Cint,(Ptr{nvrtcProgram},),progP)

# Check out the PTX example in CUDArt to see how this is done:

# CUdevice cuDevice;
# CUcontext context;
# CUmodule module;
# CUfunction kernel;
# cuInit(0);
# cuDeviceGet(&cuDevice, 0);
# cuCtxCreate(&context, 0, cuDevice);
# cuModuleLoadDataEx(&module, ptx, 0, 0, 0);
# cuModuleGetFunction(&kernel, module, "saxpy");

n = 10
a = rand()
x = KnetArray(rand(n))
y = KnetArray(rand(n))
out = similar(x)

# cuLaunchKernel(kernel,
#                NUM_THREADS, 1, 1, // grid dim
#                NUM_BLOCKS, 1, 1, // block dim
#                0, NULL, // shared mem and stream
#                args, // arguments
#                0);


text:
module mfld1
using Elfel
using Elfel.RefShapes: RefShapeTriangle, manifdim, RefShapeInterval
using Elfel.FElements: FE, refshape
using Elfel.FElements: bfun, bfungradpar, FEH1_T3
using MeshSteward: Mesh, load, increl, baseincrel
using MeshCore: nshapes
using Elfel.FESpaces.FEFields: FEField, nterms, ndofsperterm, doftype, setebc!, gathersysvec!, ndofs
using Elfel.FESpaces.FEFields: numberfreedofs!, freedofnums, numberdatadofs!, datadofnums, highestfreedofnum, highestdatadofnum
using Test
function test()

    mesh = load(Mesh(), "mt3gen3.mesh")
    fe = FEH1_T3()

    fef = FEField(Val(2), Float64, Int64, nshapes(baseincrel(mesh).right))
    @test nterms(fef) == nshapes(baseincrel(mesh).right)
    @test ndofsperterm(fef) == 2

    # Case of no data degrees of freedom
    numberfreedofs!(fef)
    fnum, lnum, tnum = freedofnums(fef)
    numberdatadofs!(fef, lnum + 1)
    fnum, lnum, tnum = freedofnums(fef)
    @test tnum == nterms(fef) * ndofsperterm(fef)
    fnum, lnum, tnum = datadofnums(fef)
    @test tnum == 0
    @test highestfreedofnum(fef) == 42
    @test highestdatadofnum(fef) == 0

    # Case of 2 degrees of freedom prescribed
    setebc!(fef, 3, 2, 3.0)
    setebc!(fef, 5, 1, 5.0)
    numberfreedofs!(fef, 1)
    fnum, lnum, tnum = freedofnums(fef)
    numberdatadofs!(fef, lnum + 1)
    fnum, lnum, tnum = freedofnums(fef)
    @test tnum == nterms(fef) * ndofsperterm(fef) - 2
    @test fnum == 1
    @test lnum == nterms(fef) * ndofsperterm(fef) - 2
    fnum, lnum, tnum = datadofnums(fef)
    @test tnum == 2
    @test fnum == nterms(fef) * ndofsperterm(fef) - 2 + 1
    @test lnum == nterms(fef) * ndofsperterm(fef)
    @test highestfreedofnum(fef) == 40
    @test highestdatadofnum(fef) == 42

    @test doftype(fef) == Float64

    v = fill(zero(doftype(fef)), ndofs(fef))
    gathersysvec!(v, fef)
    @test v[nterms(fef) * ndofsperterm(fef) - 1] == 3.0
end
end
using .mfld1
mfld1.test()


text:
module TableShowUtils

import JSON, DataValues
import Markdown, Dates, Unicode

function printtable(io::IO, source, typename::AbstractString; force_unknown_rows=false)
    T = eltype(source)

    if force_unknown_rows
        rows = nothing
        data = Iterators.take(source, 10) |> collect
    elseif Base.IteratorSize(source) isa Union{Base.HasLength, Base.HasShape{1}}
        rows = length(source)
        data = Iterators.take(source, 10) |> collect
    else
        data_plus_one = Iterators.take(source, 11) |> collect
        if length(data_plus_one)<11
            rows = length(data_plus_one)
            data = data_plus_one
        else
            rows = nothing
            data = data_plus_one[1:10]
        end
    end

    cols = length(fieldnames(T))

    println(io, "$(rows===nothing ? "?" : rows)x$(cols) $typename")

    colnames = String.(fieldnames(eltype(source)))

    NAvalues = [r==0 ? false : DataValues.isna(data[r][c]) for r in 0:length(data), c in 1:cols]

    data = [r==0 ? colnames[c] : isa(data[r][c], AbstractString) ? data[r][c] : sprint(io->show(IOContext(io, :compact => true), data[r][c])) for r in 0:length(data), c in 1:cols]

    maxwidth = [maximum(Unicode.textwidth.(data[:,c])) for c in 1:cols]

    available_heigth, available_width = displaysize(io)
    available_width -=1

    shortened_rows = Set{Int}()

    function textwidth_based_rpad(s, n)
        l = Unicode.textwidth(s)
        m = n - l
        m <= 0 && return string(s)
        return string(s, ' '^m)
    end

    while sum(maxwidth) + (size(data,2)-1) * 3 > available_width
        if size(data,2)==1
            for r in 1:size(data,1)
                if length(data[r,1])>available_width
                    data[r,1] = data[r,1][1:nextind(data[r,1], 0, available_width-2)] * "\""
                    push!(shortened_rows, r)
                end
            end
            maxwidth[1] = available_width
            break
        else
            data = data[:,1:end-1]

            maxwidth = [maximum(length.(data[:,c])) for c in 1:size(data,2)]
        end
    end

    for c in 1:size(data,2)
        print(io, rpad(colnames[c], maxwidth[c]))
        if c<size(data,2)
            print(io, " │ ")
        end
    end
    println(io)
    for c in 1:size(data,2)
        print(io, repeat("─", maxwidth[c]))
        if c<size(data,2)
            print(io, "─┼─")
        end
    end
    for r in 2:size(data,1)
        println(io)
        for c in 1:size(data,2)

            if r in shortened_rows
                print(io, data[r,c],)
                print(io, "…")
            else
                if NAvalues[r,c]
                    printstyled(io, rpad(data[r,c], maxwidth[c]), color=:light_black)
                else
                    print(io, textwidth_based_rpad(data[r,c], maxwidth[c]))
                end
            end
            if c<size(data,2)
                print(io, " │ ")
            end
        end
    end

    if rows===nothing
        row_post_text = "more rows"
    elseif rows > size(data,1)-1
        extra_rows = rows - 10
        row_post_text = "$extra_rows more $(extra_rows==1 ? "row" : "rows")"
    else
        row_post_text = ""
    end

    if size(data,2)!=cols
        extra_cols = cols-size(data,2)
        col_post_text = "$extra_cols more $(extra_cols==1 ? "column" : "columns"): "
        col_post_text *= Base.join([colnames[cols-extra_cols+1:end]...], ", ")
    else
        col_post_text = ""
    end

    if !isempty(row_post_text) || !isempty(col_post_text)
        println(io)
        print(io,"... with ")
        if !isempty(row_post_text)
            print(io, row_post_text)
        end
        if !isempty(row_post_text) && !isempty(col_post_text)
            print(io, ", and ")
        end
        if !isempty(col_post_text)
            print(io, col_post_text)
        end
    end
end

function printHTMLtable(io, source; force_unknown_rows=false)
    colnames = String.(fieldnames(eltype(source)))

    max_elements = 10

    if force_unknown_rows
        rows = nothing
    elseif Base.IteratorSize(source) isa Union{Base.HasLength, Base.HasShape{1}}
        rows = length(source)
    else
        count_needed_plus_one =  Iterators.count(i->true, Iterators.take(source, max_elements+1))
        rows = count_needed_plus_one<max_elements+1 ? count_needed_plus_one : nothing
    end

    haslimit = get(io, :limit, true)

    # Header
    print(io, "
")
    print(io, "
")
    print(io, "
")
    for c in colnames
        print(io, "")
        print(io, c)
        print(io, "	")
    end
    print(io, "
")
    print(io, "
")

    # Body
    print(io, "
")
    count = 0
    for r in Iterators.take(source, max_elements)
        count += 1
        print(io, "
")
        for c in values(r)
            print(io, "")
            Markdown.htmlesc(io, sprint(io->show(IOContext(io, :compact => true),c)))
            print(io, "	")
        end
        print(io, "
")
    end

    if rows==nothing
        row_post_text = "... with more rows."
    elseif rows > max_elements
        extra_rows = rows - max_elements
        row_post_text = "... with $extra_rows more $(extra_rows==1 ? "row" : "rows")."
    else
        row_post_text = ""
    end

    if !isempty(row_post_text)
        print(io, "
")
        for c in colnames
            print(io, "⋮	")
        end
        print(io, "
")
    end

    print(io, "
")

    print(io, "
")

    if !isempty(row_post_text)
        print(io, "
")
        Markdown.htmlesc(io, row_post_text)
        print(io, "
")
    end
end

Base.Multimedia.istextmime(::MIME{Symbol("application/vnd.dataresource+json")}) = true

julia_type_to_schema_type(::Type{T}) where {T} = "string"
julia_type_to_schema_type(::Type{T}) where {T<:AbstractFloat} = "number"
julia_type_to_schema_type(::Type{T}) where {T<:Integer} = "integer"
julia_type_to_schema_type(::Type{T}) where {T<:Bool} = "boolean"
julia_type_to_schema_type(::Type{T}) where {T<:Dates.Time} = "time"
julia_type_to_schema_type(::Type{T}) where {T<:Dates.Date} = "date"
julia_type_to_schema_type(::Type{T}) where {T<:Dates.DateTime} = "datetime"
julia_type_to_schema_type(::Type{T}) where {T<:AbstractString} = "string"
julia_type_to_schema_type(::Type{T}) where {S, T<:DataValues.DataValue{S}} = julia_type_to_schema_type(S)

own_json_formatter(io, x) = JSON.print(io, x)
own_json_formatter(io, x::DataValues.DataValue) = DataValues.isna(x) ? JSON.print(io,nothing) : own_json_formatter(io, x[])

function printdataresource(io::IO, source)
    if Base.IteratorEltype(source) isa Base.EltypeUnknown
        first_el = first(source)
        col_names = String.(propertynames(first_el))
        col_types = [fieldtype(typeof(first_el), i) for i=1:length(col_names)]
    else
        col_names = String.(fieldnames(eltype(source)))
        col_types = [fieldtype(eltype(source), i) for i=1:length(col_names)]
    end
    schema = Dict("fields" => [Dict("name"=>string(i[1]), "type"=>julia_type_to_schema_type(i[2])) for i in zip(col_names, col_types)])

    print(io, "{")
    JSON.print(io, "schema")
    print(io, ":")
    JSON.print(io,schema)
    print(io,",")
    JSON.print(io, "data")
    print(io, ":[")

    for (row_i, row) in enumerate(source)
        if row_i>1
            print(io, ",")
        end

        print(io, "{")
        for col in 1:length(col_names)
            if col>1
                print(io, ",")
            end
            JSON.print(io, col_names[col])
            print(io, ":")
            # TODO This is not type stable, should really unroll the loop in a generated function
            own_json_formatter(io, row[col])
        end
        print(io, "}")
    end

    print(io, "]}")
end

end # module


text:
d = readdir()

for f in d
    if isfile(f) && occursin(r"\.jl$", f) && f != "runexamples.jl"
        println("\n\n*** Running: $f ***")
        run(`julia $f`)
    end
end


text:
using SecureIO
using Sockets
using Test
using Serialization

#import SecureIO.Socket
#Socket(socket::IOBuffer) = Socket(socket,write,take!)

# I  need to find why write and take! does not work for the socket
#import Serialization
#Socket(socket::TCPSocket) = Socket(socket,Serialization.serialize,Serialization.deserialize)

#io = Socket(IOBuffer())
io = IOBuffer()

key = "Password"
st = SecureSocket(io,key,size=32)

msg = ("Hello","World")
serialize(st,msg)
@test msg==deserialize(st)

# Inception/Onion

io = IOBuffer()

key1 = "Password1"
st1 = SecureSocket(io,key1)

key2 = "Password2"
st2 = SecureSocket(st1,key2,size=64)

msg = ("Hello","World")
serialize(st2,msg)
@test msg==deserialize(st2)

# Checking if TCP/IP sockets works

server = listen(2000)

@sync begin
    @async global serversocket = accept(server)
    global slavesocket = connect(2000)
end

key = "Password"

msg = ("Hello","World")

stserver = SecureSocket(serversocket,key,size=64)
serialize(stserver,msg)

stslave = SecureSocket(slavesocket,key)
@test msg==deserialize(stslave)

# Let's now test asyncchronicity

@async serialize(stserver,msg)
@async serialize(stslave,msg)

@test deserialize(stserver)==msg
@test deserialize(stslave)==msg

# Closing

@test isopen(stslave)==true
close(stslave)
@test isopen(stslave)==false

close(server)