text:
export SumProductNetwork
export SPNNode, Node, Leaf, SumNode, ProductNode
export FiniteSumNode, FiniteProductNode
export IndicatorNode, UnivariateNode
export MultivariateNode

export root, leaves

# Abstract definition of an SumProductNetwork node.
abstract type SPNNode end
abstract type Node <: SPNNode end
abstract type SumNode <: Node end
abstract type ProductNode <: Node end
abstract type Leaf <: SPNNode end

header(node::SPNNode) = "$(summary(node))($(node.id))"

function Base.show(io::IO, node::SPNNode)
    println(io, header(node))
    if hasweights(node)
        println(io, "\tweights = $(weights(node))")
        println(io, "\tnormalized = $(isnormalized(node))")
    end
    if hasscope(node)
        println(io, "\tscope = $(scope(node))")
    else
        println(io, "\tNo scope set!")
    end
    if hasobs(node)
        println(io, "\tassigns = $(obs(node))")
    end
end

function Base.show(io::IO, node::Leaf)
    println(io, header(node))
    println(io, "\tscope = $(scope(node))")
    println(io, "\tparameters = $(params(node))")
end

struct SumProductNetwork
    root::Node
    nodes::Vector{<:SPNNode}
    leaves::Vector{<:SPNNode}
    idx::Dict{Symbol,Int}
    topological_order::Vector{Int}
    layers::Vector{AbstractVector{SPNNode}}
    info::Dict{Symbol,<:Real}
end

function SumProductNetwork(root::Node)
    nodes = getOrderedNodes(root)
    leaves = filter(n -> isa(n, Leaf), nodes)
    idx = Dict(n.id => indx for (indx, n) in enumerate(nodes))
    toporder = collect(1:length(nodes))

    maxdepth = depth(root)
    nodedepth = map(n -> depth(n), nodes)
    layers = Vector{Vector{SPNNode}}(undef, maxdepth+1)
    for d in 0:maxdepth
        layers[d+1] = nodes[findall(nodedepth .== d)]
    end

    return SumProductNetwork(root, nodes, leaves, idx, toporder, layers, Dict{Symbol, Real}())
end

Base.keys(spn::SumProductNetwork) = keys(spn.idx)
Base.values(spn::SumProductNetwork) = spn.nodes
Base.getindex(spn::SumProductNetwork, i...) = getindex(spn.nodes, spn.idx[i...])
Base.setindex!(spn::SumProductNetwork, v, i...) = setindex!(spn.nodes, v, spn.idx[i...])
Base.length(spn::SumProductNetwork) = length(spn.nodes)
function Base.show(io::IO, spn::SumProductNetwork)
    println(io, summary(spn))
    println(io, "\t#nodes = $(length(spn))")
    println(io, "\t#leaves = $(length(spn.leaves))")
    println(io, "\tdepth = $(length(spn.layers))")
end
leaves(spn::SumProductNetwork) = spn.leaves
root(spn::SumProductNetwork) = spn.root

"""
   FiniteSumNode <: SumNode

A sum node computes a convex combination of its weight and the pdf's of its children.

## Usage:

```julia
node = FiniteSumNode{Float64}(;D=4, N=1)
add!(node, ..., log(0.5))
add!(node, ..., log(0.5))
logpdf(node, rand(4))
```

"""
mutable struct FiniteSumNode{T<:Real} <: SumNode
    id::Symbol
    parents::Vector{<:Node}
    children::Vector{<:SPNNode}
    logweights::Vector{T}
    scopeVec::BitArray{1}
    obsVec::BitArray{1}
end

function FiniteSumNode{T}(;D=1, N=1, parents::Vector{<:Node}=Node[]) where {T<:Real}
    return FiniteSumNode{T}(gensym(:sum), parents, SPNNode[], T[], falses(D), falses(N))
end
function FiniteSumNode(;D=1, N=1, parents::Vector{<:Node}=Node[])
    return FiniteSumNode{Float64}(;D=D, N=N, parents=parents)
end

eltype(::Type{FiniteSumNode{T}}) where {T<:Real} = T
eltype(n::SPNNode) = eltype(typeof(n))

"""
   FiniteProductNode <: ProductNode

A product node computes a product of the pdf's of its children.

## Usage:

```julia
node = FiniteProductNode(;D=4, N=1)
add!(node, ...)
add!(node, ...)
logpdf(node, rand(4))
```

"""
mutable struct FiniteProductNode <: ProductNode
    id::Symbol
    parents::Vector{<:Node}
    children::Vector{<:SPNNode}
    scopeVec::BitArray{1}
    obsVec::BitArray{1}
end

function FiniteProductNode(;D=1, N=1, parents::Vector{<:Node} = Node[])
    return FiniteProductNode(gensym(:prod), parents, SPNNode[], falses(D), falses(N))
end

"""
   IndicatorNode <: Leaf

An indicator node evaluates an indicator function.

## Usage:

```julia
value = 1
dimension = 1
node = IndicatorNode(value, dimension)
logpdf(node, [1, 2, 1]) # == 0.0
logpdf(node, [2, 2, 1]) # == -Inf
```

"""
mutable struct IndicatorNode <: Leaf
    id::Symbol
    value::Int
    scope::Int
    parents::Vector{<:Node}
end

function IndicatorNode(value::Int, dim::Int; parents::Vector{<:Node} = Node[])
    return IndicatorNode(gensym(:indicator), value, dim, parents)
end

function Base.isequal(n1::IndicatorNode, n2::IndicatorNode)
    return (n1.value == n2.value) && (n1.scope == n2.scope)
end
params(n::IndicatorNode) = (n.value)

"""
   UnivariateNode <: Leaf

A univariate node evaluates the logpdf of its univariate distribution function.

## Usage:

```julia
distribution = Normal()
dimension = 1
node = UnivariateNode(distribution, dimension)
logpdf(node, rand(2)) # == logpdf(Normal(), rand(2))
```

"""
mutable struct UnivariateNode <: Leaf
    id::Symbol
    parents::Vector{<:Node}
    dist::UnivariateDistribution
    scope::Int
end

function UnivariateNode(distribution::T, dim::Int; parents::Vector{<:Node} = Node[]) where {T<:UnivariateDistribution}
    return UnivariateNode(gensym(:univ), parents, distribution, dim)
end
params(n::UnivariateNode) = Distributions.params(n.dist)

"""
   MultivariateNode <: Leaf

A multivariate node evaluates the logpdf of its multivariate distribution function.

## Usage:

```julia
distribution = MvNormal()
dimensions = [1, 2]
node = UnivariateNode(distribution, dimensions)
logpdf(node, rand(2)) # == logpdf(MvNormal(), rand(2))
```

"""
mutable struct MultivariateNode <: Leaf
    id::Symbol
    parents::Vector{<:Node}
    dist::MultivariateDistribution
    scope::Vector{Int}
end

function MultivariateNode(distribution::T, dims::Vector{Int}; parents::Vector{<:Node} = Node[]) where {T<:MultivariateDistribution}
    return MultivariateNode(gensym(:multiv), parents, distribution, dims)
end
params(n::MultivariateNode) = Distributions.params(n.dist)


text:
abstract type abstract_alg_history end

export abstract_alg_history, get_col, generic_alg_history, alg_history2

using NLPModels, JuMP

struct alg_history2 <: abstract_alg_history
    t::Int64
    step_type::String
    eta::Class_reduction_factors
    ls_info_num_steps::Int64
    ls_info_step_size_P::Float64
    ls_info_step_size_D::Float64
    dir_x_norm::Float64
    dir_y_norm::Float64
    dir_s_norm::Float64
    kkt_ratio::Float64
    mu::Float64
    fval::Float64
    dual_scaled::Float64
    norm_grad_lag::Float64
    primal_residual::Float64
    con_vio::Float64
    comp::Float64
    sy_inf::Float64
    comp_ratio::Float64
    sy_mean::Float64
    farkas::Float64
    delta::Float64
    eval_merit_function::Float64
    eval_phi::Float64
    eval_grad_phi::Float64
    y_norm::Float64
    x_norm::Float64
    tot_num_fac::Int64
    num_fac_inertia::Int64
    strict_comp::Float64

    #=function alg_history()
      return new()
  end=#
end

function major_its_only(hist::Array{alg_history2,1})
    # reduce the history list so it only includes major iterations
    its = get_col(hist,:t);
    keep_these = Array{Int64,1}()
    for i = 1:(length(its)-1)
        if its[i+1] != its[i]
            push!(keep_these,i)
        end
    end
    push!(keep_these,length(its))
    return hist[keep_these]
end

mutable struct generic_alg_history <: abstract_alg_history
  t::Int64
  #mu::Float64
  fval::Float64
  #dual_scaled::Float64
  norm_grad_lag::Float64
  sy_inf::Float64
  #comp_ratio::Float64
  #sy_mean::Float64
  #primal_residual::Float64
  #farkas::Float64
  #delta::Float64
  #eval_merit_function::Float64
  #eval_phi::Float64
  #eval_grad_phi::Float64
  mu::Float64
  primal_residual::Float64
  con_vio::Float64
  y_norm::Float64
  x_norm::Float64
  strict_comp::Float64
end

function get_col(arr::Array,colname::Symbol)
    col = nothing
    for i = 1:length(arr)
        val = getfield(arr[i],colname)
        if i == 1
            col = Array{typeof(val),1}();
        end
        push!(col,val)
    end
    return col
end

function head_progress()
  println( pd("it",3), pd("step", 6), pd("eta",8), pd("α_P"), pd("α_D"), pd("ls",3), pd("|dx|"), pd("|dy|"), pd("N err"), "|", pd("mu"), pd("dual"), pd("primal"), pd("cmp scaled"), pd("infeas?"), "|", pd("delta"), pd("#fac",6), pd("|x|"), pd("|y|"), pd("∇phi"), pd("phi") )
end

function record_progress_first_it!(progress::Array{alg_history2,1}, iter::Class_iterate, kkt_solver::abstract_KKT_system_solver, par::Class_parameters, display::Bool)
    record_progress!(progress, 0, "it0", iter, kkt_solver, Blank_ls_info(), Class_reduction_factors(),  0, 0, par, display)
end

function record_progress!(progress::Array{alg_history2,1}, t::Int64, step_type::String, iter::Class_iterate, kss::abstract_KKT_system_solver,  ls_info::abstract_ls_info, eta::Class_reduction_factors, num_fac_inertia::Int64, tot_num_fac::Int64, par::Class_parameters, display::Bool)
    dir_y_norm = LinearAlgebra.norm(kss.dir.y,Inf);
    dir_x_norm = LinearAlgebra.norm(kss.dir.x,Inf);
    dir_s_norm = norm(kss.dir.s,Inf);
    ls_info_num_steps = ls_info.num_steps
    ls_info_step_size_P = ls_info.step_size_P
    ls_info_step_size_D = ls_info.step_size_D
    kkt_err = kss.kkt_err_norm;
    mu = get_mu(iter)
    fval = get_fval(iter)
    sy_mean = dot(iter.point.s,iter.point.y)/length(iter.point.s)
    norm_grad_lag = LinearAlgebra.norm(eval_grad_lag(iter, 0.0),Inf)
    norm_grad_lag_mod = LinearAlgebra.norm(eval_grad_lag(iter, iter.point.mu),Inf)
    dual_scaled = scaled_dual_feas(iter, par)
    primal_residual = LinearAlgebra.norm(get_primal_res(iter),Inf)
    con_vio = get_max_vio(iter)
    val_comp = LinearAlgebra.norm(comp(iter),Inf)
    sy_inf = LinearAlgebra.norm(iter.point.s .* iter.point.y,Inf)
    comp_ratio = comp_ratio_max(iter) * par.ls.comp_feas_agg #LinearAlgebra.norm(comp(iter),Inf)
    farkas = eval_farkas(iter)
    delta = get_delta(iter)
    val_merit_function = eval_merit_function(iter, par)
    val_phi = eval_phi(iter,iter.point.mu)
    val_grad_phi = LinearAlgebra.norm(eval_grad_phi(iter, iter.point.mu),Inf)
    y_norm = LinearAlgebra.norm(get_y(iter),Inf)
    x_norm = LinearAlgebra.norm(get_x(iter),Inf)
    tot_num_fac = tot_num_fac
    num_fac_inertia = num_fac_inertia
    kkt_ratio = kss.kkt_err_norm.ratio
    strict_comp = minimum(iter.point.s+iter.point.y)

    hist = alg_history2(t::Int64,
    step_type::String,
    eta::Class_reduction_factors,
    ls_info_num_steps::Int64,
    ls_info_step_size_P::Float64,
    ls_info_step_size_D::Float64,
    dir_x_norm::Float64,
    dir_y_norm::Float64,
    dir_s_norm::Float64,
    kkt_ratio::Float64,
    mu::Float64,
    fval::Float64,
    dual_scaled::Float64,
    norm_grad_lag::Float64,
    primal_residual::Float64,
    con_vio::Float64,
    val_comp::Float64,
    sy_inf::Float64,
    comp_ratio::Float64,
    sy_mean::Float64,
    farkas::Float64,
    delta::Float64,
    val_merit_function::Float64,
    val_phi::Float64,
    val_grad_phi::Float64,
    y_norm::Float64,
    x_norm::Float64,
    tot_num_fac::Int64,
    num_fac_inertia::Int64,
    strict_comp::Float64)

    push!(progress, hist)

    if display
      println(pd(t,5), pd(step_type[1], 3), rd(eta.mu),  rd(ls_info_step_size_P),  rd(ls_info_step_size_D), pd(ls_info_num_steps,2), rd(dir_x_norm), rd(dir_y_norm), rd(kkt_ratio), "|", rd(mu), rd(dual_scaled), rd(primal_residual), rd(comp_ratio), rd(farkas), "|", rd(delta), pd(num_fac_inertia,3), pd(tot_num_fac,3), rd(x_norm), rd(y_norm), rd(val_grad_phi), rd(val_merit_function, 5))
    end
end

ext: jl


text:
##############################################################################
##
## Find common prefixes (up to lim. -1 means Inf)
##############################################################################

function common_prefix(s1::AbstractString, s2::AbstractString, lim::Integer = -1)
    x1 = iterate(s1)
    x2 = iterate(s2)
    l = 0
    while (x1 !== nothing) && (x2 !== nothing) && (l < lim || lim < 0)
        ch1, state1 = x1
        ch2, state2 = x2
        ch1 != ch2 && break
        x1 = iterate(s1, state1)
        x2 = iterate(s2, state2)
        l += 1
    end
    return l, x1, x2
end

##############################################################################
##
## Hamming
##
##############################################################################

function evaluate(dist::Hamming, s1::AbstractString, s2::AbstractString)
    out = 0
    for (ch1, ch2) in zip(s1, s2)
        out += ch1 != ch2
    end
    out += abs(length(s2) - length(s1))
    return out
end

##############################################################################
##
## Levenshtein
## Source: http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html
##
##############################################################################

struct Levenshtein <: SemiMetric end

function evaluate(dist::Levenshtein, s1::AbstractString, s2::AbstractString)
    # prefix common to both strings can be ignored
    s2, len2, s1, len1 = reorder(s1, s2)
    k, x1, x2start = common_prefix(s1, s2)
    (x1 == nothing) && return len2 - k
    # distance initialized to first row of matrix
    # => distance between "" and s2[1:i}
    v0 = collect(1:(len2 - k))
    current = 0
    i1 = 1
    while x1 !== nothing
        ch1, state1 = x1
        left = (i1 - 1)
        current = (i1 - 1)
        i2 = 1
        x2 = x2start
        while x2 !== nothing
            ch2, state2 = x2
            #  update
            above, current, left = current, left, v0[i2]
            if ch1 != ch2
                # substitution
                current = min(current + 1,
                                above + 1,
                                left + 1)
            end
            v0[i2] = current
            x2 = iterate(s2, state2)
            i2 += 1
        end
        x1 = iterate(s1, state1)
        i1 += 1
    end
    return current
end

##############################################################################
##
## Damerau Levenshtein
## Source: http://blog.softwx.net/2015/01/optimizing-damerau-levenshtein_15.html
##
##############################################################################

struct DamerauLevenshtein <: SemiMetric end

function evaluate(dist::DamerauLevenshtein, s1::AbstractString, s2::AbstractString)
    s2, len2, s1, len1 = reorder(s1, s2)
    # prefix common to both strings can be ignored
    k, x1, x2start = common_prefix(s1, s2)
    (x1 == nothing) && return len2 - k
    v0 = collect(1:(len2 - k))
    v2 = similar(v0)
    i1 = 1
    current = i1
    prevch1, = x1
    while (x1 !== nothing)
        ch1, state1 = x1
        left = (i1 - 1)
        current = i1
        nextTransCost = 0
        prevch2, = x2start
        x2 = x2start
        i2 = 1
        while (x2 !== nothing)
            ch2, state2 = x2
            above = current
            thisTransCost = nextTransCost
            nextTransCost = v2[i2]
            # cost of diagonal (substitution)
            v2[i2] = current = left
            # left now equals current cost (which will be diagonal at next iteration)
            left = v0[i2]
            if ch1 != ch2
                # insertion
                if left < current
                    current = left
                end
                # deletion
                if above < current
                    current = above
                end
                current += 1
                if i1 != 1 && i2 != 1 && ch1 == prevch2 && prevch1 == ch2
                    thisTransCost += 1
                    if thisTransCost < current
                        current = thisTransCost
                    end
                end
            end
            v0[i2] = current
            x2 = iterate(s2, state2)
            i2 += 1
            prevch2 = ch2
        end
        x1 = iterate(s1, state1)
        i1 += 1
        prevch1 = ch1
    end
    return current
end

##############################################################################
##
## Jaro
## http://alias-i.com/lingpipe/docs/api/com/aliasi/spell/JaroWinklerDistance.html
##############################################################################

struct Jaro <: SemiMetric end

function evaluate(dist::Jaro, s1::AbstractString, s2::AbstractString)
    s2, len2, s1, len1 = reorder(s1, s2)
    # if both are empty, m = 0 so should be 1.0 according to wikipedia. Add this line so that not the case
    len2 == 0 && return 0.0
    maxdist = max(0, div(len2, 2) - 1)
    flag = fill(false, len2)
    prevstate1 = firstindex(s1)
    i1_match = prevstate1 * ones(Int, len1)
    #  m counts matching characters
    m = 0
    i1 = 1
    i2 = 1
    x1 = iterate(s1)
    x2 = iterate(s2)
    while (x1 !== nothing)
        ch1, state1 = x1
        if i2 <= i1 - maxdist - 1
            ch2, state2 = x2
            i2 += 1
            x2 = iterate(s2, state2)
        end
        i2curr = i2
        x2curr = x2
        while (x2curr !== nothing)
            (i2curr > i1 + maxdist) && break
            ch2, state2 = x2curr
            if ch1 == ch2 && !flag[i2curr]
                m += 1
                flag[i2curr] = true
                i1_match[m] = prevstate1
                break
            end
            x2curr = iterate(s2, state2)
            i2curr += 1
        end
        x1 = iterate(s1, state1)
        i1 += 1
        prevstate1 = state1
    end
    # count t transpotsitions
    t = 0
    i1 = 0
    i2 = 0
    for ch2 in s2
        i2 += 1
        if flag[i2]
            i1 += 1
            t += ch2 != iterate(s1, i1_match[i1])[1]
        end
    end
    m == 0 && return 1.0
    score = (m / len1 + m / len2 + (m - t/2) / m) / 3.0
    return 1.0 - score
end


text:
module ConfusionTest

using Test
using ForwardDiff

using LinearAlgebra

# Perturbation Confusion (Issue #83) #
#------------------------------------#

D = ForwardDiff.derivative

@test D(x -> x * D(y -> x + y, 1), 1) == 1
@test ForwardDiff.gradient(v -> sum(v) * D(y -> y * norm(v), 1), [1]) == ForwardDiff.gradient(v -> sum(v) * norm(v), [1])

const A = rand(10,8)
y = rand(10)
x = rand(8)

@test A == ForwardDiff.jacobian(x) do x
    ForwardDiff.gradient(y) do y
        dot(y, A*x)
    end
end

# Issue #238                         #
#------------------------------------#

m,g = 1, 9.8
t = 1
q = [1,2]
q̇ = [3,4]
L(t,q,q̇) = m/2 * dot(q̇,q̇) - m*g*q[2]

∂L∂q̇(L, t, q, q̇) = ForwardDiff.gradient(a->L(t,q,a), q̇)
Dqq̇(L, t, q, q̇) = ForwardDiff.jacobian(a->∂L∂q̇(L,t,a,q̇), q)
@test Dqq̇(L, t, q, q̇)  == fill(0.0, 2, 2)

q = [1,2]
p = [5,6]
function Legendre_transformation(F, w)
    z = fill(0.0, size(w))
    M = ForwardDiff.hessian(F, z)
    b = ForwardDiff.gradient(F, z)
    v = cholesky(M)\(w-b)
    dot(w,v) - F(v)
end
function Lagrangian2Hamiltonian(Lagrangian, t, q, p)
    L = q̇ -> Lagrangian(t, q, q̇)
    Legendre_transformation(L, p)
end

Lagrangian2Hamiltonian(L, t, q, p)
@test ForwardDiff.gradient(a->Lagrangian2Hamiltonian(L, t, a, p), q) == [0.0,g]

#267: let scoping
@noinline f83a(z, x) = x[1]
z83a = ([(1, (2), [(3, (4, 5, [1, 2, (3, (4, 5), [5])]), (5))])])
let z = z83a
    g = x -> f83a(z, x)
    h = x -> g(x)
    @test ForwardDiff.hessian(h, [1.]) == zeros(1, 1)
end

end # module


text:
# This file is a part of BAT.jl, licensed under the MIT License (MIT).

# ToDO: Use Distributions.ArrayLikeVariate and merge with standard uniform
# and normal dists into a single standard-dist struct
# StandardDist{Normal|Uniform,T,N}. Propose inclusion into Distributions.

"""
    StandardUvUniform{T<:Real} <: Distributions.Distribution{Univariate,Continuous}

A standard uniform distribution between zero and one.

Constructor:
```
    StandardUvUniform()
    StandardUvUniform{T<:Real}()
```
"""
struct StandardUvUniform{T<:Real} <: Distributions.Distribution{Univariate,Continuous}
end

StandardUvUniform() = StandardUvUniform{Float64}()

Distributions.Uniform(::StandardUvUniform{T}) where T = Uniform{T}(zero(T), one(T))
Base.convert(::Type{Distributions.Uniform}, d::StandardUvUniform) = Uniform(d)

Base.minimum(::StandardUvUniform{T}) where T = zero(T)
Base.maximum(::StandardUvUniform{T}) where T = one(T)

StatsBase.params(::StandardUvUniform{T}) where T = (zero(T), one(T))
@inline Distributions.partype(::StandardUvUniform{T}) where T = T

Distributions.location(::StandardUvUniform{T}) where T = zero(T)
Distributions.scale(::StandardUvUniform{T}) where T = one(T)

Base.eltype(::Type{StandardUvUniform{T}}) where T = T

Statistics.mean(d::StandardUvUniform{T}) where T = convert(float(T), 1//2)
StatsBase.median(d::StandardUvUniform{T}) where T = mean(d)
StatsBase.mode(d::StandardUvUniform{T}) where T = mean(d)
StatsBase.modes(d::StandardUvUniform{T}) where T = Fill(mode(d), 0)

Statistics.var(d::StandardUvUniform{T}) where T = convert(float(T), 1//12)
StatsBase.std(d::StandardUvUniform{T}) where T = sqrt(var(d))
StatsBase.skewness(d::StandardUvUniform{T}) where T = zero(T)
StatsBase.kurtosis(d::StandardUvUniform{T}) where T = convert(T, -6//5)

StatsBase.entropy(d::StandardUvUniform{T}) where T = zero(T)

function Distributions.logpdf(d::StandardUvUniform{T}, x::U) where {T,U<:Real}
    R = float(promote_type(T,U))
    ifelse(insupport(d, x), R(0), R(-Inf))
end

function Distributions.pdf(d::StandardUvUniform{T}, x::U) where {T,U<:Real}
    R = promote_type(T,U)
    ifelse(insupport(d, x), one(R), zero(R))
end

Distributions.logcdf(d::StandardUvUniform, x::Real) = log(cdf(d, x))

function Distributions.cdf(d::StandardUvUniform{T}, x::U) where {T,U<:Real}
    R = promote_type(T,U)
    ifelse(x < zero(U), zero(R), ifelse(x < one(U), x, one(R)))
end

Distributions.logccdf(d::StandardUvUniform, x::Real) = log(ccdf(d, x))

function Distributions.ccdf(d::StandardUvUniform{T}, x::U) where {T,U<:Real}
    y = cdf(d, x)
    one(y) - y
end

function Distributions.quantile(d::StandardUvUniform{T}, p::U) where {T,U<:Real}
   R = promote_type(T,U)
   convert(float(R), p)
end

function Distributions.cquantile(d::StandardUvUniform{T}, p::U) where {T,U<:Real}
    y = quantile(d, p)
    one(y) - y
end

Distributions.mgf(d::StandardUvUniform, t::Real) = mgf(Uniform(d), t)
Distributions.cf(d::StandardUvUniform, t::Real) = cf(Uniform(d), t)

# Distributions doesn't seem to support gradlogpdf for Uniform()
# # Distributions.gradlogpdf(d::StandardUvUniform, x::Real) = zero(T)

Base.rand(rng::AbstractRNG, d::StandardUvUniform{T}) where T = rand(rng, float(T))

Distributions.truncated(d::StandardUvUniform, l::Real, u::Real) = truncated(Uniform(d), l, u)

function Distributions.product_distribution(dists::AbstractVector{StandardUvUniform{T}}) where T
    StandardMvUniform{T}(length(eachindex(dists)))
end

"""
    StandardMvUniform{T<:Real} <: Distributions.Distribution{Multivariate,Continuous}

A standard `n`-dimensional multivariate uniform distribution, from zero
to one in each dimension.

Constructor:
```
    StandardMvUniform(n::Integer)
    StandardMvUniform{T<:Real}(n::Integer)
```
"""
struct StandardMvUniform{T<:Real} <: Distributions.Distribution{Multivariate,Continuous}
    _dim::Int
end

StandardMvUniform(dim::Integer) = StandardMvUniform{Float64}(dim)

Distributions.Product(d::StandardMvUniform{T}) where T = Distributions.Product(Fill(StandardUvUniform{T}(), length(d)))
Base.convert(::Type{Distributions.Product}, d::StandardMvUniform) = Distributions.Product(d)

function Distributions.insupport(d::StandardMvUniform, x::AbstractVector)
    length(d) == length(eachindex(x)) && all(xi -> insupport(StandardUvUniform(), xi), x)
end

Base.eltype(::Type{StandardMvUniform{T}}) where T = T

Base.length(d::StandardMvUniform{T}) where T = d._dim

@inline function Base.view(d::StandardMvUniform{T}, i::Integer) where T
    Base.@boundscheck Base.checkindex(Bool, Base.OneTo(length(d)), i) || Base.throw_boundserror(d, i)
    StandardUvUniform{T}()
end

function Base.view(d::StandardMvUniform{T}, I::AbstractArray{<:Integer}) where T
    Base.@boundscheck Base.checkindex(Bool, Base.OneTo(length(d)), I) || Base.throw_boundserror(d, I)
    StandardMvUniform{T}(length(eachindex(I)))
end

# Not applicable:
# # StatsBase.params(d::StandardMvUniform)
# # @inline Distributions.partype(d::StandardMvUniform{T})

Statistics.mean(d::StandardMvUniform{T}) where T = Fill(mean(StandardUvUniform()), length(d))
Statistics.var(d::StandardMvUniform{T}) where T = Fill(var(StandardUvUniform()), length(d))
Statistics.cov(d::StandardMvUniform{T}) where T = Diagonal(var(d))

StatsBase.mode(d::StandardMvUniform) = mean(d)
StatsBase.modes(d::StandardMvUniform) = Fill(mean(d), 0)

Distributions.invcov(d::StandardMvUniform{T}) where T = Diagonal(Fill(inv(var(StandardUvUniform())), length(d)))
Distributions.logdetcov(d::StandardMvUniform{T}) where T = logdet(cov(d))

StatsBase.entropy(d::StandardMvUniform{T}) where T = zero(T)

function Distributions._logpdf(d::StandardMvUniform{T}, x::AbstractVector{U}) where {T,U<:Real}
    R = float(promote_type(T,U))
    ifelse(insupport(d, x), R(0), R(-Inf))
end

function Distributions._pdf(d::StandardMvUniform{T}, x::AbstractVector{U}) where {T,U<:Real}
    R = promote_type(T,U)
    ifelse(insupport(d, x), one(R), zero(R))
end

# Not useful:
# # Distributions.sqmahal(d::StandardMvUniform, x::AbstractVector{<:Real})
# # Distributions.sqmahal!(r::AbstractVector{<:Real}, d::StandardMvUniform, x::AbstractMatrix{<:Real})

function Distributions.gradlogpdf(d::StandardMvUniform{T}, x::AbstractVector{U}) where {T,U<:Real}
    FillArrays.Zeros(length(d))
end

function Distributions._rand!(rng::AbstractRNG, d::StandardMvUniform, A::AbstractVector{T}) where {T<:Real}
    broadcast!(x -> rand(rng, T), A, A)
end

function Distributions._rand!(rng::AbstractRNG, d::StandardMvUniform, A::AbstractMatrix{T}) where {T<:Real}
    broadcast!(x -> rand(rng, T), A, A)
end

const StandardUniformDist = Union{StandardUvUniform, StandardMvUniform}


text:
## This file contains the exchange and exch_UV functions
# along with grid-specific methods (exch_T_N.jl, etc.)

## User Front Ends

"""
    exchange(fld::MeshArray)

Exchange / transfer data between neighboring arrays. Other methods are

    exchange(fld::MeshArray,N::Integer)
    exchange(u::MeshArray,v::MeshArray)
    exchange(u::MeshArray,v::MeshArray,N::Integer)
"""
function exchange(fld::MeshArray)
  FLD=exch_T_N(fld,1);
end

function exchange(fld::MeshArray,N::Integer)
  FLD=exch_T_N(fld,N);
end

function exchange(u::MeshArray,v::MeshArray)
  (uex,vex)=exch_UV_N(u,v,1);
end

function exchange(u::MeshArray,v::MeshArray,N::Integer)
  (uex,vex)=exch_UV_N(u,v,N);
end

## dispatch over grid types

#note: the "cs" implementation covers both cs and llc

function exch_T_N(fld,N)

if fld.grid.class=="llc"
  FLD=exch_T_N_cs(fld,N)
elseif fld.grid.class=="cs"
  FLD=exch_T_N_cs(fld,N)
elseif fld.grid.class=="ll"
  FLD=exch_T_N_ll(fld,N)
else
  error("unknown grTopo case")
end

return FLD

end

function exch_UV_N(u,v,N)

if u.grid.class=="llc"
  (uex,vex)=exch_UV_N_cs(u,v,N)
elseif u.grid.class=="cs"
  (uex,vex)=exch_UV_N_cs(u,v,N)
elseif u.grid.class=="ll"
  (uex,vex)=exch_UV_N_ll(u,v,N)
else
  error("unknown grTopo case")
end

return uex,vex

end

function exch_UV(u,v)

if u.grid.class=="llc"
  (uex,vex)=exch_UV_cs(u,v)
elseif u.grid.class=="cs"
  (uex,vex)=exch_UV_cs(u,v)
elseif u.grid.class=="ll"
  (uex,vex)=exch_UV_ll(u,v)
else
  error("unknown grTopo case")
end

return uex,vex

end

## Grid-specific implementations: ll grid case

function exch_T_N_ll(fld::MeshArray,N::Integer)

fillval=0.0

#step 1

s=size.(fld.f);
FLD=similar(fld);
FLD.f[1]=fill(fillval,s[1].+2N);
@views FLD.f[1][N+1:N+s[1][1],N+1:N+s[1][2]]=fld.f[1];

#step 2

iW=(s[1][1]-N+1:s[1][1],1:s[1][2]);
iE=(1:N,1:s[1][2]);
jW=(1:N,N+1:N+s[1][2]);
jE=(N+1+s[1][1]:2N+s[1][1],N+1:N+s[1][2]);
FLD.f[1][jW[1],jW[2]]=view(fld.f[1],iW[1],iW[2])
FLD.f[1][jE[1],jE[2]]=view(fld.f[1],iE[1],iE[2])

return FLD

end

##

function exch_UV_N_ll(fldU,fldV,N);

FLDU=exch_T_N_ll(fldU,N);
FLDV=exch_T_N_ll(fldV,N);

return FLDU,FLDV

end

##

function exch_UV_ll(fldU,fldV);

fillval=0.0

#step 1

s=size.(fldU.f);
FLDU=similar(fldU);
FLDV=similar(fldV);

FLDU.f[1]=fill(fillval,s[1][1]+1,s[1][2]);
FLDV.f[1]=fill(fillval,s[1][1],s[1][2]+1);
@views FLDU.f[1][1:s[1][1],1:s[1][2]]=fldU.f[1];
@views FLDV.f[1][1:s[1][1],1:s[1][2]]=fldV.f[1];

#step 2

FLDU.f[1][s[1][1]+1,1:s[1][2]]=view(fldU.f[1],1,1:s[1][2])

return FLDU,FLDV

end

## Grid-specific implementations: cs & llc grid case

#note: the "cs" implementation covers both cs and llc

function exch_T_N_cs(fld::MeshArray,N::Integer)

fillval=0.0

#step 1

s=size.(fld.f)
nf=fld.grid.nFaces
nf==5 ? s=vcat(s,s[3]) : nothing
tp=fld.grid.class
FLD=similar(fld)

for i=1:nf; FLD.f[i]=fill(fillval,s[i].+2N); end;
#code below yields strange, seemingly incorrect results:
#for i=1:nf; FLD.f[i]=Array{eltype(fld.f[i])}(undef,s[i].+2N); end;

#all versions below yield same @time and memory (despite diff in allocs)
for i=1:nf;
# FLD.f[i][N+1:end-N,N+1:end-N]=fld.f[i];
 @views FLD.f[i][N+1:N+s[i][1],N+1:N+s[i][2]]=fld.f[i];
end;

#step 2

(ovfW,ovfE,ovfS,ovfN,evfW,evfE,evfS,evfN)=exch_cs_viewfunctions();

for a=1:nf
(jW, jE, jS, jN)=exch_cs_target(s[a],N)
(aW,aE,aS,aN,iW,iE,iS,iN)=exch_cs_sources(a,s,N)
if !iseven(a)
 aW <= nf ? FLD.f[a][jW[1],jW[2]]=ovfW(fld.f[aW],iW[1],iW[2]) : nothing
 aE <= nf ? FLD.f[a][jE[1],jE[2]]=ovfE(fld.f[aE],iE[1],iE[2]) : nothing
 aS <= nf ? FLD.f[a][jS[1],jS[2]]=ovfS(fld.f[aS],iS[1],iS[2]) : nothing
 aN <= nf ? FLD.f[a][jN[1],jN[2]]=ovfN(fld.f[aN],iN[1],iN[2]) : nothing
else
 aW <= nf ? FLD.f[a][jW[1],jW[2]]=evfW(fld.f[aW],iW[1],iW[2]) : nothing
 aE <= nf ? FLD.f[a][jE[1],jE[2]]=evfE(fld.f[aE],iE[1],iE[2]) : nothing
 aS <= nf ? FLD.f[a][jS[1],jS[2]]=evfS(fld.f[aS],iS[1],iS[2]) : nothing
 aN <= nf ? FLD.f[a][jN[1],jN[2]]=evfN(fld.f[aN],iN[1],iN[2]) : nothing
end
end

return FLD

end

##

function exch_UV_N_cs(fldU::MeshArray,fldV::MeshArray,N::Integer)

fillval=0.0

#step 1

s=size.(fldU.f)
nf=fldU.grid.nFaces
nf==5 ? s=vcat(s,s[3]) : nothing
tp=fldU.grid.class
FLDU=similar(fldU)
FLDV=similar(fldV)

for i=1:nf;
 FLDU.f[i]=fill(fillval,s[i].+2N);
 FLDV.f[i]=fill(fillval,s[i].+2N);
 @views FLDU.f[i][N+1:N+s[i][1],N+1:N+s[i][2]]=fldU.f[i];
 @views FLDV.f[i][N+1:N+s[i][1],N+1:N+s[i][2]]=fldV.f[i];
end;

#step 2

(ovfW,ovfE,ovfS,ovfN,evfW,evfE,evfS,evfN)=exch_cs_viewfunctions();

for a=1:nf
(jW, jE, jS, jN)=exch_cs_target(s[a],N)
(aW,aE,aS,aN,iW,iE,iS,iN)=exch_cs_sources(a,s,N)
if !iseven(a)
 aW <= nf ? FLDU.f[a][jW[1],jW[2]]=ovfW(fldV.f[aW],iW[1],iW[2]) : nothing
 aE <= nf ? FLDU.f[a][jE[1],jE[2]]=ovfE(fldU.f[aE],iE[1],iE[2]) : nothing
 aS <= nf ? FLDU.f[a][jS[1],jS[2]]=ovfS(fldU.f[aS],iS[1],iS[2]) : nothing
 aN <= nf ? FLDU.f[a][jN[1].+1,jN[2]]=-ovfN(fldV.f[aN],iN[1],iN[2]) : nothing
 aW <= nf ? FLDV.f[a][jW[1],jW[2].+1]=-ovfW(fldU.f[aW],iW[1],iW[2]) : nothing
 aE <= nf ? FLDV.f[a][jE[1],jE[2]]=ovfE(fldV.f[aE],iE[1],iE[2]) : nothing
 aS <= nf ? FLDV.f[a][jS[1],jS[2]]=ovfS(fldV.f[aS],iS[1],iS[2]) : nothing
 aN <= nf ? FLDV.f[a][jN[1],jN[2]]=ovfN(fldU.f[aN],iN[1],iN[2]) : nothing
else
 aW <= nf ? FLDU.f[a][jW[1],jW[2]]=evfW(fldU.f[aW],iW[1],iW[2]) : nothing
 aE <= nf ? FLDU.f[a][jE[1],jE[2]]=evfE(fldV.f[aE],iE[1],iE[2]) : nothing
 aS <= nf ? FLDU.f[a][jS[1].+1,jS[2]]=-evfS(fldV.f[aS],iS[1],iS[2]) : nothing
 aN <= nf ? FLDU.f[a][jN[1],jN[2]]=evfN(fldU.f[aN],iN[1],iN[2]) : nothing
 aW <= nf ? FLDV.f[a][jW[1],jW[2]]=evfW(fldV.f[aW],iW[1],iW[2]) : nothing
 aE <= nf ? FLDV.f[a][jE[1],jE[2].+1]=-evfE(fldU.f[aE],iE[1],iE[2]) : nothing
 aS <= nf ? FLDV.f[a][jS[1],jS[2]]=evfS(fldU.f[aS],iS[1],iS[2]) : nothing
 aN <= nf ? FLDV.f[a][jN[1],jN[2]]=evfN(fldV.f[aN],iN[1],iN[2]) : nothing
end
end

return FLDU,FLDV

end

##

function exch_UV_cs(fldU::MeshArray,fldV::MeshArray)

fillval=0.0

#step 1

s=size.(fldU.f)
nf=fldU.grid.nFaces
nf==5 ? s=vcat(s,s[3]) : nothing
tp=fldU.grid.class
FLDU=similar(fldU)
FLDV=similar(fldV)

for i=1:nf
  FLDU.f[i]=fill(fillval,s[i][1]+1,s[i][2]);
  FLDV.f[i]=fill(fillval,s[i][1],s[i][2]+1);
  @views FLDU.f[i][1:s[i][1],1:s[i][2]]=fldU.f[i];
  @views FLDV.f[i][1:s[i][1],1:s[i][2]]=fldV.f[i];
end

 #step 2

(ovfW,ovfE,ovfS,ovfN,evfW,evfE,evfS,evfN)=exch_cs_viewfunctions();

for a=1:nf
(jW, jE, jS, jN)=exch_cs_target(s[a],1)
(aW,aE,aS,aN,iW,iE,iS,iN)=exch_cs_sources(a,s,1)
if !iseven(a)
 aE <= nf ? FLDU.f[a][jE[1].-1,jE[2].-1]=ovfE(fldU.f[aE],iE[1],iE[2]) : nothing
 aN <= nf ? FLDV.f[a][jN[1].-1,jN[2].-1]=ovfN(fldU.f[aN],iN[1],iN[2]) : nothing
else
 aE <= nf ? FLDU.f[a][jE[1].-1,jE[2].-1]=evfE(fldV.f[aE],iE[1],iE[2]) : nothing
 aN <= nf ? FLDV.f[a][jN[1].-1,jN[2].-1]=evfN(fldV.f[aN],iN[1],iN[2]) : nothing
end
end

return FLDU,FLDV

end

## Convenience functions used in the cs & llc case

function exch_cs_target(sa::Tuple{Int64,Int64},N::Integer)

    #target array indices
    jW=(1:N,N+1:N+sa[2]);
    jE=(N+1+sa[1]:2N+sa[1],N+1:N+sa[2]);
    jS=(N+1:N+sa[1],1:N);
    jN=(N+1:N+sa[1],N+1+sa[2]:2N+sa[2]);

    return jW, jE, jS, jN

end

function exch_cs_sources(a::Integer,s::Array{Tuple{Int64,Int64},1},N::Integer)

#source array IDs
aW=0; aE=0; aS=0; aN=0;
if a==1;     aW=5; aE=2; aS=6; aN=3;
elseif a==2; aW=1; aE=4; aS=6; aN=3;
elseif a==3; aW=1; aE=4; aS=2; aN=5;
elseif a==4; aW=3; aE=6; aS=2; aN=5;
elseif a==5; aW=3; aE=6; aS=4; aN=1;
elseif a==6; aW=5; aE=2; aS=4; aN=1;
else; error("Array index is out of bounds.");
end;

if !iseven(a)
    #source array indices
    iW=(1:s[aW][1],s[aW][2]-N+1:s[aW][2]);
    iE=(1:N,1:s[aE][2]);
    iS=(1:s[aS][1],s[aS][2]-N+1:s[aS][2]);
    iN=(1:N,1:s[aN][2]);
else
    #source array indices
    iW=(s[aW][1]-N+1:s[aW][1],1:s[aW][2]);
    iE=(1:s[aE][1],1:N);
    iS=(s[aS][1]-N+1:s[aS][1],1:s[aS][2]);
    iN=(1:s[aN][1],1:N);
end

return aW,aE,aS,aN,iW,iE,iS,iN
end

function exch_cs_viewfunctions()
#view functions for odd numbered arrays
ovfW(x,i,j)=PermutedDimsArray(view(x,reverse(i),j),(2,1))
ovfE(x,i,j)=view(x,i,j)
ovfS(x,i,j)=view(x,i,j)
ovfN(x,i,j)=PermutedDimsArray(view(x,i,reverse(j)),(2,1))
#view functions for even numbered arrays
evfW(x,i,j)=view(x,i,j)
evfE(x,i,j)=PermutedDimsArray(view(x,reverse(i),j),(2,1))
evfS(x,i,j)=PermutedDimsArray(view(x,i,reverse(j)),(2,1))
evfN(x,i,j)=view(x,i,j)
#
return ovfW,ovfE,ovfS,ovfN,evfW,evfE,evfS,evfN
end

##


text:
# Julia code
# Copyright (c) 2022 the SLICOTMath.jl developers
# Portions extracted from SLICOT-Reference distribution:
# Copyright (c) 2002-2020 NICONET e.V.

function run_mc01vd(datfile, io=stdout)
    f = open(datfile,"r")
    readline(f)
    vs = split(readline(f))
    A = parse(Float64, replace(vs[1],'D'=>'E'))
    B = parse(Float64, replace(vs[2],'D'=>'E'))
    C = parse(Float64, replace(vs[3],'D'=>'E'))
# interp call 1

    Z1RE, Z1IM, Z2RE, Z2IM, INFO = SLICOT.mc01vd!(A, B, C)
    println(io, "Z1RE = $Z1RE")
    println(io, "Z1IM = $Z1IM")
    println(io, "Z2RE = $Z2RE")
    println(io, "Z2IM = $Z2IM")
    @test INFO == 0
    INFO == 0 || return

if ( INFO!=0 )
else
end # if
    close(f)
end # run_X()


text:
# This file is a part of BAT.jl, licensed under the MIT License (MIT).

using BAT
using Test

using LinearAlgebra
using ArraysOfArrays, Distributions

@testset "logdval" begin
    @test @inferred(logvalof(LogDVal(log(4.2)))) == log(4.2)
    @test @inferred(logvalof((foo = 55, logval = log(4.2), bar = 2.7))) == log(4.2)
    @test @inferred(logvalof((foo = 55, logd = log(4.3), bar = 2.7))) == log(4.3)
    @test @inferred(logvalof((foo = 55, log = log(4.4), bar = 2.7))) == log(4.4)
    @test_throws ArgumentError logvalof((foo = 55, logval = log(4.3), logd = 2.7))
    @test_throws ArgumentError logvalof((foo = 55, logval = log(4.3), log = 2.7))
    @test_throws ArgumentError logvalof(42)
end


text:
using Documenter, PoincareInvariants

makedocs(
    sitename = "PoincareInvariants.jl",
    format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
    pages = ["Home" => "index.md",
             "Poincaré Integral Invariants" => "poincare_invariants.md",
             "1st Poincaré Invariant" => "poincare_invariant_1st.md",
             "2nd Poincaré Invariant" => "poincare_invariant_2nd.md",
             "Example" => "example.md",
             ]
)

deploydocs(
    repo   = "github.com/JuliaGNI/PoincareInvariants.jl"
)


text:
"""
    function DE(;
        n_groups = 4,
        priors = nothing,
        Np,
        burnin = 1000,
        discard_burnin = true,
        α = .1,
        β = .1,
        ϵ = .001,
        σ = .05,
        κ = 1.0,
        θsnooker = 0.0,
        bounds,
        n_initial = 0,
        generate_proposal = random_gamma,
        update_particle! = mh_update!,
        evaluate_fitness! = compute_posterior!,
        sample = sample,
        blocking_on = x -> false,
        blocks = [false]
    )

Differential Evolution MCMC object.

# Keywords

- `n_groups=4`: number of groups of particles.
- `Np`: number of particles per group.
- `burnin=1000`: number of burnin iterations
- `discard_burnin`: indicates whether burnin samples are discarded. Default is true.
- `α=.1`: migration probability.
- `β=.1`: mutation probability.
- `ϵ=.001`: noise in crossover step.
- `σ=.05`: standard deviation of noise added to parameters for mutation.
- `κ=1.0`: recombination with probability (1-κ) during crossover.
- `θsnooker=0`: sample along line x_i - z. 0.1 is recommended if > 0.
- `n_initial`: initial number of samples from the prior distribution when `sample=resample`. 10 times the number of parameters
is a typical value
- `bounds`: a vector of tuples for lower and upper bounds of each parameter
- `iter`: current iteration
- `generate_proposal`: a function that generates proposals. Default is the two mode proposal described in
Turner et al. 2012. You can also choose `fixed_gamma`, `variable_gamma` (see help) or pass a custom function
- `update_particle!`: a function for updating the particle with a proposal value. Default: `mh_update!`, which uses the
Metropolis-Hastings rule.
- `evaluate_fitness!`: a function for evaluating the fitness of a posterior. The default is to compute the posterior loglikelihood with
 `compute_posterior!`. Select `evaluate_fun!` for optimization rather than MCMC sampling.
- `sample`: a function for sampling particles during the crossover step. The default `sample` uses current particle
parameter values whereas `resample` samples from the history of accepted values for each particle. Np must 3 or greater
when using `resample`.
- `blocking_on = x -> false`: a function that indicates whether block updating is used on each iteration. The function requires optimization_tests
arguement for the DE sampler object and must return a true or false value.
- `blocks`: a vector of boolean vectors indicating which parameters to update. Each sub-vector represents a
block and each element in the sub-vector indicates which parameters are updated within the block. For example, [[true,false],[false,true]]
indicates that the parameter in the first position is updated on the first block and the parameter in the second position is updated on the
second block. If a parameter is a vector or matrix, they are nested within the block sub-vector.

# References

* Ter Braak, C. J. A Markov Chain Monte Carlo version of the genetic algorithm Differential Evolution: easy Bayesian computing for real parameter spaces.

* Ter Braak, Cajo JF, and Jasper A. Vrugt. "Differential evolution Markov chain with snooker updater and fewer chains." Statistics and Computing 18.4 (2008): 435-446

* Turner, B. M., Sederberg, P. B., Brown, S. D., & Steyvers, M. (2013). A method for efficiently sampling from distributions with correlated dimensions. Psychological methods, 18(3), 368.

* Turner, B. M., & Sederberg, P. B. (2012). Approximate Bayesian computation with differential evolution. Journal of Mathematical Psychology, 56(5), 375-385.
"""
@concrete mutable struct DE <: AbstractSampler
    n_groups::Int64
    Np::Int64
    burnin::Int64
    discard_burnin::Bool
    α::Float64
    β::Float64
    ϵ::Float64
    σ::Float64
    κ::Float64
    θsnooker::Float64
    bounds
    n_initial::Int64
    iter::Int64
    generate_proposal
    update_particle!
    evaluate_fitness!
    sample
    blocking_on
    blocks
    samples
end

function DE(;
        n_groups = 4,
        priors = nothing,
        Np,
        burnin = 1000,
        discard_burnin = true,
        α = .1,
        β = .1,
        ϵ = .001,
        σ = .05,
        κ = 1.0,
        θsnooker = 0.0,
        bounds,
        n_initial = 0,
        generate_proposal = random_gamma,
        update_particle! = mh_update!,
        evaluate_fitness! = compute_posterior!,
        sample = sample,
        blocking_on = x -> false,
        blocks = [false],
        sample_prior,
    )

    if  (n_groups == 1) && (α > 0)
        α = 0.0
        @warn "migration probability α > 0 but n_groups == 1. Changing α = 0.0"
    end

    samples = initialize_samples(sample_prior)

    return DE(
        n_groups,
        Np,
        burnin,
        discard_burnin,
        α,
        β,
        ϵ,
        σ,
        κ,
        θsnooker,
        bounds,
        n_initial,
        1,
        generate_proposal,
        update_particle!,
        evaluate_fitness!,
        sample,
        blocking_on,
        blocks,
        samples
    )
end

"""
    function DEModel(
        args...;
        prior_loglike = nothing,
        loglike,
        names,
        sample_prior,
        data,
        kwargs...
    )

A model object containing the log likelihood function and prior distributions.

# Keywords

- `args...`: optional positional arguments for `loglike`
- `prior_loglike=nothing`: log likelihood of posterior sample. A function must be
define for `sample`, but not for `optimize`.
- `loglike`: a log likelihood function for Bayesian parameter estimation or an objective function for
optimization.
- `sample_prior`: a function for initial values. Typically, a prior distribution is ideal.
- `names`: parameter names
- `kwargs...`: optional keyword arguments for `loglike`
"""
struct DEModel{F,L,T,S} <: AbstractModel where {F <: Function,L,T,S}
    prior_loglike::L
    loglike::F
    sample_prior::S
    names::T
end

function DEModel(
        args...;
        prior_loglike = nothing,
        loglike,
        names,
        sample_prior,
        data,
        kwargs...
    )
    return DEModel(
        x -> prior_loglike(x...),
        x -> loglike(data, args..., x...; kwargs...),
        sample_prior,
        names
    )
end

"""
    Particle{T}

# Fields

- `θ`: a vector of parameters
- `samples`: a 2-dimensional array containing all acccepted proposals
- `accept`: proposal acceptance. 1: accept, 0: reject
- `weight`: particle weight based on model fit (currently posterior log likelihood)
- `lp`: a vector of log posterior probabilities associated with each accepted proposal
- `id`: particle id
"""
mutable struct Particle{T}
    Θ::Vector{T}
    accept::Vector{Bool}
    weight::Float64
    lp::Vector{Float64}
    id::Int
end

Base.broadcastable(x::Particle) = Ref(x)

function Particle(;
        Θ=[.0],
        accept = Bool[],
        weight = 0.0,
        id = 0
    )
    return Particle(Θ, accept, weight, Float64[], id)
end

function Particle(Θ::Number, accept, weight, lp, id)
    Particle([Θ], accept, weight, lp, id)
end


text:
using Random

import RLCore

module MountainCarConst
const vel_limit = (-0.07, 0.07)
const pos_limit = (-1.2, 0.5)
const pos_initial_range = (-0.6, 0.4)

const Reverse=1
const Neutral=2
const Accelerate=3

end

"""
MountainCar(pos=0.0, vel=0.0, normalized::Bool=false)
MountainCar(rng::AbstractRNG, normalized::Bool=false)

    The mountain car environment.

"""
mutable struct MountainCar <: RLCore.AbstractEnvironment
    pos::Float64
    vel::Float64
    actions::AbstractSet
    normalized::Bool
    function MountainCar(pos=0.0, vel=0.0, normalized::Bool=false)
        mcc = MountainCarConst
        @boundscheck (pos >= mcc.pos_limit[1] && pos <= mcc.pos_limit[2])
        @boundscheck (vel >= mcc.vel_limit[1] && vel <= mcc.vel_limit[2])
        new(pos, vel, Set([mcc.Reverse, mcc.Neutral, mcc.Accelerate]), normalized)
    end
end

RLCore.get_actions(env::MountainCar) = env.actions
valid_action(env::MountainCar, action) = action in env.actions

function RLCore.reset!(env::MountainCar, rng::AbstractRNG; kwargs...)
    env.pos = (rand(rng)*(MountainCarConst.pos_initial_range[2]
                          - MountainCarConst.pos_initial_range[1])
               + MountainCarConst.pos_initial_range[1])
    env.vel = 0.0
end

function RLCore.reset!(env::MountainCar,
                        start_state::T;
                        kwargs...) where {T<:AbstractArray}
    if env.normalized
        env.pos = start_state[1]
        env.vel = start_state[2]
    else
        pos_limit = MountainCarConst.pos_limit
        vel_limit = MountainCarConst.vel_limit
        env.pos = (start_state[1]*(pos_limit[2] - pos_limit[1])) + pos_limit[1]
        env.vel = (start_state[2]*(vel_limit[2] - vel_limit[1])) + vel_limit[1]
    end
end

function RLCore.environment_step!(env::MountainCar, action, rng::AbstractRNG; kwargs...)

    @boundscheck valid_action(env, action)
    env.vel =
        clamp(env.vel + (action - 2)*0.001 - 0.0025*cos(3*env.pos),
              MountainCarConst.vel_limit...)
    env.pos = clamp(env.pos + env.vel,
                    MountainCarConst.pos_limit...)
end

function RLCore.get_reward(env::MountainCar) # -> determines if the agent_state is terminal
    if env.pos >= MountainCarConst.pos_limit[2]
        return 0
    end
    return -1
end

function RLCore.is_terminal(env::MountainCar) # -> determines if the agent_state is terminal
    return env.pos >= MountainCarConst.pos_limit[2]
end

function RLCore.get_state(env::MountainCar)
    if env.normalized
        return get_normalized_state(env)
    else
        return [env.pos, env.vel]
    end
end

function get_normalized_state(env::MountainCar)
    pos_limit = MountainCarConst.pos_limit
    vel_limit = MountainCarConst.vel_limit
    return [(env.pos - pos_limit[1])/(pos_limit[2] - pos_limit[1]),
            (env.vel - vel_limit[1])/(vel_limit[2] - vel_limit[1])]
end


text:
#   Generating exports
export curl_strequal
export curl_strnequal
export curl_mime_init
export curl_mime_free
export curl_mime_addpart
export curl_mime_name
export curl_mime_filename
export curl_mime_type
export curl_mime_encoder
export curl_mime_data
export curl_mime_filedata
export curl_mime_data_cb
export curl_mime_subparts
export curl_mime_headers
export curl_formget
export curl_formfree
export curl_getenv
export curl_version
export curl_easy_escape
export curl_escape
export curl_easy_unescape
export curl_unescape
export curl_free
export curl_global_init
export curl_global_init_mem
export curl_global_cleanup
export curl_global_sslset
export curl_slist_append
export curl_slist_free_all
export curl_getdate
export curl_share_init
export curl_share_setopt
export curl_share_cleanup
export curl_version_info
export curl_easy_strerror
export curl_share_strerror
export curl_easy_pause
export curl_easy_init
export curl_easy_setopt
export curl_easy_perform
export curl_easy_cleanup
export curl_easy_getinfo
export curl_easy_duphandle
export curl_easy_reset
export curl_easy_recv
export curl_easy_send
export curl_multi_init
export curl_multi_add_handle
export curl_multi_remove_handle
export curl_multi_fdset
export curl_multi_wait
export curl_multi_perform
export curl_multi_cleanup
export curl_multi_info_read
export curl_multi_strerror
export curl_multi_socket
export curl_multi_socket_action
export curl_multi_socket_all
export curl_multi_timeout
export curl_multi_setopt
export curl_multi_assign
export curl_pushheader_bynum
export curl_pushheader_byname
export CURL
export CURLSH
export curl_socket_t
export CURL_SOCKET_BAD
export curl_sslbackend
export CURLSSLBACKEND_NONE
export CURLSSLBACKEND_OPENSSL
export CURLSSLBACKEND_GNUTLS
export CURLSSLBACKEND_NSS
export CURLSSLBACKEND_OBSOLETE4
export CURLSSLBACKEND_GSKIT
export CURLSSLBACKEND_POLARSSL
export CURLSSLBACKEND_WOLFSSL
export CURLSSLBACKEND_SCHANNEL
export CURLSSLBACKEND_DARWINSSL
export CURLSSLBACKEND_AXTLS
export CURLSSLBACKEND_MBEDTLS
export CURLSSLBACKEND_LIBRESSL
export CURLSSLBACKEND_BORINGSSL
export CURLSSLBACKEND_CYASSL
export CURL_HTTPPOST_FILENAME
export CURL_HTTPPOST_READFILE
export CURL_HTTPPOST_PTRNAME
export CURL_HTTPPOST_PTRCONTENTS
export CURL_HTTPPOST_BUFFER
export CURL_HTTPPOST_PTRBUFFER
export CURL_HTTPPOST_CALLBACK
export CURL_HTTPPOST_LARGE
export curl_progress_callback
export curl_xferinfo_callback
export CURL_MAX_READ_SIZE
export CURL_MAX_WRITE_SIZE
export CURL_MAX_HTTP_HEADER
export CURL_WRITEFUNC_PAUSE
export curl_write_callback
export curl_resolver_start_callback
export CURLFINFOFLAG_KNOWN_FILENAME
export CURLFINFOFLAG_KNOWN_FILETYPE
export CURLFINFOFLAG_KNOWN_TIME
export CURLFINFOFLAG_KNOWN_PERM
export CURLFINFOFLAG_KNOWN_UID
export CURLFINFOFLAG_KNOWN_GID
export CURLFINFOFLAG_KNOWN_SIZE
export CURLFINFOFLAG_KNOWN_HLINKCOUNT
export CURL_CHUNK_BGN_FUNC_OK
export CURL_CHUNK_BGN_FUNC_FAIL
export CURL_CHUNK_BGN_FUNC_SKIP
export CURL_CHUNK_END_FUNC_OK
export CURL_CHUNK_END_FUNC_FAIL
export CURL_FNMATCHFUNC_MATCH
export CURL_FNMATCHFUNC_NOMATCH
export CURL_FNMATCHFUNC_FAIL
export CURL_SEEKFUNC_OK
export CURL_SEEKFUNC_FAIL
export CURL_SEEKFUNC_CANTSEEK
export CURL_READFUNC_ABORT
export CURL_READFUNC_PAUSE
export CURL_SOCKOPT_OK
export CURL_SOCKOPT_ERROR
export CURL_SOCKOPT_ALREADY_CONNECTED
export curlfiletype
export CURLFILETYPE_FILE
export CURLFILETYPE_DIRECTORY
export CURLFILETYPE_SYMLINK
export CURLFILETYPE_DEVICE_BLOCK
export CURLFILETYPE_DEVICE_CHAR
export CURLFILETYPE_NAMEDPIPE
export CURLFILETYPE_SOCKET
export CURLFILETYPE_DOOR
export CURLFILETYPE_UNKNOWN
export curl_chunk_bgn_callback
export curl_chunk_end_callback
export curl_fnmatch_callback
export curl_seek_callback
export curl_read_callback
export curlsocktype
export CURLSOCKTYPE_IPCXN
export CURLSOCKTYPE_ACCEPT
export CURLSOCKTYPE_LAST
export curl_sockopt_callback
export curl_opensocket_callback
export curl_closesocket_callback
export curlioerr
export CURLIOE_OK
export CURLIOE_UNKNOWNCMD
export CURLIOE_FAILRESTART
export CURLIOE_LAST
export curliocmd
export CURLIOCMD_NOP
export CURLIOCMD_RESTARTREAD
export CURLIOCMD_LAST
export curl_ioctl_callback
export curl_malloc_callback
export curl_free_callback
export curl_realloc_callback
export curl_strdup_callback
export curl_calloc_callback
export curl_infotype
export CURLINFO_TEXT
export CURLINFO_HEADER_IN
export CURLINFO_HEADER_OUT
export CURLINFO_DATA_IN
export CURLINFO_DATA_OUT
export CURLINFO_SSL_DATA_IN
export CURLINFO_SSL_DATA_OUT
export CURLINFO_END
export curl_debug_callback
export CURLcode
export CURLE_OK
export CURLE_UNSUPPORTED_PROTOCOL
export CURLE_FAILED_INIT
export CURLE_URL_MALFORMAT
export CURLE_NOT_BUILT_IN
export CURLE_COULDNT_RESOLVE_PROXY
export CURLE_COULDNT_RESOLVE_HOST
export CURLE_COULDNT_CONNECT
export CURLE_WEIRD_SERVER_REPLY
export CURLE_REMOTE_ACCESS_DENIED
export CURLE_FTP_ACCEPT_FAILED
export CURLE_FTP_WEIRD_PASS_REPLY
export CURLE_FTP_ACCEPT_TIMEOUT
export CURLE_FTP_WEIRD_PASV_REPLY
export CURLE_FTP_WEIRD_227_FORMAT
export CURLE_FTP_CANT_GET_HOST
export CURLE_HTTP2
export CURLE_FTP_COULDNT_SET_TYPE
export CURLE_PARTIAL_FILE
export CURLE_FTP_COULDNT_RETR_FILE
export CURLE_OBSOLETE20
export CURLE_QUOTE_ERROR
export CURLE_HTTP_RETURNED_ERROR
export CURLE_WRITE_ERROR
export CURLE_OBSOLETE24
export CURLE_UPLOAD_FAILED
export CURLE_READ_ERROR
export CURLE_OUT_OF_MEMORY
export CURLE_OPERATION_TIMEDOUT
export CURLE_OBSOLETE29
export CURLE_FTP_PORT_FAILED
export CURLE_FTP_COULDNT_USE_REST
export CURLE_OBSOLETE32
export CURLE_RANGE_ERROR
export CURLE_HTTP_POST_ERROR
export CURLE_SSL_CONNECT_ERROR
export CURLE_BAD_DOWNLOAD_RESUME
export CURLE_FILE_COULDNT_READ_FILE
export CURLE_LDAP_CANNOT_BIND
export CURLE_LDAP_SEARCH_FAILED
export CURLE_OBSOLETE40
export CURLE_FUNCTION_NOT_FOUND
export CURLE_ABORTED_BY_CALLBACK
export CURLE_BAD_FUNCTION_ARGUMENT
export CURLE_OBSOLETE44
export CURLE_INTERFACE_FAILED
export CURLE_OBSOLETE46
export CURLE_TOO_MANY_REDIRECTS
export CURLE_UNKNOWN_OPTION
export CURLE_TELNET_OPTION_SYNTAX
export CURLE_OBSOLETE50
export CURLE_PEER_FAILED_VERIFICATION
export CURLE_GOT_NOTHING
export CURLE_SSL_ENGINE_NOTFOUND
export CURLE_SSL_ENGINE_SETFAILED
export CURLE_SEND_ERROR
export CURLE_RECV_ERROR
export CURLE_OBSOLETE57
export CURLE_SSL_CERTPROBLEM
export CURLE_SSL_CIPHER
export CURLE_SSL_CACERT
export CURLE_BAD_CONTENT_ENCODING
export CURLE_LDAP_INVALID_URL
export CURLE_FILESIZE_EXCEEDED
export CURLE_USE_SSL_FAILED
export CURLE_SEND_FAIL_REWIND
export CURLE_SSL_ENGINE_INITFAILED
export CURLE_LOGIN_DENIED
export CURLE_TFTP_NOTFOUND
export CURLE_TFTP_PERM
export CURLE_REMOTE_DISK_FULL
export CURLE_TFTP_ILLEGAL
export CURLE_TFTP_UNKNOWNID
export CURLE_REMOTE_FILE_EXISTS
export CURLE_TFTP_NOSUCHUSER
export CURLE_CONV_FAILED
export CURLE_CONV_REQD
export CURLE_SSL_CACERT_BADFILE
export CURLE_REMOTE_FILE_NOT_FOUND
export CURLE_SSH
export CURLE_SSL_SHUTDOWN_FAILED
export CURLE_AGAIN
export CURLE_SSL_CRL_BADFILE
export CURLE_SSL_ISSUER_ERROR
export CURLE_FTP_PRET_FAILED
export CURLE_RTSP_CSEQ_ERROR
export CURLE_RTSP_SESSION_ERROR
export CURLE_FTP_BAD_FILE_LIST
export CURLE_CHUNK_FAILED
export CURLE_NO_CONNECTION_AVAILABLE
export CURLE_SSL_PINNEDPUBKEYNOTMATCH
export CURLE_SSL_INVALIDCERTSTATUS
export CURLE_HTTP2_STREAM
export CURLE_RECURSIVE_API_CALL
export CURL_LAST
export curl_conv_callback
export curl_ssl_ctx_callback
export curl_proxytype
export CURLPROXY_HTTP
export CURLPROXY_HTTP_1_0
export CURLPROXY_HTTPS
export CURLPROXY_SOCKS4
export CURLPROXY_SOCKS5
export CURLPROXY_SOCKS4A
export CURLPROXY_SOCKS5_HOSTNAME
export CURLSSH_AUTH_ANY
export CURLSSH_AUTH_NONE
export CURLSSH_AUTH_PUBLICKEY
export CURLSSH_AUTH_PASSWORD
export CURLSSH_AUTH_HOST
export CURLSSH_AUTH_KEYBOARD
export CURLSSH_AUTH_AGENT
export CURLSSH_AUTH_GSSAPI
export CURLSSH_AUTH_DEFAULT
export CURLGSSAPI_DELEGATION_NONE
export CURLGSSAPI_DELEGATION_POLICY_FLAG
export CURLGSSAPI_DELEGATION_FLAG
export CURL_ERROR_SIZE
export curl_khtype
export CURLKHTYPE_UNKNOWN
export CURLKHTYPE_RSA1
export CURLKHTYPE_RSA
export CURLKHTYPE_DSS
export CURLKHTYPE_ECDSA
export CURLKHTYPE_ED25519
export curl_khstat
export CURLKHSTAT_FINE_ADD_TO_FILE
export CURLKHSTAT_FINE
export CURLKHSTAT_REJECT
export CURLKHSTAT_DEFER
export CURLKHSTAT_LAST
export curl_khmatch
export CURLKHMATCH_OK
export CURLKHMATCH_MISMATCH
export CURLKHMATCH_MISSING
export CURLKHMATCH_LAST
export curl_sshkeycallback
export curl_usessl
export CURLUSESSL_NONE
export CURLUSESSL_TRY
export CURLUSESSL_CONTROL
export CURLUSESSL_ALL
export CURLUSESSL_LAST
export CURLSSLOPT_ALLOW_BEAST
export CURLSSLOPT_NO_REVOKE
export CURL_HET_DEFAULT
export curl_ftpssl
export CURLFTPSSL_NONE
export CURLFTPSSL_TRY
export CURLFTPSSL_CONTROL
export CURLFTPSSL_ALL
export CURLFTPSSL_LAST
export curl_ftpccc
export CURLFTPSSL_CCC_NONE
export CURLFTPSSL_CCC_PASSIVE
export CURLFTPSSL_CCC_ACTIVE
export CURLFTPSSL_CCC_LAST
export curl_ftpauth
export CURLFTPAUTH_DEFAULT
export CURLFTPAUTH_SSL
export CURLFTPAUTH_TLS
export CURLFTPAUTH_LAST
export curl_ftpcreatedir
export CURLFTP_CREATE_DIR_NONE
export CURLFTP_CREATE_DIR
export CURLFTP_CREATE_DIR_RETRY
export CURLFTP_CREATE_DIR_LAST
export curl_ftpmethod
export CURLFTPMETHOD_DEFAULT
export CURLFTPMETHOD_MULTICWD
export CURLFTPMETHOD_NOCWD
export CURLFTPMETHOD_SINGLECWD
export CURLFTPMETHOD_LAST
export CURLHEADER_UNIFIED
export CURLHEADER_SEPARATE
export CURLPROTO_HTTP
export CURLPROTO_HTTPS
export CURLPROTO_FTP
export CURLPROTO_FTPS
export CURLPROTO_SCP
export CURLPROTO_SFTP
export CURLPROTO_TELNET
export CURLPROTO_LDAP
export CURLPROTO_LDAPS
export CURLPROTO_DICT
export CURLPROTO_FILE
export CURLPROTO_TFTP
export CURLPROTO_IMAP
export CURLPROTO_IMAPS
export CURLPROTO_POP3
export CURLPROTO_POP3S
export CURLPROTO_SMTP
export CURLPROTO_SMTPS
export CURLPROTO_RTSP
export CURLPROTO_RTMP
export CURLPROTO_RTMPT
export CURLPROTO_RTMPE
export CURLPROTO_RTMPTE
export CURLPROTO_RTMPS
export CURLPROTO_RTMPTS
export CURLPROTO_GOPHER
export CURLPROTO_SMB
export CURLPROTO_SMBS
export CURLPROTO_ALL
export CURLOPTTYPE_LONG
export CURLOPTTYPE_OBJECTPOINT
export CURLOPTTYPE_STRINGPOINT
export CURLOPTTYPE_FUNCTIONPOINT
export CURLOPTTYPE_OFF_T
export CURLoption
export CURLOPT_WRITEDATA
export CURLOPT_URL
export CURLOPT_PORT
export CURLOPT_PROXY
export CURLOPT_USERPWD
export CURLOPT_PROXYUSERPWD
export CURLOPT_RANGE
export CURLOPT_READDATA
export CURLOPT_ERRORBUFFER
export CURLOPT_WRITEFUNCTION
export CURLOPT_READFUNCTION
export CURLOPT_TIMEOUT
export CURLOPT_INFILESIZE
export CURLOPT_POSTFIELDS
export CURLOPT_REFERER
export CURLOPT_FTPPORT
export CURLOPT_USERAGENT
export CURLOPT_LOW_SPEED_LIMIT
export CURLOPT_LOW_SPEED_TIME
export CURLOPT_RESUME_FROM
export CURLOPT_COOKIE
export CURLOPT_HTTPHEADER
export CURLOPT_HTTPPOST
export CURLOPT_SSLCERT
export CURLOPT_KEYPASSWD
export CURLOPT_CRLF
export CURLOPT_QUOTE
export CURLOPT_HEADERDATA
export CURLOPT_COOKIEFILE
export CURLOPT_SSLVERSION
export CURLOPT_TIMECONDITION
export CURLOPT_TIMEVALUE
export CURLOPT_CUSTOMREQUEST
export CURLOPT_STDERR
export CURLOPT_POSTQUOTE
export CURLOPT_OBSOLETE40
export CURLOPT_VERBOSE
export CURLOPT_HEADER
export CURLOPT_NOPROGRESS
export CURLOPT_NOBODY
export CURLOPT_FAILONERROR
export CURLOPT_UPLOAD
export CURLOPT_POST
export CURLOPT_DIRLISTONLY
export CURLOPT_APPEND
export CURLOPT_NETRC
export CURLOPT_FOLLOWLOCATION
export CURLOPT_TRANSFERTEXT
export CURLOPT_PUT
export CURLOPT_PROGRESSFUNCTION
export CURLOPT_PROGRESSDATA
export CURLOPT_AUTOREFERER
export CURLOPT_PROXYPORT
export CURLOPT_POSTFIELDSIZE
export CURLOPT_HTTPPROXYTUNNEL
export CURLOPT_INTERFACE
export CURLOPT_KRBLEVEL
export CURLOPT_SSL_VERIFYPEER
export CURLOPT_CAINFO
export CURLOPT_MAXREDIRS
export CURLOPT_FILETIME
export CURLOPT_TELNETOPTIONS
export CURLOPT_MAXCONNECTS
export CURLOPT_OBSOLETE72
export CURLOPT_FRESH_CONNECT
export CURLOPT_FORBID_REUSE
export CURLOPT_RANDOM_FILE
export CURLOPT_EGDSOCKET
export CURLOPT_CONNECTTIMEOUT
export CURLOPT_HEADERFUNCTION
export CURLOPT_HTTPGET
export CURLOPT_SSL_VERIFYHOST
export CURLOPT_COOKIEJAR
export CURLOPT_SSL_CIPHER_LIST
export CURLOPT_HTTP_VERSION
export CURLOPT_FTP_USE_EPSV
export CURLOPT_SSLCERTTYPE
export CURLOPT_SSLKEY
export CURLOPT_SSLKEYTYPE
export CURLOPT_SSLENGINE
export CURLOPT_SSLENGINE_DEFAULT
export CURLOPT_DNS_USE_GLOBAL_CACHE
export CURLOPT_DNS_CACHE_TIMEOUT
export CURLOPT_PREQUOTE
export CURLOPT_DEBUGFUNCTION
export CURLOPT_DEBUGDATA
export CURLOPT_COOKIESESSION
export CURLOPT_CAPATH
export CURLOPT_BUFFERSIZE
export CURLOPT_NOSIGNAL
export CURLOPT_SHARE
export CURLOPT_PROXYTYPE
export CURLOPT_ACCEPT_ENCODING
export CURLOPT_PRIVATE
export CURLOPT_HTTP200ALIASES
export CURLOPT_UNRESTRICTED_AUTH
export CURLOPT_FTP_USE_EPRT
export CURLOPT_HTTPAUTH
export CURLOPT_SSL_CTX_FUNCTION
export CURLOPT_SSL_CTX_DATA
export CURLOPT_FTP_CREATE_MISSING_DIRS
export CURLOPT_PROXYAUTH
export CURLOPT_FTP_RESPONSE_TIMEOUT
export CURLOPT_IPRESOLVE
export CURLOPT_MAXFILESIZE
export CURLOPT_INFILESIZE_LARGE
export CURLOPT_RESUME_FROM_LARGE
export CURLOPT_MAXFILESIZE_LARGE
export CURLOPT_NETRC_FILE
export CURLOPT_USE_SSL
export CURLOPT_POSTFIELDSIZE_LARGE
export CURLOPT_TCP_NODELAY
export CURLOPT_FTPSSLAUTH
export CURLOPT_IOCTLFUNCTION
export CURLOPT_IOCTLDATA
export CURLOPT_FTP_ACCOUNT
export CURLOPT_COOKIELIST
export CURLOPT_IGNORE_CONTENT_LENGTH
export CURLOPT_FTP_SKIP_PASV_IP
export CURLOPT_FTP_FILEMETHOD
export CURLOPT_LOCALPORT
export CURLOPT_LOCALPORTRANGE
export CURLOPT_CONNECT_ONLY
export CURLOPT_CONV_FROM_NETWORK_FUNCTION
export CURLOPT_CONV_TO_NETWORK_FUNCTION
export CURLOPT_CONV_FROM_UTF8_FUNCTION
export CURLOPT_MAX_SEND_SPEED_LARGE
export CURLOPT_MAX_RECV_SPEED_LARGE
export CURLOPT_FTP_ALTERNATIVE_TO_USER
export CURLOPT_SOCKOPTFUNCTION
export CURLOPT_SOCKOPTDATA
export CURLOPT_SSL_SESSIONID_CACHE
export CURLOPT_SSH_AUTH_TYPES
export CURLOPT_SSH_PUBLIC_KEYFILE
export CURLOPT_SSH_PRIVATE_KEYFILE
export CURLOPT_FTP_SSL_CCC
export CURLOPT_TIMEOUT_MS
export CURLOPT_CONNECTTIMEOUT_MS
export CURLOPT_HTTP_TRANSFER_DECODING
export CURLOPT_HTTP_CONTENT_DECODING
export CURLOPT_NEW_FILE_PERMS
export CURLOPT_NEW_DIRECTORY_PERMS
export CURLOPT_POSTREDIR
export CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
export CURLOPT_OPENSOCKETFUNCTION
export CURLOPT_OPENSOCKETDATA
export CURLOPT_COPYPOSTFIELDS
export CURLOPT_PROXY_TRANSFER_MODE
export CURLOPT_SEEKFUNCTION
export CURLOPT_SEEKDATA
export CURLOPT_CRLFILE
export CURLOPT_ISSUERCERT
export CURLOPT_ADDRESS_SCOPE
export CURLOPT_CERTINFO
export CURLOPT_USERNAME
export CURLOPT_PASSWORD
export CURLOPT_PROXYUSERNAME
export CURLOPT_PROXYPASSWORD
export CURLOPT_NOPROXY
export CURLOPT_TFTP_BLKSIZE
export CURLOPT_SOCKS5_GSSAPI_SERVICE
export CURLOPT_SOCKS5_GSSAPI_NEC
export CURLOPT_PROTOCOLS
export CURLOPT_REDIR_PROTOCOLS
export CURLOPT_SSH_KNOWNHOSTS
export CURLOPT_SSH_KEYFUNCTION
export CURLOPT_SSH_KEYDATA
export CURLOPT_MAIL_FROM
export CURLOPT_MAIL_RCPT
export CURLOPT_FTP_USE_PRET
export CURLOPT_RTSP_REQUEST
export CURLOPT_RTSP_SESSION_ID
export CURLOPT_RTSP_STREAM_URI
export CURLOPT_RTSP_TRANSPORT
export CURLOPT_RTSP_CLIENT_CSEQ
export CURLOPT_RTSP_SERVER_CSEQ
export CURLOPT_INTERLEAVEDATA
export CURLOPT_INTERLEAVEFUNCTION
export CURLOPT_WILDCARDMATCH
export CURLOPT_CHUNK_BGN_FUNCTION
export CURLOPT_CHUNK_END_FUNCTION
export CURLOPT_FNMATCH_FUNCTION
export CURLOPT_CHUNK_DATA
export CURLOPT_FNMATCH_DATA
export CURLOPT_RESOLVE
export CURLOPT_TLSAUTH_USERNAME
export CURLOPT_TLSAUTH_PASSWORD
export CURLOPT_TLSAUTH_TYPE
export CURLOPT_TRANSFER_ENCODING
export CURLOPT_CLOSESOCKETFUNCTION
export CURLOPT_CLOSESOCKETDATA
export CURLOPT_GSSAPI_DELEGATION
export CURLOPT_DNS_SERVERS
export CURLOPT_ACCEPTTIMEOUT_MS
export CURLOPT_TCP_KEEPALIVE
export CURLOPT_TCP_KEEPIDLE
export CURLOPT_TCP_KEEPINTVL
export CURLOPT_SSL_OPTIONS
export CURLOPT_MAIL_AUTH
export CURLOPT_SASL_IR
export CURLOPT_XFERINFOFUNCTION
export CURLOPT_XOAUTH2_BEARER
export CURLOPT_DNS_INTERFACE
export CURLOPT_DNS_LOCAL_IP4
export CURLOPT_DNS_LOCAL_IP6
export CURLOPT_LOGIN_OPTIONS
export CURLOPT_SSL_ENABLE_NPN
export CURLOPT_SSL_ENABLE_ALPN
export CURLOPT_EXPECT_100_TIMEOUT_MS
export CURLOPT_PROXYHEADER
export CURLOPT_HEADEROPT
export CURLOPT_PINNEDPUBLICKEY
export CURLOPT_UNIX_SOCKET_PATH
export CURLOPT_SSL_VERIFYSTATUS
export CURLOPT_SSL_FALSESTART
export CURLOPT_PATH_AS_IS
export CURLOPT_PROXY_SERVICE_NAME
export CURLOPT_SERVICE_NAME
export CURLOPT_PIPEWAIT
export CURLOPT_DEFAULT_PROTOCOL
export CURLOPT_STREAM_WEIGHT
export CURLOPT_STREAM_DEPENDS
export CURLOPT_STREAM_DEPENDS_E
export CURLOPT_TFTP_NO_OPTIONS
export CURLOPT_CONNECT_TO
export CURLOPT_TCP_FASTOPEN
export CURLOPT_KEEP_SENDING_ON_ERROR
export CURLOPT_PROXY_CAINFO
export CURLOPT_PROXY_CAPATH
export CURLOPT_PROXY_SSL_VERIFYPEER
export CURLOPT_PROXY_SSL_VERIFYHOST
export CURLOPT_PROXY_SSLVERSION
export CURLOPT_PROXY_TLSAUTH_USERNAME
export CURLOPT_PROXY_TLSAUTH_PASSWORD
export CURLOPT_PROXY_TLSAUTH_TYPE
export CURLOPT_PROXY_SSLCERT
export CURLOPT_PROXY_SSLCERTTYPE
export CURLOPT_PROXY_SSLKEY
export CURLOPT_PROXY_SSLKEYTYPE
export CURLOPT_PROXY_KEYPASSWD
export CURLOPT_PROXY_SSL_CIPHER_LIST
export CURLOPT_PROXY_CRLFILE
export CURLOPT_PROXY_SSL_OPTIONS
export CURLOPT_PRE_PROXY
export CURLOPT_PROXY_PINNEDPUBLICKEY
export CURLOPT_ABSTRACT_UNIX_SOCKET
export CURLOPT_SUPPRESS_CONNECT_HEADERS
export CURLOPT_REQUEST_TARGET
export CURLOPT_SOCKS5_AUTH
export CURLOPT_SSH_COMPRESSION
export CURLOPT_MIMEPOST
export CURLOPT_TIMEVALUE_LARGE
export CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS
export CURLOPT_RESOLVER_START_FUNCTION
export CURLOPT_RESOLVER_START_DATA
export CURLOPT_HAPROXYPROTOCOL
export CURLOPT_DNS_SHUFFLE_ADDRESSES
export CURLOPT_TLS13_CIPHERS
export CURLOPT_PROXY_TLS13_CIPHERS
export CURLOPT_DISALLOW_USERNAME_IN_URL
export CURLOPT_LASTENTRY
export CURLOPT_XFERINFODATA
export CURLOPT_SERVER_RESPONSE_TIMEOUT
export CURLOPT_POST301
export CURLOPT_SSLKEYPASSWD
export CURLOPT_FTPAPPEND
export CURLOPT_FTPLISTONLY
export CURLOPT_FTP_SSL
export CURLOPT_SSLCERTPASSWD
export CURLOPT_KRB4LEVEL
export CURL_IPRESOLVE_WHATEVER
export CURL_IPRESOLVE_V4
export CURL_IPRESOLVE_V6
export CURLOPT_RTSPHEADER
export CURL_HTTP_VERSION_NONE
export CURL_HTTP_VERSION_1_0
export CURL_HTTP_VERSION_1_1
export CURL_HTTP_VERSION_2_0
export CURL_HTTP_VERSION_2TLS
export CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE
export CURL_HTTP_VERSION_LAST
export CURL_HTTP_VERSION_2
export CURL_RTSPREQ_NONE
export CURL_RTSPREQ_OPTIONS
export CURL_RTSPREQ_DESCRIBE
export CURL_RTSPREQ_ANNOUNCE
export CURL_RTSPREQ_SETUP
export CURL_RTSPREQ_PLAY
export CURL_RTSPREQ_PAUSE
export CURL_RTSPREQ_TEARDOWN
export CURL_RTSPREQ_GET_PARAMETER
export CURL_RTSPREQ_SET_PARAMETER
export CURL_RTSPREQ_RECORD
export CURL_RTSPREQ_RECEIVE
export CURL_RTSPREQ_LAST
export CURL_NETRC_OPTION
export CURL_NETRC_IGNORED
export CURL_NETRC_OPTIONAL
export CURL_NETRC_REQUIRED
export CURL_NETRC_LAST
export CURL_SSLVERSION_DEFAULT
export CURL_SSLVERSION_TLSv1
export CURL_SSLVERSION_SSLv2
export CURL_SSLVERSION_SSLv3
export CURL_SSLVERSION_TLSv1_0
export CURL_SSLVERSION_TLSv1_1
export CURL_SSLVERSION_TLSv1_2
export CURL_SSLVERSION_TLSv1_3
export CURL_SSLVERSION_LAST
export CURL_SSLVERSION_MAX_NONE
export CURL_SSLVERSION_MAX_DEFAULT
export CURL_SSLVERSION_MAX_TLSv1_0
export CURL_SSLVERSION_MAX_TLSv1_1
export CURL_SSLVERSION_MAX_TLSv1_2
export CURL_SSLVERSION_MAX_TLSv1_3
export CURL_SSLVERSION_MAX_LAST
export CURL_TLSAUTH
export CURL_TLSAUTH_NONE
export CURL_TLSAUTH_SRP
export CURL_TLSAUTH_LAST
export CURL_REDIR_GET_ALL
export CURL_REDIR_POST_301
export CURL_REDIR_POST_302
export CURL_REDIR_POST_303
export CURL_REDIR_POST_ALL
export curl_TimeCond
export CURL_TIMECOND_NONE
export CURL_TIMECOND_IFMODSINCE
export CURL_TIMECOND_IFUNMODSINCE
export CURL_TIMECOND_LASTMOD
export CURL_TIMECOND_LAST
export curl_mime
export curl_mimepart
export CURLformoption
export CURLFORM_NOTHING
export CURLFORM_COPYNAME
export CURLFORM_PTRNAME
export CURLFORM_NAMELENGTH
export CURLFORM_COPYCONTENTS
export CURLFORM_PTRCONTENTS
export CURLFORM_CONTENTSLENGTH
export CURLFORM_FILECONTENT
export CURLFORM_ARRAY
export CURLFORM_OBSOLETE
export CURLFORM_FILE
export CURLFORM_BUFFER
export CURLFORM_BUFFERPTR
export CURLFORM_BUFFERLENGTH
export CURLFORM_CONTENTTYPE
export CURLFORM_CONTENTHEADER
export CURLFORM_FILENAME
export CURLFORM_END
export CURLFORM_OBSOLETE2
export CURLFORM_STREAM
export CURLFORM_CONTENTLEN
export CURLFORM_LASTENTRY
export CURLFORMcode
export CURL_FORMADD_OK
export CURL_FORMADD_MEMORY
export CURL_FORMADD_OPTION_TWICE
export CURL_FORMADD_NULL
export CURL_FORMADD_UNKNOWN_OPTION
export CURL_FORMADD_INCOMPLETE
export CURL_FORMADD_ILLEGAL_ARRAY
export CURL_FORMADD_DISABLED
export CURL_FORMADD_LAST
export curl_formget_callback
export curl_ssl_backend
export CURLsslset
export CURLSSLSET_OK
export CURLSSLSET_UNKNOWN_BACKEND
export CURLSSLSET_TOO_LATE
export CURLSSLSET_NO_BACKENDS
export CURLINFO_STRING
export CURLINFO_LONG
export CURLINFO_DOUBLE
export CURLINFO_SLIST
export CURLINFO_PTR
export CURLINFO_SOCKET
export CURLINFO_OFF_T
export CURLINFO_MASK
export CURLINFO_TYPEMASK
export CURLINFO
export CURLINFO_NONE
export CURLINFO_EFFECTIVE_URL
export CURLINFO_RESPONSE_CODE
export CURLINFO_TOTAL_TIME
export CURLINFO_NAMELOOKUP_TIME
export CURLINFO_CONNECT_TIME
export CURLINFO_PRETRANSFER_TIME
export CURLINFO_SIZE_UPLOAD
export CURLINFO_SIZE_UPLOAD_T
export CURLINFO_SIZE_DOWNLOAD
export CURLINFO_SIZE_DOWNLOAD_T
export CURLINFO_SPEED_DOWNLOAD
export CURLINFO_SPEED_DOWNLOAD_T
export CURLINFO_SPEED_UPLOAD
export CURLINFO_SPEED_UPLOAD_T
export CURLINFO_HEADER_SIZE
export CURLINFO_REQUEST_SIZE
export CURLINFO_SSL_VERIFYRESULT
export CURLINFO_FILETIME
export CURLINFO_FILETIME_T
export CURLINFO_CONTENT_LENGTH_DOWNLOAD
export CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
export CURLINFO_CONTENT_LENGTH_UPLOAD
export CURLINFO_CONTENT_LENGTH_UPLOAD_T
export CURLINFO_STARTTRANSFER_TIME
export CURLINFO_CONTENT_TYPE
export CURLINFO_REDIRECT_TIME
export CURLINFO_REDIRECT_COUNT
export CURLINFO_PRIVATE
export CURLINFO_HTTP_CONNECTCODE
export CURLINFO_HTTPAUTH_AVAIL
export CURLINFO_PROXYAUTH_AVAIL
export CURLINFO_OS_ERRNO
export CURLINFO_NUM_CONNECTS
export CURLINFO_SSL_ENGINES
export CURLINFO_COOKIELIST
export CURLINFO_LASTSOCKET
export CURLINFO_FTP_ENTRY_PATH
export CURLINFO_REDIRECT_URL
export CURLINFO_PRIMARY_IP
export CURLINFO_APPCONNECT_TIME
export CURLINFO_CERTINFO
export CURLINFO_CONDITION_UNMET
export CURLINFO_RTSP_SESSION_ID
export CURLINFO_RTSP_CLIENT_CSEQ
export CURLINFO_RTSP_SERVER_CSEQ
export CURLINFO_RTSP_CSEQ_RECV
export CURLINFO_PRIMARY_PORT
export CURLINFO_LOCAL_IP
export CURLINFO_LOCAL_PORT
export CURLINFO_TLS_SESSION
export CURLINFO_ACTIVESOCKET
export CURLINFO_TLS_SSL_PTR
export CURLINFO_HTTP_VERSION
export CURLINFO_PROXY_SSL_VERIFYRESULT
export CURLINFO_PROTOCOL
export CURLINFO_SCHEME
export CURLINFO_TOTAL_TIME_T
export CURLINFO_NAMELOOKUP_TIME_T
export CURLINFO_CONNECT_TIME_T
export CURLINFO_PRETRANSFER_TIME_T
export CURLINFO_STARTTRANSFER_TIME_T
export CURLINFO_REDIRECT_TIME_T
export CURLINFO_APPCONNECT_TIME_T
export CURLINFO_LASTONE
export CURLINFO_HTTP_CODE
export curl_closepolicy
export CURLCLOSEPOLICY_NONE
export CURLCLOSEPOLICY_OLDEST
export CURLCLOSEPOLICY_LEAST_RECENTLY_USED
export CURLCLOSEPOLICY_LEAST_TRAFFIC
export CURLCLOSEPOLICY_SLOWEST
export CURLCLOSEPOLICY_CALLBACK
export CURLCLOSEPOLICY_LAST
export CURL_GLOBAL_SSL
export CURL_GLOBAL_WIN32
export CURL_GLOBAL_ALL
export CURL_GLOBAL_NOTHING
export CURL_GLOBAL_DEFAULT
export CURL_GLOBAL_ACK_EINTR
export curl_lock_data
export CURL_LOCK_DATA_NONE
export CURL_LOCK_DATA_SHARE
export CURL_LOCK_DATA_COOKIE
export CURL_LOCK_DATA_DNS
export CURL_LOCK_DATA_SSL_SESSION
export CURL_LOCK_DATA_CONNECT
export CURL_LOCK_DATA_PSL
export CURL_LOCK_DATA_LAST
export curl_lock_access
export CURL_LOCK_ACCESS_NONE
export CURL_LOCK_ACCESS_SHARED
export CURL_LOCK_ACCESS_SINGLE
export CURL_LOCK_ACCESS_LAST
export curl_lock_function
export curl_unlock_function
export CURLSHcode
export CURLSHE_OK
export CURLSHE_BAD_OPTION
export CURLSHE_IN_USE
export CURLSHE_INVALID
export CURLSHE_NOMEM
export CURLSHE_NOT_BUILT_IN
export CURLSHE_LAST
export CURLSHoption
export CURLSHOPT_NONE
export CURLSHOPT_SHARE
export CURLSHOPT_UNSHARE
export CURLSHOPT_LOCKFUNC
export CURLSHOPT_UNLOCKFUNC
export CURLSHOPT_USERDATA
export CURLSHOPT_LAST
export CURLversion
export CURLVERSION_FIRST
export CURLVERSION_SECOND
export CURLVERSION_THIRD
export CURLVERSION_FOURTH
export CURLVERSION_FIFTH
export CURLVERSION_LAST
export CURLVERSION_NOW
export CURL_VERSION_IPV6
export CURL_VERSION_KERBEROS4
export CURL_VERSION_SSL
export CURL_VERSION_LIBZ
export CURL_VERSION_NTLM
export CURL_VERSION_GSSNEGOTIATE
export CURL_VERSION_DEBUG
export CURL_VERSION_ASYNCHDNS
export CURL_VERSION_SPNEGO
export CURL_VERSION_LARGEFILE
export CURL_VERSION_IDN
export CURL_VERSION_SSPI
export CURL_VERSION_CONV
export CURL_VERSION_CURLDEBUG
export CURL_VERSION_TLSAUTH_SRP
export CURL_VERSION_NTLM_WB
export CURL_VERSION_HTTP2
export CURL_VERSION_GSSAPI
export CURL_VERSION_KERBEROS5
export CURL_VERSION_UNIX_SOCKETS
export CURL_VERSION_PSL
export CURL_VERSION_HTTPS_PROXY
export CURL_VERSION_MULTI_SSL
export CURL_VERSION_BROTLI
export CURLPAUSE_RECV
export CURLPAUSE_RECV_CONT
export CURLPAUSE_SEND
export CURLPAUSE_SEND_CONT
export CURLPAUSE_ALL
export CURLPAUSE_CONT
export CURLE_OBSOLETE16
export CURLE_OBSOLETE10
export CURLE_OBSOLETE12
export CURLOPT_ENCODING
export CURLE_FTP_WEIRD_SERVER_REPLY
export CURLE_UNKNOWN_TELNET_OPTION
export CURLE_SSL_PEER_CERTIFICATE
export CURLE_OBSOLETE
export CURLE_BAD_PASSWORD_ENTERED
export CURLE_BAD_CALLING_ORDER
export CURLE_FTP_USER_PASSWORD_INCORRECT
export CURLE_FTP_CANT_RECONNECT
export CURLE_FTP_COULDNT_GET_SIZE
export CURLE_FTP_COULDNT_SET_ASCII
export CURLE_FTP_WEIRD_USER_REPLY
export CURLE_FTP_WRITE_ERROR
export CURLE_LIBRARY_NOT_FOUND
export CURLE_MALFORMAT_USER
export CURLE_SHARE_IN_USE
export CURLE_URL_MALFORMAT_USER
export CURLE_FTP_ACCESS_DENIED
export CURLE_FTP_COULDNT_SET_BINARY
export CURLE_FTP_QUOTE_ERROR
export CURLE_TFTP_DISKFULL
export CURLE_TFTP_EXISTS
export CURLE_HTTP_RANGE_ERROR
export CURLE_FTP_SSL_FAILED
export CURLE_OPERATION_TIMEOUTED
export CURLE_HTTP_NOT_FOUND
export CURLE_HTTP_PORT_FAILED
export CURLE_FTP_COULDNT_STOR_FILE
export CURLE_FTP_PARTIAL_FILE
export CURLE_FTP_BAD_DOWNLOAD_RESUME
export CURLE_ALREADY_COMPLETE
export CURLOPT_FILE
export CURLOPT_INFILE
export CURLOPT_WRITEHEADER
export CURLOPT_WRITEINFO
export CURLOPT_CLOSEPOLICY
export CURLM
export CURLMcode
export CURLM_CALL_MULTI_PERFORM
export CURLM_OK
export CURLM_BAD_HANDLE
export CURLM_BAD_EASY_HANDLE
export CURLM_OUT_OF_MEMORY
export CURLM_INTERNAL_ERROR
export CURLM_BAD_SOCKET
export CURLM_UNKNOWN_OPTION
export CURLM_ADDED_ALREADY
export CURLM_RECURSIVE_API_CALL
export CURLM_LAST
export CURLM_CALL_MULTI_SOCKET
export CURLPIPE_NOTHING
export CURLPIPE_HTTP1
export CURLPIPE_MULTIPLEX
export CURLMSG
export CURLMSG_NONE
export CURLMSG_DONE
export CURLMSG_LAST
export CURL_WAIT_POLLIN
export CURL_WAIT_POLLPRI
export CURL_WAIT_POLLOUT
export CURL_POLL_NONE
export CURL_POLL_IN
export CURL_POLL_OUT
export CURL_POLL_INOUT
export CURL_POLL_REMOVE
export CURL_SOCKET_TIMEOUT
export CURL_CSELECT_IN
export CURL_CSELECT_OUT
export CURL_CSELECT_ERR
export curl_socket_callback
export curl_multi_timer_callback
export CURLMoption
export CURLMOPT_SOCKETFUNCTION
export CURLMOPT_SOCKETDATA
export CURLMOPT_PIPELINING
export CURLMOPT_TIMERFUNCTION
export CURLMOPT_TIMERDATA
export CURLMOPT_MAXCONNECTS
export CURLMOPT_MAX_HOST_CONNECTIONS
export CURLMOPT_MAX_PIPELINE_LENGTH
export CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE
export CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE
export CURLMOPT_PIPELINING_SITE_BL
export CURLMOPT_PIPELINING_SERVER_BL
export CURLMOPT_MAX_TOTAL_CONNECTIONS
export CURLMOPT_PUSHFUNCTION
export CURLMOPT_PUSHDATA
export CURLMOPT_LASTENTRY
export CURL_PUSH_OK
export CURL_PUSH_DENY
export curl_push_callback
export CURL_TYPEOF_CURL_OFF_T
export CURL_FORMAT_CURL_OFF_T
export CURL_FORMAT_CURL_OFF_TU
export CURL_SUFFIX_CURL_OFF_T
export CURL_SUFFIX_CURL_OFF_TU
export CURL_TYPEOF_CURL_SOCKLEN_T
export CURL_PULL_SYS_TYPES_H
export CURL_PULL_SYS_SOCKET_H
export CURL_SOCKET_BAD
export CURLSSLBACKEND_LIBRESSL
export CURLSSLBACKEND_BORINGSSL
export CURLSSLBACKEND_CYASSL
export CURL_HTTPPOST_FILENAME
export CURL_HTTPPOST_READFILE
export CURL_HTTPPOST_PTRNAME
export CURL_HTTPPOST_PTRCONTENTS
export CURL_HTTPPOST_BUFFER
export CURL_HTTPPOST_PTRBUFFER
export CURL_HTTPPOST_CALLBACK
export CURL_HTTPPOST_LARGE
export CURL_MAX_READ_SIZE
export CURL_MAX_WRITE_SIZE
export CURL_MAX_HTTP_HEADER
export CURL_WRITEFUNC_PAUSE
export CURLFINFOFLAG_KNOWN_FILENAME
export CURLFINFOFLAG_KNOWN_FILETYPE
export CURLFINFOFLAG_KNOWN_TIME
export CURLFINFOFLAG_KNOWN_PERM
export CURLFINFOFLAG_KNOWN_UID
export CURLFINFOFLAG_KNOWN_GID
export CURLFINFOFLAG_KNOWN_SIZE
export CURLFINFOFLAG_KNOWN_HLINKCOUNT
export CURL_CHUNK_BGN_FUNC_OK
export CURL_CHUNK_BGN_FUNC_FAIL
export CURL_CHUNK_BGN_FUNC_SKIP
export CURL_CHUNK_END_FUNC_OK
export CURL_CHUNK_END_FUNC_FAIL
export CURL_FNMATCHFUNC_MATCH
export CURL_FNMATCHFUNC_NOMATCH
export CURL_FNMATCHFUNC_FAIL
export CURL_SEEKFUNC_OK
export CURL_SEEKFUNC_FAIL
export CURL_SEEKFUNC_CANTSEEK
export CURL_READFUNC_ABORT
export CURL_READFUNC_PAUSE
export CURL_SOCKOPT_OK
export CURL_SOCKOPT_ERROR
export CURL_SOCKOPT_ALREADY_CONNECTED
export CURLE_OBSOLETE16
export CURLE_OBSOLETE10
export CURLE_OBSOLETE12
export CURLOPT_ENCODING
export CURLE_FTP_WEIRD_SERVER_REPLY
export CURLE_UNKNOWN_TELNET_OPTION
export CURLE_SSL_PEER_CERTIFICATE
export CURLE_OBSOLETE
export CURLE_BAD_PASSWORD_ENTERED
export CURLE_BAD_CALLING_ORDER
export CURLE_FTP_USER_PASSWORD_INCORRECT
export CURLE_FTP_CANT_RECONNECT
export CURLE_FTP_COULDNT_GET_SIZE
export CURLE_FTP_COULDNT_SET_ASCII
export CURLE_FTP_WEIRD_USER_REPLY
export CURLE_FTP_WRITE_ERROR
export CURLE_LIBRARY_NOT_FOUND
export CURLE_MALFORMAT_USER
export CURLE_SHARE_IN_USE
export CURLE_URL_MALFORMAT_USER
export CURLE_FTP_ACCESS_DENIED
export CURLE_FTP_COULDNT_SET_BINARY
export CURLE_FTP_QUOTE_ERROR
export CURLE_TFTP_DISKFULL
export CURLE_TFTP_EXISTS
export CURLE_HTTP_RANGE_ERROR
export CURLE_FTP_SSL_FAILED
export CURLE_OPERATION_TIMEOUTED
export CURLE_HTTP_NOT_FOUND
export CURLE_HTTP_PORT_FAILED
export CURLE_FTP_COULDNT_STOR_FILE
export CURLE_FTP_PARTIAL_FILE
export CURLE_FTP_BAD_DOWNLOAD_RESUME
export CURLE_ALREADY_COMPLETE
export CURLOPT_FILE
export CURLOPT_INFILE
export CURLOPT_WRITEHEADER
export CURLOPT_WRITEINFO
export CURLOPT_CLOSEPOLICY
export CURLAUTH_NONE
export CURLAUTH_BASIC
export CURLAUTH_DIGEST
export CURLAUTH_NEGOTIATE
export CURLAUTH_GSSNEGOTIATE
export CURLAUTH_GSSAPI
export CURLAUTH_NTLM
export CURLAUTH_DIGEST_IE
export CURLAUTH_NTLM_WB
export CURLAUTH_BEARER
export CURLAUTH_ONLY
export CURLAUTH_ANY
export CURLAUTH_ANYSAFE
export CURLSSH_AUTH_ANY
export CURLSSH_AUTH_NONE
export CURLSSH_AUTH_PUBLICKEY
export CURLSSH_AUTH_PASSWORD
export CURLSSH_AUTH_HOST
export CURLSSH_AUTH_KEYBOARD
export CURLSSH_AUTH_AGENT
export CURLSSH_AUTH_GSSAPI
export CURLSSH_AUTH_DEFAULT
export CURLGSSAPI_DELEGATION_NONE
export CURLGSSAPI_DELEGATION_POLICY_FLAG
export CURLGSSAPI_DELEGATION_FLAG
export CURL_ERROR_SIZE
export CURLSSLOPT_ALLOW_BEAST
export CURLSSLOPT_NO_REVOKE
export CURL_HET_DEFAULT
export CURLFTPSSL_NONE
export CURLFTPSSL_TRY
export CURLFTPSSL_CONTROL
export CURLFTPSSL_ALL
export CURLFTPSSL_LAST
export CURLHEADER_UNIFIED
export CURLHEADER_SEPARATE
export CURLPROTO_HTTP
export CURLPROTO_HTTPS
export CURLPROTO_FTP
export CURLPROTO_FTPS
export CURLPROTO_SCP
export CURLPROTO_SFTP
export CURLPROTO_TELNET
export CURLPROTO_LDAP
export CURLPROTO_LDAPS
export CURLPROTO_DICT
export CURLPROTO_FILE
export CURLPROTO_TFTP
export CURLPROTO_IMAP
export CURLPROTO_IMAPS
export CURLPROTO_POP3
export CURLPROTO_POP3S
export CURLPROTO_SMTP
export CURLPROTO_SMTPS
export CURLPROTO_RTSP
export CURLPROTO_RTMP
export CURLPROTO_RTMPT
export CURLPROTO_RTMPE
export CURLPROTO_RTMPTE
export CURLPROTO_RTMPS
export CURLPROTO_RTMPTS
export CURLPROTO_GOPHER
export CURLPROTO_SMB
export CURLPROTO_SMBS
export CURLPROTO_ALL
export CURLOPTTYPE_LONG
export CURLOPTTYPE_OBJECTPOINT
export CURLOPTTYPE_STRINGPOINT
export CURLOPTTYPE_FUNCTIONPOINT
export CURLOPTTYPE_OFF_T
export CURLOPT_XFERINFODATA
export CURLOPT_SERVER_RESPONSE_TIMEOUT
export CURLOPT_POST301
export CURLOPT_SSLKEYPASSWD
export CURLOPT_FTPAPPEND
export CURLOPT_FTPLISTONLY
export CURLOPT_FTP_SSL
export CURLOPT_SSLCERTPASSWD
export CURLOPT_KRB4LEVEL
export CURL_IPRESOLVE_WHATEVER
export CURL_IPRESOLVE_V4
export CURL_IPRESOLVE_V6
export CURLOPT_RTSPHEADER
export CURL_HTTP_VERSION_2
export CURL_REDIR_GET_ALL
export CURL_REDIR_POST_301
export CURL_REDIR_POST_302
export CURL_REDIR_POST_303
export CURL_REDIR_POST_ALL
export CURL_ZERO_TERMINATED
export CURLINFO_STRING
export CURLINFO_LONG
export CURLINFO_DOUBLE
export CURLINFO_SLIST
export CURLINFO_PTR
export CURLINFO_SOCKET
export CURLINFO_OFF_T
export CURLINFO_MASK
export CURLINFO_TYPEMASK
export CURLINFO_HTTP_CODE
export CURL_GLOBAL_SSL
export CURL_GLOBAL_WIN32
export CURL_GLOBAL_ALL
export CURL_GLOBAL_NOTHING
export CURL_GLOBAL_DEFAULT
export CURL_GLOBAL_ACK_EINTR
export CURLVERSION_NOW
export CURL_VERSION_IPV6
export CURL_VERSION_KERBEROS4
export CURL_VERSION_SSL
export CURL_VERSION_LIBZ
export CURL_VERSION_NTLM
export CURL_VERSION_GSSNEGOTIATE
export CURL_VERSION_DEBUG
export CURL_VERSION_ASYNCHDNS
export CURL_VERSION_SPNEGO
export CURL_VERSION_LARGEFILE
export CURL_VERSION_IDN
export CURL_VERSION_SSPI
export CURL_VERSION_CONV
export CURL_VERSION_CURLDEBUG
export CURL_VERSION_TLSAUTH_SRP
export CURL_VERSION_NTLM_WB
export CURL_VERSION_HTTP2
export CURL_VERSION_GSSAPI
export CURL_VERSION_KERBEROS5
export CURL_VERSION_UNIX_SOCKETS
export CURL_VERSION_PSL
export CURL_VERSION_HTTPS_PROXY
export CURL_VERSION_MULTI_SSL
export CURL_VERSION_BROTLI
export CURLPAUSE_RECV
export CURLPAUSE_RECV_CONT
export CURLPAUSE_SEND
export CURLPAUSE_SEND_CONT
export CURLPAUSE_ALL
export CURLPAUSE_CONT
export CURLM_CALL_MULTI_SOCKET
export CURLPIPE_NOTHING
export CURLPIPE_HTTP1
export CURLPIPE_MULTIPLEX
export CURL_WAIT_POLLIN
export CURL_WAIT_POLLPRI
export CURL_WAIT_POLLOUT
export CURL_POLL_NONE
export CURL_POLL_IN
export CURL_POLL_OUT
export CURL_POLL_INOUT
export CURL_POLL_REMOVE
export CURL_SOCKET_TIMEOUT
export CURL_CSELECT_IN
export CURL_CSELECT_OUT
export CURL_CSELECT_ERR
export CURL_PUSH_OK
export CURL_PUSH_DENY
export CURLOPT_MAXAGE_CONN


text:
module Two

macro sayhello()
           return :( println("Hello, world!") )
end

ex = quote
           x = 1
           y = 2
           x + y
end

end


text:
@testset "gen data" begin
    @test 5 ≤ SqState.rand2range((5, 10)) < 10

    r_range = (0, 2)
    θ_range = (0, 2π)
    n̄_range = (0, 0.5)

    args = SqState.rand_arg_sqth_th(r_range, θ_range, n̄_range)
    @test all([
        r_range[1] ≤ args[1] < r_range[2],
        θ_range[1] ≤ args[2] < θ_range[2],
        n̄_range[1] ≤ args[3] < n̄_range[2],
        n̄_range[1] ≤ args[4] < n̄_range[2],
        0 ≤ args[5] < 1,
        args[6] == 1-args[5]
    ])

    args = SqState.rand_arg_sqth(r_range, θ_range, n̄_range)
    @test all([
        r_range[1] ≤ args[1] < r_range[2],
        θ_range[1] ≤ args[2] < θ_range[2],
        n̄_range[1] ≤ args[3] < n̄_range[2],
    ])

    @test tr(SqState.construct_state_sqth_th(SqState.rand_arg_sqth_th(r_range, θ_range, n̄_range)..., 100).𝛒) ≈ 1

    @test tr(SqState.construct_state_sqth(SqState.rand_arg_sqth(r_range, θ_range, n̄_range)..., 100).𝛒) ≈ 1
end

@testset "model" begin
    a = rand(5, 5, 10)
    b = rand(5, 5, 10)
    c = SqState.to_complex(a, b)
    @test size(c) == (5, 5, 10)
    @test all([c[i] == complex(a[i], b[i]) for i in 1:length(a)])

    @test size(SqState.reshape_cholesky(rand(5*5, 10))) == (5, 5, 10)
    @test size(SqState.cholesky2ρ(rand(5*5, 10))) == (2, 5, 5, 10)

    @test size(SqState.res_block((8, 4, 4, 1), (1, 15, 7), (0, 7, 3), 1, 0, 2)(rand(Float32, 1024, 8, 2))) == (512, 1, 2)
end

@testset "training" begin
    file = joinpath(SqState.model_path(), "test.jld2")
    SqState.update_model!(SqState.model_path(), "test", 1)
    @test isfile(file)
    rm(file)

    device = SqState.get_device()
    @test device == Flux.cpu || device == Flux.gpu
end

@testset "inference" begin
    m = SqState.get_model("q2args_sqth")
    @test size(m(rand(Float32, 2, 4096, 1))) == (3, 1)
end


text:
# https://juliaci.github.io/PkgBenchmark.jl/stable/run_benchmarks/
# https://github.com/JuliaCI/PkgBenchmark.jl/blob/master/benchmark/benchmarks.jl
using BenchmarkTools
using Distributions
using HMMBase
using PyCall

include("helpers.jl")

# hmmlearn
hmmlearn = pyimport("hmmlearn.hmm")

# pyhsmm
pyhsmm_viterbi = pyimport("pyhsmm.internals.hmm_messages_interface").viterbi
HMMStatesPython = pyimport("pyhsmm.internals.hmm_states").HMMStatesPython

const SUITE = BenchmarkGroup()

function randhmm(K)
    A = randtransmat(K)
    B = [Normal(rand() * 100, rand() * 10) for _ = 1:K]
    HMM(A, B)
end

HMMs = Dict([K => randhmm(K) for K = 2:2:10])
Ys = Dict([K => rand(HMMs[K], 5000) for K in keys(HMMs)])

# HMMBase

for f in (forward, backward, viterbi), (K, hmm) in HMMs
    LL = loglikelihoods(hmm, Ys[K])
    mkbench!(SUITE, ["hmmbase", f, K]) do
        @benchmarkable ($f)($hmm.a, $hmm.A, $LL)
    end
end

# pyhsmm

fs = [
    HMMStatesPython._messages_forwards_normalized,
    HMMStatesPython._messages_backwards_normalized,
]

for f in fs, (K, hmm) in HMMs
    LL = loglikelihoods(hmm, Ys[K])
    mkbench!(SUITE, ["pyhsmm", f, K]) do
        @benchmarkable ($f)($hmm.A, $hmm.a, $LL)
    end
end

for (K, hmm) in HMMs
    LL = loglikelihoods(hmm, Ys[K])
    buf = zeros(Int32, size(LL, 1))

    a = hmm.a
    A = PyReverseDims(permutedims(hmm.A))
    LL = PyReverseDims(permutedims(LL))

    mkbench!(SUITE, ["pyhsmm", "viterbi", K]) do
        @benchmarkable pyhsmm_viterbi($A, $LL, $a, $buf)
    end
end

# hmmlearn

function tohmmlearn(hmm::AbstractHMM)
    K = size(hmm, 1)
    model = hmmlearn.GaussianHMM(n_components = K, covariance_type = :diag)
    model.startprob_ = hmm.a
    model.transmat_ = hmm.A # permutedims(...) ?
    model.means_ = [d.μ for d in hmm.B]
    model._covars_ = reshape([d.σ^2 for d in hmm.B], (1, 1, :))
    model
end

fs = [:_do_forward_pass, :_do_backward_pass, :_do_viterbi_pass]

for f in fs, (K, hmm) in HMMs
    model = tohmmlearn(hmm)
    LL = loglikelihoods(hmm, Ys[K])
    mkbench!(SUITE, ["hmmlearn", f, K]) do
        @benchmarkable $(model).$(f)($LL)
    end
end


text:
using Revise
using Random
using Printf
using LinearAlgebra
using Distributions
using StatsBase
using StaticArrays
using POMDPs
using AutoViz
using AutomotiveDrivingModels
using AutomotivePOMDPs
using POMDPSimulators
using BeliefUpdaters
using ProgressMeter
using POMDPPolicies
using DeepQLearning
using Flux
using RLInterface
using POMDPModelTools
using TensorBoardLogger
using POMCPOW
includet("environment.jl")
includet("generative_mdp.jl")
includet("masking.jl")
includet("cooperative_IDM.jl")
includet("belief_updater.jl")
includet("belief_mdp.jl")
includet("overlays.jl")
includet("make_gif.jl");

rng = MersenneTwister(1)

mdp = GenerativeMergingMDP(random_n_cars=true, min_cars=10,max_cars=14, traffic_speed = :mixed, driver_type=:random,
                           observe_cooperation=true)
for i=2:mdp.max_cars+1
    mdp.driver_models[i] = CooperativeIDM()
end
pomdp = FullyObservablePOMDP(mdp)

solver = POMCPOWSolver(depth = 40,
                   exploration_constant = 1.0,
                   n_iterations = 100,
                   k_state  = 2.0,
                   alpha_state = 0.2,
                   keep_tree = true,
                   enable_action_pw = false,
                   rng = rng,
                    tree_in_info = true,
                  estimate_value = RolloutEstimator(RandomPolicy(mdp, rng=rng))
                   )

s0 = initialstate(pomdp, rng)

function initial_particles(s0::AugScene)
    driver_type_mask = [6, 9, 12, 15]
    ovec = convert_s(Vector{Float64})


text:
# ## Brusselator

# ## Model

# The Brusselator is a two ODEs theoretical model for autocatalytic reactions,
# where $x$ and $y$ are chemical concentrations:

module brusselator      #jl

using ReachabilityAnalysis

const A = 1.0
const B = 1.5
const B1 = B + 1

@taylorize function brusselator!(du, u, p, t)
    x, y = u
    x² = x * x
    aux = x² * y
    du[1] = A + aux - B1*x
    du[2] = B*x - aux
    return du
end

function model(X0)
    S = @system(x' = brusselator!(x), dim:2)
    return IVP(S, X0)
end

end #jl

# ## Reachability settings

# ## Results

# ## References

max_stars_repo_name: mforets/ReachabilityLibrary

max_issues_repo_name: mforets/ReachabilityLibrary

max_forks_repo_name: mforets/ReachabilityLibrary


text:
struct DMap

    params :: Tuple{Float64, Float64, Float64}
    d_to_c :: ConformalMap{Float64}
    c_to_d :: InverseConformalMap{Float64}

end

function DMap(ep, kapp, delta, Nv)

    params = (ep, kapp, delta)
    alpha = asin(delta)

    ts = LinRange(0, 2*pi, Nv+1)[1:Nv]
    verts = zeros(Nv, 2)
    verts[:,1] = ep*cos.(ts + alpha*sin.(ts))
    verts[:,2] = ep*kapp*sin.(ts)

    d_to_c = ConformalMap(verts, 0.0)
    c_to_d = inv(d_to_c)

    return DMap(params, d_to_c, c_to_d)
end

function (dm::DMap)(x::Float64, y::Float64)
    return dm.d_to_c(x + im*y)
end

function (dm::DMap)(z::Complex{Float64})
    zn = dm.c_to_d(z)
    return real(zn), imag(zn)
end

# function (dm::DMap)(psib::Function)
#
#     rs = dm.([exp(im*t) for t in LinRange(0, 2*pi, 1002)[1:1001]])
#     ts = [atan(r[2], r[1]) for r in rs]
#     psib_vec = psib.(ts)
#     C = fft(psib_vec)
#
#     c0 = real(C[1]) / 1001
#     a = 2*real.(C[2:501]) / 1001
#     b = -2*imag.(C[2:501]) / 1001
#
#     psi_v(z) = begin
#         r = abs(z)
#         t = angle(z)
#         return c0 + sum([(r/0.95)^k * (a[k]*cos(k*t) + b[k]*sin(k*t)) for k=1:500])
#     end
# end


text:
using NaiveBayes

using Test

include("core.jl")


text:
using AutoML
using Base.Test

# write your own tests here
@test 1 == 1

include("evaluation/mlogloss.jl")


text:
# La classe EarliestTimingSolver contient toutes les données
# nécessaires à la résolution du problème de timing pour seqata.
# Utilise la statégie de placement au plus tôt pour un ordre
# d'avions donné
mutable struct EarliestTimingSolver
    # inst contient l'instance initiale et ses données
    inst::Instance
    nb_calls::Int
    nb_infeasable::Int

    # Le constructeur
    function EarliestTimingSolver(inst::Instance)
        this=new()
        this.inst = inst
        this.nb_calls = 0
        this.nb_infeasable = 0
        return this
    end
end

# Permettre de retrouver le nom de notre XxxxTimingSolver à partir de l'objet
function symbol(sv::EarliestTimingSolver)
    return :earliest
end

function Base.show(io::IO, sv::EarliestTimingSolver)
    print(io, to_s(sv))
end

# Fonction d'affichage, to string
function to_s(sv::EarliestTimingSolver)
    buf = IOBuffer()
    print(buf, '\n')
    print(buf, "  nb_calls : ", sv.nb_calls)
    print(buf, "  nb_infeasable : ", sv.nb_infeasable)
    String(take!(buf))
end

"""
Résoud le sous-problème de timing (dates d'atterrissage) des avions à
permutation fixée par l'ordre des avions de l'objet sol, puis met à jour
la solution sol.
"""
function solve!(sv::EarliestTimingSolver, sol::Solution)
    sv.nb_calls += 1

    # On sous-traite le positionnement des dates x[] à l'une des méthodes de la
    # classe Solution.
    solve_to_earliest!(sol::Solution, do_update_cost=true)

    return nothing
end

# function test_earliest_timing_solver()
#     println("BEGIN EarliestTimingSolver")
#     inst = Instance("$(Args.appli)/data/ampl/01.ampl")
#     sv = EarliestTimingSolver(inst)
#     sol = Solution(inst)
#     solve!(sv, sol)
#     println(to_s_long(sol))
#     println("END EarliestTimingSolver")
# end


text:
# ----------------- Border methods ------------------------
@doc """
Holds infomation on the presence or absence of a border.
""" ->
type Border
    horizontal::Matrix{Bool}
    vertical::Matrix{Bool}
end

function Border(tbl::Table)
  n, m = size(tbl)
  return new(fill(false, n+1, m), fill(false, n, m+1))
end

size(brd::Border) = (size(brd.horizontal, 1), size(brd.vertical, 2))
function setindex!(brd::Border, cell, i, j)
  brd.vertical[i,j] |= cell.border.left
  brd.vertical[i,j+1] |= cell.border.right

  brd.horizontal[i,j] |= cell.border.top
  brd.horizontal[i+1,j] |= cell.border.bottom
end

function show(io::IO, brd::Border)
    println(io, "Horizontal Lines")
    show(io, brd.horizontal)

    println(io, "\n\nVertical Lines")
    show(io, brd.vertical)
end

function neighborlines(brd::Border, i, j)
    n, m = size(brd)

    hasleft   = j > 1
    hasright  = j < m
    hastop    = i > 1
    hasbottom = i < n

    left   = hasleft ? brd.horizontal[i,j-1] : false
    right  = hasright ? brd.horizontal[i,j] : false
    top    = hastop ? brd.vertical[i-1, j] : false
    bottom = hasbottom ? brd.vertical[i, j] : false

    return [left; right; top; bottom]
end

function getconnections(brd::Border)
    n, m = size(brd)

    res = Array(Char,n,m)
    for j=1:m
        for i=1:n
            res[i,j] = getconnector(neighborlines(brd, i, j))
        end
    end
    return res
end

function getverticals(brd::Border, i)
    m = size(brd.vertical, 2)
    res = zeros(Char, m)
    for j=1:m
        res[j] = brd.vertical[i,j] ? '\u2502' : ' '
    end
    return res
end

function gethorizontals(brd::Border, i)
    m = size(brd.horizontal, 2)
    res = zeros(Char, m)
    for j=1:m
        res[j] = brd.horizontal[i,j] ? '\u2500' : ' '
    end
    return res
end

function allblank(horizontals)
    for el in horizontals
        if el != ' '
            return false
        end
    end
    return true
end

function _init_border(tbl::Table)
  n, m = size(tbl)
  return fill(' ', n+1, m+1)
end
_init_data(tbl::Table) = fill(PlainCell, size(tbl))

function convert(::Type{PlainText}, tbl::Table)
  border = Border(tbl)
  data = _init_data(tbl)
end


text:
using Test
using Forecast

@testset "arsim" begin

    # arsim(Φ,Φ0,x0,n)
    Φ,Φ0,x0,n = .1,.2,.3,10
    x = arsim(Φ,Φ0,x0,n)
    @test x isa Vector
    @test length(x) == 10

    Φ,Φ0,x0,n = [.1,.2],.3,[.4,.5],10
    x = arsim(Φ,Φ0,x0,n)
    @test x isa Vector
    @test length(x) == 10

    Φ,Φ0,x0,n = [.1 .2; .3 .4],[.5, .6],[.7,.8],10
    x = arsim(Φ,Φ0,x0,n)
    @test x isa Matrix
    @test size(x) == (10,2)

    # arsim(Φ,Φ0,x0,Σ2,n)
    Φ,Φ0,x0,n,Σ2 = 1,0,1,3,0
    x = arsim(Φ,Φ0,x0,n;Σ2)
    @test x ≈ [1, 1, 1]

    Φ,Φ0,x0,n,Σ2 = 1,0,1,3,0
    x = arsim(Φ,Φ0,x0,n;Σ2,fix=[missing,2,missing])
    @test x ≈ [1, 2, 2]

    Φ,Φ0,x0,Σ2,n = .1,.2,.3,0.,3
    x = arsim(Φ,Φ0,x0,n;Σ2)
    @test x ≈ [0.23, 0.223, 0.2223]

    Φ,Φ0,x0,n,Σ2 = .1,.2,.3,10,.4
    x = arsim(Φ,Φ0,x0,n;Σ2)
    @test x isa Vector
    @test length(x) == 10

    Φ,Φ0,x0,n,Σ2 = [.1,.2],.3,[.4,.5],10,.6
    x = arsim(Φ,Φ0,x0,n;Σ2)
    @test x isa Vector
    @test length(x) == 10

    Φ,Φ0,x0,n,Σ2 = [.1 .2; .3 .4],[.5, .6],[.7,.8],10,[.9 .10; .10 .9]
    x = arsim(Φ,Φ0,x0,n;Σ2)
    @test x isa Matrix
    @test size(x) == (10,2)

    Φ,Φ0,x0,n,Σ2 = reshape([[.1 .2; .3 .4] [.5 .6; .7 .8]],2,2,2),
                  [.9, .10],[.11 .12; .13 .14],10,[.9 .10; .10 .9]
    x = arsim(Φ,Φ0,x0,n;Σ2)
    @test x isa Matrix
    @test size(x) == (10,2)

    # arsim(Φ,Φ0,x0,E,n)
    E = MvLogNormal(MvNormal(1,1))
    Φ,Φ0,x0,n = .1,.2,.3,10
    x = arsim(Φ,Φ0,x0,n;E)
    @test x isa Vector
    @test length(x) == 10

    Φ,Φ0,x0,n = [.1,.2],.3,[.4,.5],10
    x = arsim(Φ,Φ0,x0,n;E)
    @test x isa Vector
    @test length(x) == 10

    E = MvLogNormal(MvNormal(2,1))
    Φ,Φ0,x0,n = [.1 .2; .3 .4],[.5, .6],[.7,.8],10
    x = arsim(Φ,Φ0,x0,n;E)
    @test x isa Matrix
    @test size(x) == (10,2)

    E = MvNormal(2,1)
    Φ,Φ0,x0,n,Σ2 = reshape([[.1 .2; .3 .4] [.5 .6; .7 .8]],2,2,2),
    [.9, .10],[.11 .12; .13 .14],10,[.9 .10; .10 .9]
    x = arsim(Φ,Φ0,x0,n;E)
    @test x isa Matrix
    @test size(x) == (10,2)

    # arsim(AR,100)
    Φ,Φ0,x0,n,Σ2 = .1,.2,.3,1000,.4
    xar = ar(arsim(Φ,Φ0,x0,n;Σ2),1)
    x = arsim(xar,100)
    @test x isa Vector
    @test length(x) == 100

end