text:
using Clang.Generators
using MacroTools: @capture, postwalk, prettify
using PROJ_jll: artifact_dir
using JuliaFormatter: format

"create an optional argument expression"
kw(name, val) = Expr(:kw, name, val)

renames = Dict(:PJ_COORD => :Coord, :PROJ_STRING_LIST => :(Ptr{Cstring}))

function rewrite(ex::Expr)
    if @capture(ex, function fname_(fargs__)
        @ccall lib_.cname_(cargs__)::rettype_
    end)
        fargs′ = copy(fargs)
        # if ctx is the first argument, put it at the end as an optional argument
        if !isempty(fargs) && fargs[1] == :ctx
            fargs′ = circshift!(fargs′, fargs, -1)
            fargs′[end] = kw(:ctx, :C_NULL)
        end

        # make certain function arguments optional
        if fname === :proj_coord
            fargs′ = [:x, :y, kw(:z, 0.0), kw(:t, Inf)]
        elseif fname in (:proj_create_crs_to_crs, :proj_create_crs_to_crs_from_pj)
            fargs′[3] = kw(:area, :C_NULL)
        elseif fname === :proj_create_from_wkt
            fargs′[3] = kw(:out_warnings, :C_NULL)
            fargs′[4] = kw(:out_grammar_errors, :C_NULL)
        elseif fname === :proj_identify
            # put options behind out_confidence so we can make it optional
            fargs′ = reverse!(fargs′, 3, 4)
        end
        for (i, arg) in enumerate(fargs′)
            if arg === :options
                fargs′[i] = kw(:options, :C_NULL)
            end
        end

        # bind the ccall such that we can easily wrap it
        cc = :(@ccall $lib.$cname($(cargs...))::$rettype)
        cc′ = if rettype in [:Cstring, :(Ptr{Cstring})]
            :(aftercare($cc))
        else
            cc
        end

        # stitch the modified function expression back together
        f = :(function $fname($(fargs′...))
            $cc′
        end) |> prettify

        # rename some things
        f = postwalk(x -> get(renames, x, x), f)

        return f
    end
    return ex
end

function rewrite!(dag::ExprDAG)
    for node in get_nodes(dag)
        map!(rewrite, node.exprs, node.exprs)
    end
end

cd(@__DIR__)

include_dir = normpath(artifact_dir, "include")

# wrapper generator options
options = load_options(joinpath(@__DIR__, "generator.toml"))

args = get_default_args()
push!(args, "-I$include_dir")

headers = [joinpath(include_dir, "proj.h"), joinpath(include_dir, "geodesic.h")]

# create context
ctx = create_context(headers, args, options)

# run generator
build!(ctx, BUILDSTAGE_NO_PRINTING)
rewrite!(ctx.dag)
build!(ctx, BUILDSTAGE_PRINTING_ONLY)

# run JuliaFormatter on the whole package
format(joinpath(@__DIR__, ".."))


text:
import Pkg
Pkg.add("JuMP")
Pkg.add("Cbc")

using Cbc
using JuMP

include("dataGoogle.jl")
include("checker.jl")
include("run.jl")

#main(instanceFilename, assignmentFilename, verbose)

ext: jl


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

module SPQR

import Base: \

# ordering options */
const ORDERING_FIXED   = Int32(0)
const ORDERING_NATURAL = Int32(1)
const ORDERING_COLAMD  = Int32(2)
const ORDERING_GIVEN   = Int32(3) # only used for C/C++ interface
const ORDERING_CHOLMOD = Int32(4) # CHOLMOD best-effort (COLAMD, METIS,...)
const ORDERING_AMD     = Int32(5) # AMD(A'*A)
const ORDERING_METIS   = Int32(6) # metis(A'*A)
const ORDERING_DEFAULT = Int32(7) # SuiteSparseQR default ordering
const ORDERING_BEST    = Int32(8) # try COLAMD, AMD, and METIS; pick best
const ORDERING_BESTAMD = Int32(9) # try COLAMD and AMD; pick best#

# Let [m n] = size of the matrix after pruning singletons.  The default
# ordering strategy is to use COLAMD if m <= 2*n.  Otherwise, AMD(A'A) is
# tried.  If there is a high fill-in with AMD then try METIS(A'A) and take
# the best of AMD and METIS. METIS is not tried if it isn't installed.

using ..SparseArrays: SparseMatrixCSC
using ..SparseArrays.CHOLMOD
using ..SparseArrays.CHOLMOD: change_stype!, free!

function _qr!(ordering::Integer, tol::Real, econ::Integer, getCTX::Integer,
        A::Sparse{Tv},
        Bsparse::Union{Sparse{Tv}                      , Ptr{Void}} = C_NULL,
        Bdense::Union{Dense{Tv}                        , Ptr{Void}} = C_NULL,
        Zsparse::Union{Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}  , Ptr{Void}} = C_NULL,
        Zdense::Union{Ref{Ptr{CHOLMOD.C_Dense{Tv}}}    , Ptr{Void}} = C_NULL,
        R::Union{Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}        , Ptr{Void}} = C_NULL,
        E::Union{Ref{Ptr{CHOLMOD.SuiteSparse_long}}    , Ptr{Void}} = C_NULL,
        H::Union{Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}        , Ptr{Void}} = C_NULL,
        HPinv::Union{Ref{Ptr{CHOLMOD.SuiteSparse_long}}, Ptr{Void}} = C_NULL,
        HTau::Union{Ref{Ptr{CHOLMOD.C_Dense{Tv}}}      , Ptr{Void}} = C_NULL) where {Tv<:CHOLMOD.VTypes}

    AA   = unsafe_load(pointer(A))
    m, n = AA.nrow, AA.ncol
    rnk  = ccall((:SuiteSparseQR_C, :libspqr), CHOLMOD.SuiteSparse_long,
        (Cint, Cdouble, CHOLMOD.SuiteSparse_long, Cint,
         Ptr{CHOLMOD.C_Sparse{Tv}}, Ptr{CHOLMOD.C_Sparse{Tv}}, Ptr{CHOLMOD.C_Dense{Tv}},
         Ptr{Ptr{CHOLMOD.C_Sparse{Tv}}}, Ptr{Ptr{CHOLMOD.C_Dense{Tv}}}, Ptr{Ptr{CHOLMOD.C_Sparse{Tv}}},
         Ptr{Ptr{CHOLMOD.SuiteSparse_long}}, Ptr{Ptr{CHOLMOD.C_Sparse{Tv}}}, Ptr{Ptr{CHOLMOD.SuiteSparse_long}},
         Ptr{Ptr{CHOLMOD.C_Dense{Tv}}}, Ptr{Void}),
        ordering,       # all, except 3:given treated as 0:fixed
        tol,            # columns with 2-norm <= tol treated as 0
        econ,           # e = max(min(m,econ),rank(A))
        getCTX,         # 0: Z=C (e-by-k), 1: Z=C', 2: Z=X (e-by-k)
        A,              # m-by-n sparse matrix to factorize
        Bsparse,        # sparse m-by-k B
        Bdense,         # dense  m-by-k B
        # /* outputs: */
        Zsparse,        # sparse Z
        Zdense,         # dense Z
        R,              # e-by-n sparse matrix */
        E,              # size n column perm, NULL if identity */
        H,              # m-by-nh Householder vectors
        HPinv,          # size m row permutation
        HTau,           # 1-by-nh Householder coefficients
        CHOLMOD.common_struct) # /* workspace and parameters */

    if rnk < 0
        error("Sparse QR factorization failed")
    end

    e = E[]
    if e == C_NULL
        _E = Vector{CHOLMOD.SuiteSparse_long}()
    else
        _E = Vector{CHOLMOD.SuiteSparse_long}(n)
        for i in 1:n
            @inbounds _E[i] = unsafe_load(e, i) + 1
        end
        # Free memory allocated by SPQR. This call will make sure that the
        # correct deallocator function is called and that the memory count in
        # the common struct is updated
        ccall((:cholmod_l_free, :libcholmod), Void,
            (Csize_t, Cint, Ptr{CHOLMOD.SuiteSparse_long}, Ptr{Void}),
            n, sizeof(CHOLMOD.SuiteSparse_long), e, CHOLMOD.common_struct)
    end
    hpinv = HPinv[]
    if hpinv == C_NULL
        _HPinv = Vector{CHOLMOD.SuiteSparse_long}()
    else
        _HPinv = Vector{CHOLMOD.SuiteSparse_long}(m)
        for i in 1:m
            @inbounds _HPinv[i] = unsafe_load(hpinv, i) + 1
        end
        # Free memory allocated by SPQR. This call will make sure that the
        # correct deallocator function is called and that the memory count in
        # the common struct is updated
        ccall((:cholmod_l_free, :libcholmod), Void,
            (Csize_t, Cint, Ptr{CHOLMOD.SuiteSparse_long}, Ptr{Void}),
            m, sizeof(CHOLMOD.SuiteSparse_long), hpinv, CHOLMOD.common_struct)
    end

    return rnk, _E, _HPinv
end

# Struct for storing sparse QR from SPQR such that
# A[invperm(rpivinv), cpiv] = (I - factors[:,1]*τ[1]*factors[:,1]')*...*(I - factors[:,k]*τ[k]*factors[:,k]')*R
# with k = size(factors, 2).
struct QRSparse{Tv,Ti} <: LinAlg.Factorization{Tv}
    factors::SparseMatrixCSC{Tv,Ti}
    τ::Vector{Tv}
    R::SparseMatrixCSC{Tv,Ti}
    cpiv::Vector{Ti}
    rpivinv::Vector{Ti}
end

Base.size(F::QRSparse) = (size(F.factors, 1), size(F.R, 2))
function Base.size(F::QRSparse, i::Integer)
    if i == 1
        return size(F.factors, 1)
    elseif i == 2
        return size(F.R, 2)
    elseif i > 2
        return 1
    else
        throw(ArgumentError("second argument must be positive"))
    end
end

struct QRSparseQ{Tv<:CHOLMOD.VTypes,Ti<:Integer} <: LinAlg.AbstractQ{Tv}
    factors::SparseMatrixCSC{Tv,Ti}
    τ::Vector{Tv}
end

Base.size(Q::QRSparseQ) = (size(Q.factors, 1), size(Q.factors, 1))

# From SPQR manual p. 6
_default_tol(A::SparseMatrixCSC) =
    20*sum(size(A))*eps(real(eltype(A)))*maximum(norm(view(A, :, i))^2 for i in 1:size(A, 2))

function Base.LinAlg.qrfact(A::SparseMatrixCSC{Tv}; tol = _default_tol(A)) where {Tv <: CHOLMOD.VTypes}
    R     = Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}()
    E     = Ref{Ptr{CHOLMOD.SuiteSparse_long}}()
    H     = Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}()
    HPinv = Ref{Ptr{CHOLMOD.SuiteSparse_long}}()
    HTau  = Ref{Ptr{CHOLMOD.C_Dense{Tv}}}(C_NULL)

    # SPQR doesn't accept symmetric matrices so we explicitly set the stype
    r, p, hpinv = _qr!(ORDERING_DEFAULT, tol, 0, 0, Sparse(A, 0),
        C_NULL, C_NULL, C_NULL, C_NULL,
        R, E, H, HPinv, HTau)

    return QRSparse(SparseMatrixCSC(Sparse(H[])),
                    vec(Array(CHOLMOD.Dense(HTau[]))),
                    SparseMatrixCSC(Sparse(R[])),
                    p, hpinv)
end

"""
    qrfact(A) -> QRSparse

Compute the `QR` factorization of a sparse matrix `A`. Fill-reducing row and column permutations
are used such that `F[:R] = F[:Q]'*A[F[:prow],F[:pcol]]`. The main application of this type is to
solve least squares or underdetermined problems with [`\\`](@ref). The function calls the C library SPQR.

# Examples
```jldoctest
julia> A = sparse([1,2,3,4], [1,1,2,2], ones(4))
4×2 SparseMatrixCSC{Float64,Int64} with 4 stored entries:
  [1, 1]  =  1.0
  [2, 1]  =  1.0
  [3, 2]  =  1.0
  [4, 2]  =  1.0

julia> qrfact(A)
Base.SparseArrays.SPQR.QRSparse{Float64,Int64}
Q factor:
4×4 Base.SparseArrays.SPQR.QRSparseQ{Float64,Int64}:
 -0.707107   0.0        0.0       -0.707107
  0.0       -0.707107  -0.707107   0.0
  0.0       -0.707107   0.707107   0.0
 -0.707107   0.0        0.0        0.707107
R factor:
2×2 SparseMatrixCSC{Float64,Int64} with 2 stored entries:
  [1, 1]  =  -1.41421
  [2, 2]  =  -1.41421
Row permutation:
4-element Array{Int64,1}:
 1
 3
 4
 2
Column permutation:
2-element Array{Int64,1}:
 1
 2
```
"""
Base.LinAlg.qrfact(A::SparseMatrixCSC; tol = _default_tol(A)) = qrfact(A, Val{true}, tol = tol)

Base.LinAlg.qr(A::SparseMatrixCSC; tol = _default_tol(A)) = qr(A, Val{true}, tol = tol)

function Base.A_mul_B!(Q::QRSparseQ, A::StridedVecOrMat)
    if size(A, 1) != size(Q, 1)
        throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))"))
    end
    for l in size(Q.factors, 2):-1:1
        τl = -Q.τ[l]
        h = view(Q.factors, :, l)
        for j in 1:size(A, 2)
            a = view(A, :, j)
            LinAlg.axpy!(τl*dot(h, a), h, a)
        end
    end
    return A
end

function Base.A_mul_B!(A::StridedMatrix, Q::QRSparseQ)
    if size(A, 2) != size(Q, 1)
        throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))"))
    end
    tmp = similar(A, size(A, 1))
    for l in 1:size(Q.factors, 2)
        τl = -Q.τ[l]
        h = view(Q.factors, :, l)
        A_mul_B!(tmp, A, h)
        LinAlg.lowrankupdate!(A, tmp, h, τl)
    end
    return A
end

function Base.Ac_mul_B!(Q::QRSparseQ, A::StridedVecOrMat)
    if size(A, 1) != size(Q, 1)
        throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))"))
    end
    for l in 1:size(Q.factors, 2)
        τl = -Q.τ[l]
        h = view(Q.factors, :, l)
        for j in 1:size(A, 2)
            a = view(A, :, j)
            LinAlg.axpy!(τl'*dot(h, a), h, a)
        end
    end
    return A
end

function Base.A_mul_Bc!(A::StridedMatrix, Q::QRSparseQ)
    if size(A, 2) != size(Q, 1)
        throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))"))
    end
    tmp = similar(A, size(A, 1))
    for l in size(Q.factors, 2):-1:1
        τl = -Q.τ[l]
        h = view(Q.factors, :, l)
        A_mul_B!(tmp, A, h)
        LinAlg.lowrankupdate!(A, tmp, h, τl')
    end
    return A
end

Base.LinAlg.getq(F::QRSparse) = QRSparseQ(F.factors, F.τ)

"""
    getindex(F::QRSparse, d::Symbol)

Extract factors of a QRSparse factorization. Possible values of `d` are
- `:Q` : `QRSparseQ` matrix of the ``Q`` factor in Householder form
- `:R` : `UpperTriangular` ``R`` factor
- `:prow` : Vector of the row permutations applied to the factorized matrix
- `:pcol` : Vector of the column permutations applied to the factorized matrix

# Examples
```jldoctest
julia> F = qrfact(sparse([1,3,2,3,4], [1,1,2,3,4], [1.0,2.0,3.0,4.0,5.0]));

julia> F[:Q]
4×4 Base.SparseArrays.SPQR.QRSparseQ{Float64,Int64}:
 1.0  0.0  0.0  0.0
 0.0  1.0  0.0  0.0
 0.0  0.0  1.0  0.0
 0.0  0.0  0.0  1.0

julia> F[:R]
4×4 SparseMatrixCSC{Float64,Int64} with 5 stored entries:
  [1, 1]  =  3.0
  [2, 2]  =  4.0
  [3, 3]  =  5.0
  [2, 4]  =  2.0
  [4, 4]  =  1.0

julia> F[:prow]
4-element Array{Int64,1}:
 2
 3
 4
 1

julia> F[:pcol]
4-element Array{Int64,1}:
 2
 3
 4
 1
```
"""
function Base.getindex(F::QRSparse, d::Symbol)
    if d == :Q
        return LinAlg.getq(F)
    elseif d == :R
        return F.R
    elseif d == :prow
        return invperm(F.rpivinv)
    elseif d == :pcol
        return F.cpiv
    else
        throw(KeyError(d))
    end
end

function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, F::QRSparse)
    println(io, summary(F))
    println(io, "Q factor:")
    show(io, mime, F[:Q])
    println(io, "\nR factor:")
    show(io, mime, F[:R])
    println(io, "\nRow permutation:")
    show(io, mime, F[:prow])
    println(io, "\nColumn permutation:")
    show(io, mime, F[:pcol])
end

# With a real lhs and complex rhs with the same precision, we can reinterpret
# the complex rhs as a real rhs with twice the number of columns
#
# This definition is similar to the definition in factorization.jl except that
# here we have to use \ instead of A_ldiv_B! because of limitations in SPQR

## Two helper methods
_ret_size(F::QRSparse, b::AbstractVector) = (size(F, 2),)
_ret_size(F::QRSparse, B::AbstractMatrix) = (size(F, 2), size(B, 2))

function (\)(F::QRSparse{Float64}, B::VecOrMat{Complex{Float64}})
# |z1|z3|  reinterpret  |x1|x2|x3|x4|  transpose  |x1|y1|  reshape  |x1|y1|x3|y3|
# |z2|z4|      ->       |y1|y2|y3|y4|     ->      |x2|y2|     ->    |x2|y2|x4|y4|
#                                                 |x3|y3|
#                                                 |x4|y4|
    c2r = reshape(transpose(reinterpret(Float64, B, (2, length(B)))), size(B, 1), 2*size(B, 2))
    x = F\c2r

# |z1|z3|  reinterpret  |x1|x2|x3|x4|  transpose  |x1|y1|  reshape  |x1|y1|x3|y3|
# |z2|z4|      <-       |y1|y2|y3|y4|     <-      |x2|y2|     <-    |x2|y2|x4|y4|
#                                                 |x3|y3|
#                                                 |x4|y4|
    return reinterpret(Complex{Float64}, transpose(reshape(x, (length(x) >> 1), 2)), _ret_size(F, B))
end

function _ldiv_basic(F::QRSparse, B::StridedVecOrMat)
    if size(F, 1) != size(B, 1)
        throw(DimensionMismatch("size(F) = $(size(F)) but size(B) = $(size(B))"))
    end

    # The rank of F equal to the number of rows in R
    rnk = size(F.R, 1)

    # allocate an array for the return value large enough to hold B and X
    # For overdetermined problem, B is larger than X and vice versa
    X   = similar(B, ntuple(i -> i == 1 ? max(size(F, 2), size(B, 1)) : size(B, 2), Val(ndims(B))))

    # Fill will zeros. These will eventually become the zeros in the basic solution
    # fill!(X, 0)
    # Apply left permutation to the solution and store in X
    for j in 1:size(B, 2)
        for i in 1:length(F.rpivinv)
            @inbounds X[F.rpivinv[i], j] = B[i, j]
        end
    end

    # Make a view into X corresponding to the size of B
    X0 = view(X, 1:size(B, 1), :)

    # Apply Q' to B
    Ac_mul_B!(LinAlg.getq(F), X0)

    # Zero out to get basic solution
    X[rnk + 1:end, :] = 0

    # Solve R*X = B
    A_ldiv_B!(UpperTriangular(view(F.R, :, Base.OneTo(rnk))), view(X0, Base.OneTo(rnk), :))

    # Apply right permutation and extract solution from X
    return getindex(X, ntuple(i -> i == 1 ? invperm(F.cpiv) : :, Val(ndims(B)))...)
end

(\)(F::QRSparse{T}, B::StridedVecOrMat{T}) where {T} = _ldiv_basic(F, B)
"""
    (\\)(F::QRSparse, B::StridedVecOrMat)

Solve the least squares problem ``\\min\\|Ax - b\\|^2`` or the linear system of equations
``Ax=b`` when `F` is the sparse QR factorization of ``A``. A basic solution is returned
when the problem is underdetermined.

# Examples
```jldoctest
julia> A = sparse([1,2,4], [1,1,1], ones(3), 4, 2)
4×2 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
  [1, 1]  =  1.0
  [2, 1]  =  1.0
  [4, 1]  =  1.0

julia> qrfact(A)\\ones(4)
2-element Array{Float64,1}:
 1.0
 0.0
```
"""
(\)(F::QRSparse, B::StridedVecOrMat) = F\convert(AbstractArray{eltype(F)}, B)

end # module

max_stars_repo_name: visr/julia

max_issues_repo_name: visr/julia

max_forks_repo_name: visr/julia


text:
using .HyperDualNumbers

function blkimpv_hyper(num1, num2, num3, num4, num5)
    @eval function blkimpv(S0::$num1, K::$num2, r::$num3, T::$num4, Price::$num5, FlagIsCall::Bool = true, xtol::Real = 1e-14, ytol::Real = 1e-15)
        blscheck(S0, K, r, T, 0.1, r)

        return blsimpv(S0, K, r, T, Price, r, FlagIsCall)
    end
end

type_blkimpv_hyper_1 = [Hyper, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}]
type_blkimpv_hyper_2 = [Real, Hyper, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}]
type_blkimpv_hyper_3 = [Real, Real, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}]
blkimpv_hyper(type_blkimpv_hyper_1[1], type_blkimpv_hyper_1[2], type_blkimpv_hyper_1[3], type_blkimpv_hyper_1[4], type_blkimpv_hyper_1[5])
blkimpv_hyper(type_blkimpv_hyper_2[1], type_blkimpv_hyper_2[2], type_blkimpv_hyper_2[3], type_blkimpv_hyper_2[4], type_blkimpv_hyper_2[5])
blkimpv_hyper(type_blkimpv_hyper_3[1], type_blkimpv_hyper_3[2], type_blkimpv_hyper_3[3], type_blkimpv_hyper_3[4], type_blkimpv_hyper_3[5])

function blsimpv_hyper(num1, num2, num3, num4, num5, num6)
    @eval function blsimpv(S0::$num1, K::$num2, r::$num3, T::$num4, Price::$num5, d::$num6 = 0.0, FlagIsCall::Bool = true, xtol::Real = 1e-14, ytol::Real = 1e-15)
        if (Price < 0)
            throw(ErrorException("Option Price Cannot Be Negative"))
        end
        FinancialToolbox.blscheck(S0, K, r, T, 0.1, d)
        value__(x) = x.value
        value__(x::Real) = x
        f(x) = (blsprice(value__(S0), value__(K), value__(r), value__(T), x, value__(d), FlagIsCall) - value__(Price))
        σ = FinancialToolbox.brentMethod(f, 0.001, 1.2, xtol, ytol)
        out = hyper(0.0)
        if (!ishyper(Price))
            der_ = -(blsprice(S0, K, r, T, σ, d, FlagIsCall) / blsvega(value__(S0), value__(K), value__(r), value__(T), σ, value__(d), FlagIsCall)).epsilon1
            der_2 = ((blsprice(S0, K, r, T, σ, d, FlagIsCall).epsilon12 + blsvega(S0, K, r, T, σ, d, FlagIsCall).epsilon1 * der_) * blsvega(value__(S0), value__(K), value__(r), value__(T), σ, value__(d), FlagIsCall) - blsprice(S0, K, r, T, σ, d, FlagIsCall).epsilon1 * (blsvega(S0, K, r, T, σ, d, FlagIsCall).epsilon1 + blsvega(value__(S0), value__(K), value__(r), value__(T), hyper(σ, 1.0, 1.0, 0.0), value__(d), FlagIsCall).epsilon1 * der_)) / (blsvega(value__(S0), value__(K), value__(r), value__(T), σ, value__(d), FlagIsCall)^2)
            out = hyper(σ, der_, der_, -der_2)
        else
            der_ = 1 / blsvega(value__(S0), value__(K), value__(r), value__(T), σ, value__(d), FlagIsCall)
            der_2 = -(blsprice(S0, K, r, T, hyper(σ, 1.0, 1.0, 0.0), d, FlagIsCall).epsilon12) / (blsvega(value__(S0), value__(K), value__(r), value__(T), σ, value__(d), FlagIsCall)^3)
            out = hyper(σ, der_, der_, der_2)
        end

        return out
    end
end

type_blsimpv_hyper_1 = [Hyper, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}]
type_blsimpv_hyper_2 = [Real, Hyper, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}]
type_blsimpv_hyper_3 = [Real, Real, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}, Union{Real, Hyper}]
blsimpv_hyper(type_blsimpv_hyper_1[1], type_blsimpv_hyper_1[2], type_blsimpv_hyper_1[3], type_blsimpv_hyper_1[4], type_blsimpv_hyper_1[5], type_blsimpv_hyper_1[6])
blsimpv_hyper(type_blsimpv_hyper_2[1], type_blsimpv_hyper_2[2], type_blsimpv_hyper_2[3], type_blsimpv_hyper_2[4], type_blsimpv_hyper_2[5], type_blsimpv_hyper_2[6])
blsimpv_hyper(type_blsimpv_hyper_3[1], type_blsimpv_hyper_3[2], type_blsimpv_hyper_3[3], type_blsimpv_hyper_3[4], type_blsimpv_hyper_3[5], type_blsimpv_hyper_3[6])


text:
struct OnePositions{T<:Integer}
    x :: T
end
IteratorSize(::Type{OnePositions}) = HasLength()
Base.length(op::OnePositions) = count_ones(op.x)
IteratorEltype(::Type{OnePositions}) = HasEltype()
Base.eltype(op::OnePositions{T}) where {T<:Integer}= T
function Base.iterate(op::OnePositions{T}) where {T<:Integer}
    number_of_ones = length(op)
    number_of_ones == zero(T) && return nothing
    remaining_ones = number_of_ones-one(T)
    first_one_position = trailing_zeros(op.x)+one(T)
    (first_one_position,(remaining_ones,first_one_position))
end
function Base.iterate(op::OnePositions{T}, state) where {T<:Integer}
    remaining_ones,previous_one_position = state
    x = op.x
    remaining_ones==zero(T) && return nothing
    remaining_ones-=one(T)
    shifted=x>>>(previous_one_position)
    this_one_position = trailing_zeros(shifted)+previous_one_position+one(T)
    (this_one_position,(remaining_ones,this_one_position))
end

function Base.getindex(a::AbstractArray ,op::OnePositions{T})  where T
    [a[x] for x in op]
end
function Base.setindex!(a::BitArray{1}, x::Union{Bool,Integer}, op::OnePositions)
    for i in op
        a[i] = x
    end
end

# Similar performance to sum(a[pos]).  Probably do not need this.
function sum_one_positions(a::Vector{T}, pos::OnePositions) where T
    s = zero(T)
    for e in pos
        s+=e
    end
    s
end


text:
using Combinatorics

for sequence in permutations(5:9)
    print("ncat -l -o results/$(sequence[1])$(sequence[2])$(sequence[3])$(sequence[4])$(sequence[5]).txt localhost 60001 ");
    for i in 1:length(sequence)
        print("| julia aoc-2019-07.jl input.txt $(sequence[i]) ");
        if i == 1
            print("0 ")
        end
    end
    println("| ncat localhost 60001");
end


text:
function FieldRecordAndContinue()
    return FieldRecordAndContinue(())
end

function FieldRecordAndContinue(arg0::List)
    return FieldRecordAndContinue((List,), arg0)
end

function clear(obj::FieldRecordAndContinue)
    return jcall(obj, "clear", void, ())
end

function event_occurred(obj::FieldRecordAndContinue, arg0::FieldSpacecraftState, arg1::FieldEventDetector, arg2::jboolean)
    return jcall(obj, "eventOccurred", Action, (FieldSpacecraftState, FieldEventDetector, jboolean), arg0, arg1, arg2)
end

function get_events(obj::FieldRecordAndContinue)
    return jcall(obj, "getEvents", List, ())
end

function reset_state(obj::FieldRecordAndContinue, arg0::FieldEventDetector, arg1::FieldSpacecraftState)
    return jcall(obj, "resetState", FieldSpacecraftState, (FieldEventDetector, FieldSpacecraftState), arg0, arg1)
end


text:
function encode(s)
    map(r -> "$(length(r) > 1 ? length(r) : "")$(s[r[1]])"
    , findall(r"(.)\1*",s)) |> join
end

function decode(s)
    map(r -> begin
            count_str = s[r[1:end-1]]
            count = isempty(count_str) ? 1 : parse(Int,count_str)
            repeat(s[r[end]],count)
        end,
        findall(r"[0-9]*[^0-9]",s)
    ) |> join
end

# This chap's solution is neat - it's similar to my first attempt (not shown)
# but uses an IOBuffer to get past the slowness of constantly appending to strings
# https://exercism.io/tracks/julia/exercises/run-length-encoding/solutions/e30fdad5ddec41439f749e321e076d1b
function outputrun!(buf, char, length)
    if length == 0
        return # do nothing
    elseif length == 1
        print(buf, char)
    else
        print(buf, length)
        print(buf, char)
    end
end

function encode(s)
    runchar = 'a' # arbitrary
    runlength = 0
    buf = IOBuffer()
    for char in s
        if char == runchar
            runlength += 1
        else
            outputrun!(buf, runchar, runlength)
            runlength = 1
            runchar = char
        end
    end
    outputrun!(buf, runchar, runlength)
    String(take!(buf))
end

# NB: code for old Julia, needs updating
# function decode2(buf, char, length)
#     for i in 1:length
#         print(buf, char)
#     end
# end
#
# function decode(s)
#     buf = IOBuffer()
#     numbuf = IOBuffer()
#     for char in s
#         if isalpha(char) || isspace(char)
#             size = 1
#             if numbuf.size > 0
#                 size = parse(Int64, String(take!(numbuf)))
#             end
#             decode2(buf, char, size)
#         else
#             @assert isnumber(char)
#             print(numbuf, char)
#         end
#     end
#     String(take!(buf))
# end


text:
module ForTheBadge

    using Colors
    using Luxor
    using Luxor: julia_blue, julia_purple, julia_green, julia_red

    """
        badge(
            labels; # must be the same length as kwargs, so if you
            fonts = ("Roboto Medium", "Montserrat ExtraBold")
            bgcolours = (colorant"#a7bfc1", colorant"#5593c8"),
            textcolours = (colorant"white", colorant"white"),
            padding = 13,
            h = 50,
            ext = :pdf,
            filename = join(labels, "_") * ".\$ext",
            textsize = 20,
            texttype = :path,
            showbadge = true
        )

        badge(labels...; kwargs...)

    Provided labels, font sizes and colours of the appropriate type,
    this function will create a badge in the style of (ForTheBadge)[https://forthebadge.com/].

    Input must be in the form of tuples.

    ## Keyword arguments

        * `texttype` may be `:path` or `:text`.
        * `ext` may be `:pdf`, `:png`, or `:svg`.
        * `showbadge` controls whether the badge is opened
          by the system viewer after it is drawn.

    ## Examples:

    ```julia
    # To generate the logo:
    badge(
        "FOR", "THE", "BADGE", ".jl";
        filename = "logo.svg",
        textcolours = (colorant"white", colorant"white", colorant"white", colorant"white"),
        bgcolours = (julia_green, julia_purple, julia_red, julia_blue),
        fonts = ("Roboto Medium", "Roboto Medium", "Montserrat ExtraBold", "Roboto Medium")
    )
    ```
    """
    function badge(
            labels;
            fonts = ("$(@__DIR__)../assets/fonts/Roboto-Medium.ttf", "$(@__DIR__)../assets/fonts/Montserrat-ExtraBold.otf"),
            bgcolours = (colorant"#a7bfc1", colorant"#5593c8"),
            textcolours = (colorant"white", colorant"white"),
            padding = 13,
            h = 50,
            ext = :pdf,
            filename = join(labels, "_") * ".$ext",
            textsize = 20,
            texttype = :path,
            showbadge = true
        ) where N where T

        @assert length(labels) == length(fonts) == length(bgcolours) == length(textcolours)

        Drawing(800, h, :png) # initialize a dummy, in-memory drawing to get text extents

        fontsize(textsize) # set the font size

        rawextents = [begin fontface(fonts[i]); ceil(textextents(labels[i])[3]) + padding * 2 end for i in eachindex(labels)]
        finish()
        pushfirst!(rawextents, 0.0)

        extents = [sum(rawextents[1:i]) for i in eachindex(rawextents)]

        xlength = sum(rawextents)

        midpoints = ((rawextents[i]) / 2 + ((i == zero(typeof(i))) ? 0 : sum(rawextents[1:i-1])) for i in eachindex(extents)) |> collect

        Drawing(xlength, h, filename)

        for (k, p) in enumerate(midpoints[2:end])
            sethue(bgcolours[k])
            box(Point(extents[k], 0), Point(extents[k+1], 50), :fill)
            sethue(textcolours[k])
            fontface(fonts[k])
            fontsize(textsize)
            textoutlines(labels[k], Point(p, 25), halign=:center, valign=:middle)
            fillpreserve()
        end

        finish()

        showbadge && preview()

        filename
    end

    badge(labels...; kwargs...) = badge(Tuple(labels); kwargs...)

    export badge

    export julia_blue, julia_purple, julia_green, julia_red

end


text:
"""
Modia module with translational component models (inspired from Modelica Standard Library).

* Developer: Hilding Elmqvist, Mogram AB, Martin Otter, DLR
* Copyright (c) 2021: Hilding Elmqvist, Martin Otter
* License: MIT (expat)

"""
#module Rotational

#export Flange, Inertia, Spring, SpringDamper, EMF, IdealGear, Torque, CurrentSensor, Fixed, Damper, IdealGear_withSupport, SpeedSensor

using TinyModia
using Unitful

# Connector for 1D translational systems
TranslationalFlange = Model(
    s = potential,  # Absolute position of flange
    f = flow        # Cut force directed into the flange
)

# Flange fixed in housing at a given position
FixedPosition = Model(
    flange = TranslationalFlange,
    equations = :[
        flange.s = 0.0]
)

# Rigid connection of two translational 1D flanges
PartialRigid = Model(
    flange_a = TranslationalFlange,
    flange_b = TranslationalFlange,
    L = 0.0u"m",                # Length of component, from left flange to right flange
    partialEquations = :[
        flange_a.s = s - L/2
        flange_b.s = s + L/2]
)

# 1D-translational mass
TranslationalMass = PartialRigid | Model(
    flange_a = TranslationalFlange, # (info = "Left flange of mass")
    flange_b = TranslationalFlange, # (info = "Right flange of mass")
    m = 1.0u"kg",                   # Mass of sliding mass
    s = Var(init = 0.0u"m"),        # Absolute position of center of component
    v = Var(init = 0.0u"m/s"),
    equations = :[
        v = der(s)
        m*der(v) = flange_a.f + flange_b.f]
)

# Partial input signal acting as external force on a flange
PartialForce = Model(
    f      = input,
    flange = TranslationalFlange
)

# Input signal acting as external torque on a flange
Force         = PartialForce | Model(equations = :[flange.f = -f])
UnitlessForce = PartialForce | Model(equations = :[flange.f = -f*u"N"])

# Partial model to measure a single absolute flange variable
PartialAbsoluteSensor = Model(
    flange   = TranslationalFlange,
    equation = :[flange.f = 0]
)

# Ideal sensor to measure the absolute flange position and velocity
VelocitySensor         = PartialAbsoluteSensor | Model(v = output, equations = :[v = der(flange.s)])
UnitlessVelocitySensor = PartialAbsoluteSensor | Model(v = output, equations = :[v = der(flange.s)*u"m/s"])

PositionSensor         = PartialAbsoluteSensor | Model(s = output, equations = :[s = flange.s])
UnitlessPositionSensor = PartialAbsoluteSensor | Model(s = output, equations = :[s = flange.s*u"m"])

#end


text:
# The function rref(), but with the modification that it also returns the pivot vector

export rref_with_pivots, rref_with_pivots!

function rref_with_pivots!(A::Matrix{T}, ɛ=T <: Union{Rational,Integer} ? 0 : eps(norm(A,Inf))) where T
    nr, nc = size(A)
    pivots = Vector{Int64}()
    i = j = 1
    while i <= nr && j <= nc
        (m, mi) = findmax(abs.(A[i:nr,j]))
        mi = mi+i - 1
        if m <= ɛ
            if ɛ > 0
                A[i:nr,j] .= zero(T)
            end
            j += 1
        else
            for k=j:nc
                A[i, k], A[mi, k] = A[mi, k], A[i, k]
            end
            d = A[i,j]
            for k = j:nc
                A[i,k] /= d
            end
            for k = 1:nr
                if k != i
                    d = A[k,j]
                    for l = j:nc
                        A[k,l] -= d*A[i,l]
                    end
                end
            end
            append!(pivots,j)
            i += 1
            j += 1
        end
    end
    return A, pivots
end

rref_with_pivots_conv(::Type{T}, A::Matrix) where {T} = rref_with_pivots!(copyto!(similar(A, T), A))

"""
    rref_with_pivots(A)
Compute the reduced row echelon form of the matrix A together with the
position of the pivots.
Since this algorithm is sensitive to numerical imprecision,
* Complex numbers are converted to ComplexF64
* Integer, Float16 and Float32 numbers are converted to Float64
* Rational are kept unchanged

```jldoctest
julia> rref_with_pivots([ 1  2 -1  -4;
              2  3 -1 -11;
             -2  0 -3  22])
3×4 Array{Float64,2}:
 1.0  0.0  0.0  -8.0
 0.0  1.0  0.0   1.0
 0.0  0.0  1.0  -2.0
 Int64[3]:
 1
 2
 3

julia> rref_with_pivots([16  2  3  13;
              5 11 10   8;
              9  7  6  12;
              4 14 15   1])
4×4 Array{Float64,2}:
 1.0  0.0  0.0   1.0
 0.0  1.0  0.0   3.0
 0.0  0.0  1.0  -3.0
 0.0  0.0  0.0   0.0
 Int64[3]:
 1
 2
 3

julia> rref_with_pivots([ 1  2  0   3;
              2  4  0   7])
2×4 Array{Float64,2}:
 1.0  2.0  0.0  0.0
 0.0  0.0  0.0  1.0
 Int64[3]:
 1
 4
```
"""
rref_with_pivots(A::Matrix{T}) where {T} = rref_with_pivots!(copy(A))
rref_with_pivots(A::Matrix{T}) where {T <: Complex} = rref_with_pivots_conv(ComplexF64, A)
rref_with_pivots(A::Matrix{ComplexF64}) = rref_with_pivots!(copy(A))
rref_with_pivots(A::Matrix{T}) where {T <: Union{Integer, Float16, Float32}} = rref_with_pivots_conv(Float64, A)

rref_with_pivots(A::AbstractMatrix) = rref_with_pivots(Matrix(A))


text:
function sakura_fall(v)
    distance = 400 # cm
    v > 0 || return 0
    return distance/v
end

max_stars_repo_name: UlrichBerntien/Codewars-Katas

max_issues_repo_name: UlrichBerntien/Codewars-Katas

max_forks_repo_name: UlrichBerntien/Codewars-Katas


text:
#=
fragment:
- Julia version:
- Author: Dan
- Date: 2021-06-01
=#
import .CONCEPT.getName
export Residue, isAminoAcid, isNTerminal, isHetero

"Represents a Residue (e.g. An Amino-Acid). See also [`AbstractComposite`](@ref)."
mutable struct Residue <: AbstractResidue
    name_                                       ::Union{String,Nothing}
    number_of_children_                         ::Union{Int64,Nothing}
    parent_                                     ::Union{Nothing,AbstractComposite}
    previous_                                   ::Union{Nothing,AbstractComposite}
    next_                                       ::Union{Nothing,AbstractComposite}
    first_child_                                ::Union{Nothing,AbstractComposite}
    last_child_                                 ::Union{Nothing,AbstractComposite}
    properties_                                 ::Vector{Tuple{String,UInt8}}
    contains_selection_                         ::Union{Bool,Nothing}
    number_of_selected_children_                ::Union{Int64,Nothing}
    number_of_children_containing_selection_    ::Union{Int64,Nothing}
    selection_stamp_                            ::Union{TimeStamp,Nothing}
    modification_stamp_                         ::Union{TimeStamp,Nothing}
    trait_                                      ::Union{Nothing,AbstractComposite}
    insertion_code_                             ::Union{Char,Nothing}
    is_disordered_                              ::Union{Bool,Nothing}
    res_number_                                 ::Union{Int64,Nothing}
    is_hetero_                                  ::Union{Bool,Nothing}
    selected_                                   ::Bool

    Residue() = new(nothing,nothing,nothing,nothing,nothing,nothing,nothing,Vector{Tuple{String,UInt8}}(),nothing,nothing,nothing,nothing,nothing,nothing,
    nothing,nothing,nothing,nothing,false)

    Residue(name_                                   ::Union{String,Nothing},
            number_of_children_                         ::Union{Int64,Nothing},
            parent_                                     ::Union{Nothing,AbstractComposite},
            previous_                                   ::Union{Nothing,AbstractComposite},
            next_                                       ::Union{Nothing,AbstractComposite},
            first_child_                                ::Union{Nothing,AbstractComposite},
            last_child_                                 ::Union{Nothing,AbstractComposite},
            properties_                                 ::Vector{Tuple{String,UInt8}},
            contains_selection_                         ::Union{Bool,Nothing},
            number_of_selected_children_                ::Union{Int64,Nothing},
            number_of_children_containing_selection_    ::Union{Int64,Nothing},
            selection_stamp_                            ::Union{TimeStamp,Nothing},
            modification_stamp_                         ::Union{TimeStamp,Nothing},
            trait_                                      ::Union{Nothing,AbstractComposite},
            insertion_code_                             ::Union{Char,Nothing},
            is_disordered_                              ::Union{Bool,Nothing},
            res_number_                                 ::Union{Int64,Nothing},
            is_hetero_                                  ::Union{Bool,Nothing},
            selected_                                   ::Union{Bool,Nothing}) = new(

            name_,
            number_of_children_,
            parent_,
            previous_,
            next_,
            first_child_,
            last_child_,
            properties_,
            contains_selection_,
            number_of_selected_children_,
            number_of_children_containing_selection_,
            selection_stamp_,
            modification_stamp_,
            trait_,
            insertion_code_,
            is_disordered_,
            res_number_,
            is_hetero_,
            selected_
        )
end
Residue(res_name::String,num_of_children::Int64, ins_code::Char, res_number::Int64,hetero::Bool) =
    Residue(res_name,num_of_children,nothing,nothing,nothing,nothing,nothing,
            Vector{Tuple{String,UInt8}}(),nothing,nothing,nothing,nothing,nothing,nothing,
            ins_code, false,res_number,hetero,false)

getName(res::Residue) = !isnothing(res.name_) ? (res.name_) : "N/A"
"""
    isAminoAcid(res::Residue)
Checks if `res` is an [Amino Acid](@ref ).
"""
isAminoAcid(res::Residue) = return hasProperty(res, ("amino_acid",true) )

"""
    isNTerminal(res::Residue)
Checks if `res` is a [N-Terminus](https://en.wikipedia.org/wiki/N-terminus).
"""

isNTerminal(res::Residue) = begin
    !isAminoAcid(res) && return false
    chain = res.parent_
    typeof(chain) == Residue && return false
    residues = collectResidues(chain)
    current_res = residues[1]
    for x in residues
        if (x == res) || (!isAminoAcid(x))
            current_res = x
            break
        end
    end
    return (current_res == res)
end

Base.show(io::IO, res::Residue) =
    print(io,
    "$(getName(res)), ",
    "$(countAtoms(res)) atoms"
)

isHetero(res::Residue) = res.is_hetero_


text:
# ------------------------------------------------------------------
# Copyright (c) 2018, Júlio Hoffimann Mendes <juliohm@stanford.edu>
# Licensed under the ISC License. See LICENCE in the project root.
# ------------------------------------------------------------------

"""
    CookieCutter(master, others)

A cookie-cutter simulation solver.

## Parameters

* `master` - Master simulation solver (a.k.a. facies solver)
* `others` - A list of pairs mapping categories to solvers

## Examples

Simulate lithology facies with image quilting and fill property
with direct Gaussian simulation:

```julia
julia> fsolver  = ImgQuilt(:facies => (TI=Strebelle, template=(30,30,1)))
julia> psolver₀ = DirectGaussSim(:property => (variogram=SphericalVariogram(range=10.),))
julia> psolver₁ = DirectGaussSim(:property => (variogram=SphericalVariogram(range=20.),))
julia> solver   = CookieCutter(fsolver, [0 => psolver₀, 1 => psolver₁])
```
"""
struct CookieCutter <: AbstractSimulationSolver
  master::AbstractSimulationSolver
  others::Vector{Pair{Number,AbstractSimulationSolver}}
end

function solve(problem::SimulationProblem, solver::CookieCutter)
  # retrieve problem info
  pdata   = data(problem)
  pdomain = domain(problem)
  pmapper = mapper(problem)
  pvars   = variables(problem)
  preals  = nreals(problem)

  mastervars = collect(keys(solver.master.params))
  @assert length(mastervars) == 1 "only one variable can be specified in master solver"

  mastervar = mastervars[1]
  @assert mastervar ∈ keys(pvars) "invalid variable in master solver"
  mastertype = pvars[mastervar]

  others = Dict(var => V for (var,V) in pvars if var ≠ mastervar)
  @assert length(others) > 0 "cookie-cutter requires problem with more than one target variable"

  # define master and other problems
  if hasdata(problem)
    mproblem = SimulationProblem(pdata, pdomain, mastervar, preals, mapper=pmapper)
    oproblem = SimulationProblem(pdata, pdomain, keys(others), preals, mapper=pmapper)
  else
    mproblem = SimulationProblem(pdomain, mastervar => mastertype, preals, mapper=pmapper)
    oproblem = SimulationProblem(pdomain, others, preals, mapper=pmapper)
  end

  # solve master problem
  msolution = solve(mproblem, solver.master)

  # pre-allocate memory for result
  realizations = msolution.realizations
  for (var, V) in others
    realizations[var] = [Vector{V}(npoints(pdomain)) for i in 1:preals]
  end

  # use master solution as guide
  guides = realizations[mastervar]

  # solve other problems
  for (mval, osolver) in solver.others
    osolution = solve(oproblem, osolver)
    for (var, oreals) in osolution.realizations
      for i in 1:preals
        mask = guides[i] .≈ mval
        realizations[var][i][mask] .= oreals[i][mask]
      end
    end
  end

  SimulationSolution(pdomain, realizations)
end

# ------------
# IO methods
# ------------
function Base.show(io::IO, solver::CookieCutter)
  print(io, "CookieCutter")
end

function Base.show(io::IO, ::MIME"text/plain", solver::CookieCutter)
  mastervar = collect(keys(solver.master.params))[1]
  println(io, solver)
  println(io, "  └─", mastervar, " ⇨ ", solver.master)
  for (val, osolver) in solver.others
    println(io, "    └─", val, " ⇨ ", osolver)
  end
end


text:
#
# This is the benefit/tax credit/IT/MinWage/NI rates from April 2021
#
sys.it.savings_rates   =  [0.0, 20.0, 40.0, 45.0]
sys.it.savings_thresholds   =  [5_000.0, 37_700.0, 150_000.0]
sys.it.savings_basic_rate = 2 # above this counts as higher rate

sys.it.non_savings_rates  =  [19.0,20.0,21.0,41.0,46.0]
sys.it.non_savings_thresholds  =  [2_097, 12_726, 31_092, 150_000.0]
sys.it.non_savings_basic_rate = 2 # above this counts as higher rate

sys.it.dividend_rates  =  [0.0, 7.5,32.5,38.1]
sys.it.dividend_thresholds  =  [2_000.0, 37_700.0, 150_000.0]
sys.it.dividend_basic_rate = 2 # above this counts as higher rate

sys.it.personal_allowance          = 12_570.00
sys.it.personal_allowance_income_limit = 100_000.00
sys.it.personal_allowance_withdrawal_rate = 50.0
sys.it.blind_persons_allowance     = 2_520.00

sys.it.married_couples_allowance   = 9_125.00
sys.it.mca_minimum                 = 3_530.00
sys.it.mca_income_maximum          = 29_600.00
sys.it.mca_credit_rate             = 10.0
sys.it.mca_withdrawal_rate        = 50.0

sys.it.marriage_allowance          = 1_260.00
sys.it.personal_savings_allowance  = 1_000.00

# FIXME better to have it straight from
# the book with charges per CO2 range
# and the data being an estimate of CO2 per type
merge( sys.it.company_car_charge_by_CO2_emissions,
    Dict([
        Missing_Fuel_Type=>0.1,
        No_Fuel=>0.1,
        Other=>0.1,
        Dont_know=>0.1,
        Petrol=>0.25,
        Diesel=>0.37,
        Hybrid_use_a_combination_of_petrol_and_electricity=>0.16,
        Electric=>0.02,
        LPG=>0.02,
        Biofuel_eg_E85_fuel=>0.02 ]))

sys.it.fuel_imputation  = 24_500.00 # 20/21

#
# pensions
#
sys.it.pension_contrib_basic_amount = 3_600.00
sys.it.pension_contrib_annual_allowance = 40_000.00
sys.it.pension_contrib_annual_minimum = 4_000.00
sys.it.pension_contrib_threshold_income = 240_000.00
sys.it.pension_contrib_withdrawal_rate = 50.0

# sys.it.non_savings_income = NON_SAVINGS_INCOME
# sys.it.all_taxable = ALL_TAXABLE_INCOME
# sys.it.savings_income = SAVINGS_INCOME
# sys.it.dividend_income = DIVIDEND_INCOME

# sys.it.mca_date = MCA_DATE

sys.ni.abolished = false
sys.ni.primary_class_1_rates  = [0.0, 0.0, 12.0, 2.0 ]
sys.ni.primary_class_1_bands  = [120.0, 184.0, 967.0, 9999999999999.9] # the '-1' here is because json can't write inf
sys.ni.secondary_class_1_rates  = [0.0, 13.8, 13.8 ] # keep 2 so
sys.ni.secondary_class_1_bands  = [170.0, 967.0, 99999999999999.9 ]
sys.ni.state_pension_age = 66; # fixme move
sys.ni.class_2_threshold = 6_515.0;
sys.ni.class_2_rate = 3.05;
sys.ni.class_4_rates  = [0.0, 9.0, 2.0 ]
sys.ni.class_4_bands  = [9_569.0, 50_270.0, 99999999999999.9 ]
# sys.ni.class_1_income = IncludedItems([WAGES],[PENSION_CONTRIBUTIONS_EMPLOYER])
# sys.ni.class_4_income = [SELF_EMPLOYMENT_INCOME]

# sys.uc.

sys.lmt.isa_jsa_esa_abolished = false
sys.lmt.pen_credit_abolished = false
## FIXME we can't turn off pension credit individually here..

sys.lmt.premia.family = 17.65
sys.lmt.premia.family_lone_parent = 22.20
sys.lmt.premia.carer_single = 37.70
sys.lmt.premia.carer_couple = 2*37.70
sys.lmt.premia.disabled_child = 65.94
sys.lmt.premia.disability_single = 35.10
sys.lmt.premia.disability_couple = 50.05
sys.lmt.premia.enhanced_disability_child = 26.67
sys.lmt.premia.enhanced_disability_single = 17.20
sys.lmt.premia.enhanced_disability_couple = 24.60
sys.lmt.premia.severe_disability_single = 67.30
sys.lmt.premia.severe_disability_couple = 134.60
sys.lmt.premia.pensioner_is = 152.90

sys.lmt.allowances.age_18_24 = 59.20
sys.lmt.allowances.age_25_and_over = 74.70
sys.lmt.allowances.age_18_and_in_work_activity = 74.70
sys.lmt.allowances.over_pension_age = 191.15 #
sys.lmt.allowances.lone_parent = 74.70
sys.lmt.allowances.lone_parent_over_pension_age = 191.15
sys.lmt.allowances.couple_both_under_18 = 59.20
sys.lmt.allowances.couple_both_over_18 = 117.40
sys.lmt.allowances.couple_over_pension_age = 286.05
sys.lmt.allowances.couple_one_over_18_high = 117.40
sys.lmt.allowances.couple_one_over_18_med = 74.70
sys.lmt.allowances.pa_couple_one_over_18_low = 59.20
sys.lmt.allowances.child = 68.60
sys.lmt.allowances.pc_mig_single = 177.10
sys.lmt.allowances.pc_mig_couple = 270.30
sys.lmt.allowances.pc_child = 54.60

# sys.lmt.income_rules.
sys.lmt.income_rules.permitted_work =143.00
sys.lmt.income_rules.lone_parent_hb = 25.0
sys.lmt.income_rules.high = 20.0
sys.lmt.income_rules.low_couple = 10.0
sys.lmt.income_rules.low_single = 5.0
sys.lmt.income_rules.hb_additional = 17.10
sys.lmt.income_rules.childcare_max_1 = 175.0
sys.lmt.income_rules.childcare_max_2 = 300.0
sys.lmt.income_rules.incomes     = LEGACY_MT_INCOME
sys.lmt.income_rules.hb_incomes  = LEGACY_HB_INCOME
sys.lmt.income_rules.pc_incomes  = LEGACY_PC_INCOME
sys.lmt.income_rules.sc_incomes  = LEGACY_SAVINGS_CREDIT_INCOME
sys.lmt.income_rules.capital_min = 6_000.0
sys.lmt.income_rules.capital_max = 16_000.0
sys.lmt.income_rules.pc_capital_min = 10_000.0
sys.lmt.income_rules.pc_capital_max = 99999999999999.9
sys.lmt.income_rules.pensioner_capital_min = 10_000.0
sys.lmt.income_rules.pensioner_capital_max = 16_000.0

sys.lmt.income_rules.capital_tariff = 250
sys.lmt.income_rules.pensioner_tariff = 500
# FIXME why do we need a seperate copy of HoursLimits here?

sys.lmt.hours_limits.lower = 16
sys.lmt.hours_limits.med = 24
sys.lmt.hours_limits.higher = 30

sys.lmt.savings_credit.abolished = false
sys.lmt.savings_credit.withdrawal_rate = 60.0
sys.lmt.savings_credit.threshold_single = 153.70
sys.lmt.savings_credit.threshold_couple =244.12
sys.lmt.savings_credit.max_single = 14.04
sys.lmt.savings_credit.max_couple = 15.71
sys.lmt.savings_credit.available_till = Date( 2016, 04, 06 )

sys.lmt.child_tax_credit.abolished = false
sys.lmt.child_tax_credit.family = 545.0
sys.lmt.child_tax_credit.child  = 2_845.0
sys.lmt.child_tax_credit.disability = 3_435
sys.lmt.child_tax_credit.severe_disability = 4825
sys.lmt.child_tax_credit.threshold = 16_480.0

sys.lmt.working_tax_credit.basic = 2_005+1_045  # CAREFUL!! assuming 20 uplift still in place
sys.lmt.working_tax_credit.lone_parent = 2_060
sys.lmt.working_tax_credit.couple  = 2_060
sys.lmt.working_tax_credit.hours_ge_30 = 830
sys.lmt.working_tax_credit.disability = 3_240
sys.lmt.working_tax_credit.severe_disability = 1_400
sys.lmt.working_tax_credit.age_50_plus  = 1_365.00
sys.lmt.working_tax_credit.age_50_plus_30_hrs = 2_030.00
sys.lmt.working_tax_credit.childcare_max_2_plus_children = 300.0 # pw
sys.lmt.working_tax_credit.childcare_max_1_child  = 175.0
sys.lmt.working_tax_credit.childcare_proportion = 70.0
sys.lmt.working_tax_credit.taper = 41.0
sys.lmt.working_tax_credit.threshold = 6_565.0
sys.lmt.working_tax_credit.non_earnings_minima = 300.0 # FIXME check

sys.lmt.hb.taper = 65.0
sys.lmt.hb.ndd_deductions = [15.95,36.65,50.30,82.30,93.70,102.85]
sys.lmt.hb.ndd_incomes = [149.0,217.0,283.0,377.0,469.0,99999999999999.9]

sys.lmt.ctr.taper = 20.0
sys.lmt.ctr.ndd_deductions = []
sys.lmt.ctr.ndd_incomes = []

sys.uc.abolished = false
sys.uc.threshold = 2_500.0 ## NOT USED
sys.uc.age_18_24 = 344.00
sys.uc.age_25_and_over = 411.51

sys.uc.couple_both_under_25 = 490.60
sys.uc.couple_oldest_25_plus = 596.58

sys.uc.first_child  = 282.50
sys.uc.subsequent_child = 237.08
sys.uc.disabled_child_lower = 128.89
sys.uc.disabled_child_higher = 402.41
sys.uc.limited_capcacity_for_work_activity = 343.63
sys.uc.carer = 163.73

sys.uc.ndd = 75.53

sys.uc.childcare_max_2_plus_children  = 1_108.04 # pm
sys.uc.childcare_max_1_child  = 646.35
sys.uc.childcare_proportion = 85.0 # pct

sys.uc.minimum_income_floor_hours = 35*WEEKS_PER_MONTH

sys.uc.work_allowance_w_housing = 293.0
sys.uc.work_allowance_no_housing = 515.0
sys.uc.other_income = UC_OTHER_INCOME
# sys.uc.earned_income :: IncludedItems = UC_EARNED_INCOME
sys.uc.capital_min = 6_000.0
sys.uc.capital_max = 16_000.0
# £1 *per week* ≆ 4.35 pm FIXME make 4.35 WEEKS_PER_MONTH?
sys.uc.capital_tariff = 250.0/4.35
sys.uc.taper = 63.0
sys.uc.ctr_taper = 20.0

sys.age_limits.state_pension_ages = pension_ages()
sys.age_limits.savings_credit_to_new_state_pension = Date( 2016, 04, 06 )

sys.hours_limits.lower = 16
sys.hours_limits.med = 24
sys.hours_limits.higher = 30

sys.child_limits.max_children = 2

# THESE ARE TILL APRIL 2022
sys.minwage.ages = [16,18,21,23]
sys.minwage.wage_per_hour = [4.62, 6.56, 8.36, 8.91]
sys.minwage.apprentice_rate = 4.30

sys.hr.maximum_rooms = 4
sys.hr.rooms_rent_reduction = [14.0,25.0]
sys.hr.single_room_age = 35
#
# These are unchanged in 3 years; see:
# https://www.gov.scot/publications/local-housing-allowance-rates-2021-2022/
#
sys.hr.brmas = loadBRMAs( 4, T, DEFAULT_BRMA_2021 )

sys.nmt_bens.attendance_allowance.abolished = false
sys.nmt_bens.attendance_allowance.higher = 89.60
sys.nmt_bens.attendance_allowance.lower = 60.00

sys.nmt_bens.child_benefit.abolished = false
sys.nmt_bens.child_benefit.first_child = 21.15
sys.nmt_bens.child_benefit.other_children = 14.00
sys.nmt_bens.child_benefit.high_income_thresh = 50_000.0
sys.nmt_bens.child_benefit.withdrawal = 1/100
sys.nmt_bens.child_benefit.guardians_allowance = 18.00

sys.nmt_bens.dla.abolished = false
sys.nmt_bens.dla.care_high = 89.60
sys.nmt_bens.dla.care_middle  = 60.00
sys.nmt_bens.dla.care_low  = 23.70
sys.nmt_bens.dla.mob_high  = 62.55
sys.nmt_bens.dla.mob_low  = 23.70

sys.nmt_bens.carers.abolished = false
sys.nmt_bens.carers.allowance = 67.60

sys.nmt_bens.carers.scottish_supplement = 231.40 # FROM APRIL 2021
sys.nmt_bens.carers.hours :: Int = 35
sys.nmt_bens.carers.gainful_employment_min = 128.00

sys.nmt_bens.pip.abolished = false
sys.nmt_bens.pip.dl_standard = 60.0
sys.nmt_bens.pip.dl_enhanced = 89.60
sys.nmt_bens.pip.mobility_standard = 23.70
sys.nmt_bens.pip.mobility_enhanced = 62.55

sys.nmt_bens.esa.abolished = false
sys.nmt_bens.esa.assessment_u25 = 59.20
sys.nmt_bens.esa.assessment_25p = 74.70
sys.nmt_bens.esa.main           = 74.70
sys.nmt_bens.esa.work           = 29.70
sys.nmt_bens.esa.support        = 39.40

sys.nmt_bens.jsa.abolished = false
sys.nmt_bens.jsa.u25 = 59.20
sys.nmt_bens.jsa.o24 = 74.70

sys.nmt_bens.pensions.abolished = false
sys.nmt_bens.pensions.new_state_pension = 179.60
# pension_start_date = Date( 2016, 04, 06 )
sys.nmt_bens.pensions.cat_a     = 137.60
sys.nmt_bens.pensions.cat_b     = 137.60
sys.nmt_bens.pensions.cat_b_survivor = 82.45
sys.nmt_bens.pensions.cat_d     = 82.45

sys.nmt_bens.bereavement.abolished = false
# higher effectively just means 'with children';
sys.nmt_bens.bereavement.lump_sum_higher = 3_500
sys.nmt_bens.bereavement.lump_sum_lower  = 2_500
sys.nmt_bens.bereavement.higher = 350
sys.nmt_bens.bereavement.lower  = 100

sys.nmt_bens.widows_pension.abolished = false
sys.nmt_bens.widows_pension.industrial_higher =  137.60
sys.nmt_bens.widows_pension.industrial_lower = 41.28
sys.nmt_bens.widows_pension.standard_rate =  122.55
sys.nmt_bens.widows_pension.parent =  122.55
sys.nmt_bens.widows_pension.ages = collect(54:-1:45)
sys.nmt_bens.widows_pension.age_amounts = [113.97,105.39,96.81,88.24,79.66,71.08,62.50,53.92,45.34,36.77]

#
# young carer grant
sys.nmt_bens.maternity.abolished = false
sys.nmt_bens.maternity.rate = 151.97

sys.nmt_bens.smp = 151.97 ## 90% of earn cpag 21/2 812
# = XX

sys.bencap.abolished = false
sys.bencap.outside_london_single = 257.69
sys.bencap.outside_london_couple = 384.62
# not really needed, but anyway ..
sys.bencap.inside_london_single = 296.35
sys.bencap.inside_london_couple  = 442.31
sys.bencap.uc_incomes_limit  = 617

sys.scottish_child_payment.amount = 10.0
sys.scottish_child_payment.maximum_age = 5

sys.ubi.abolished = true
sys.ubi.adult_amount = 4_800.0
sys.ubi.child_amount= 3_000.0
sys.ubi.universal_pension = 8_780.0
sys.ubi.adult_age = 17
sys.ubi.retirement_age = 66

max_stars_repo_name: grahamstark/ScottishTaxBenefitModel

max_issues_repo_name: grahamstark/ScottishTaxBenefitModel

max_forks_repo_name: grahamstark/ScottishTaxBenefitModel


text:
module TestData
    using Test, DataFrames, Random, Statistics
    const ≅ = isequal

    @testset "constructors" begin
        df1 = DataFrame([[1, 2, missing, 4], ["one", "two", missing, "four"]], [:Ints, :Strs])
        df2 = DataFrame([[1, 2, missing, 4], ["one", "two", missing, "four"]])
        df3 = DataFrame([[1, 2, missing, 4]])
        df4 = DataFrame([Vector{Union{Int, Missing}}(1:4), Vector{Union{Int, Missing}}(1:4)])
        df5 = DataFrame([Union{Int, Missing}[1, 2, 3, 4], ["one", "two", missing, "four"]])
        df6 = DataFrame([[1, 2, missing, 4], [1, 2, missing, 4], ["one", "two", missing, "four"]],
                        [:A, :B, :C])
        df7 = DataFrame(x = [1, 2, missing, 4], y = ["one", "two", missing, "four"])
        @test size(df7) == (4, 2)
        @test df7[:x] ≅ [1, 2, missing, 4]

        #test_group("description functions")
        @test size(df6, 1) == 4
        @test size(df6, 2) == 3
        @test names(df6) == [:A, :B, :C]
        @test names(df2) == [:x1, :x2]
        @test names(df7) == [:x, :y]

        #test_group("ref")
        @test df6[2, 3] == "two"
        @test ismissing(df6[3, 3])
        @test df6[2, :C] == "two"
        @test df6[:B] ≅ [1, 2, missing, 4]
        @test size(df6[[2,3]], 2) == 2
        @test size(df6[2,:], 1) == 1
        @test size(df6[[1, 3], [1, 3]]) == (2, 2)
        @test size(df6[1:2, 1:2]) == (2, 2)
        @test size(head(df6,2)) == (2, 3)
        # lots more to do

        #test_group("assign")
        df6[3] = ["un", "deux", "trois", "quatre"]
        @test df6[1, 3] == "un"
        df6[:B] = [4, 3, 2, 1]
        @test df6[1,2] == 4
        df6[:D] = [true, false, true, false]
        @test df6[1,4]
        deletecols!(df6, :D)
        @test names(df6) == [:A, :B, :C]
        @test size(df6, 2) == 3

        #test_group("missing handling")
        @test df5[completecases(df5), :] == df5[[1, 2, 4], :]
        @test dropmissing(df5) == df5[[1, 2, 4], :]
        returned = dropmissing(df4)
        @test df4 == returned && df4 !== returned
        df5b = deepcopy(df5)
        @test dropmissing!(df5b) === df5b
        @test df5b == df5[[1, 2, 4], :]
        df4b = deepcopy(df4)
        @test dropmissing!(df4b) === df4b
        @test df4b == df4

        for cols in (:x2, [:x2], [:x1, :x2], 2, [2], 1:2, [true, true], [false, true])
            @test df5[completecases(df5, cols), :] == df5[[1, 2, 4], :]
            @test dropmissing(df5, cols) == df5[[1, 2, 4], :]
            returned = dropmissing(df4, cols)
            @test df4 == returned && df4 !== returned
            df5b = deepcopy(df5)
            @test dropmissing!(df5b, cols) === df5b
            @test df5b == df5[[1, 2, 4], :]
            @test dropmissing(df5, cols) == df5b
            @test df5 != df5b
            df4b = deepcopy(df4)
            @test dropmissing!(df4b, cols) === df4b
            @test df4b == df4
        end

        #test_context("SubDataFrames")

        #test_group("constructors")
        # single index is rows
        sdf6a = view(df6, 1)
        sdf6b = view(df6, 2:3)
        sdf6c = view(df6, [true, false, true, false])
        @test size(sdf6a) == (1,3)
        sdf6d = view(df6, [1,3], :B)
        @test size(sdf6d) == (2,1)
        sdf6e = view(df6, 0x01)
        @test size(sdf6e) == (1,3)
        sdf6f = view(df6, UInt64[1, 2])
        @test size(sdf6f) == (2,3)

        #test_group("ref")
        @test sdf6a[1,2] == 4

        #test_context("Within")
        #test_group("Associative")

        #test_group("DataFrame")
        Random.seed!(1)
        N = 20
        d1 = Vector{Union{Int64, Missing}}(rand(1:2, N))
        d2 = CategoricalArray(["A", "B", missing])[rand(1:3, N)]
        d3 = randn(N)
        d4 = randn(N)
        df7 = DataFrame([d1, d2, d3], [:d1, :d2, :d3])

        #test_group("groupby")
        gd = groupby(df7, :d1)
        @test length(gd) == 2
        @test gd[1][:d2] ≅ d2[d1 .== 1]
        @test gd[2][:d2] ≅ d2[d1 .== 2]
        @test gd[1][:d3] == d3[d1 .== 1]
        @test gd[2][:d3] == d3[d1 .== 2]

        g1 = groupby(df7, [:d1, :d2])
        g2 = groupby(df7, [:d2, :d1])
        @test g1[1][:d3] == g2[1][:d3]

        res = 0.0
        for x in g1
            res += sum(x[:d1])
        end
        @test res == sum(df7[:d1])

        @test aggregate(DataFrame(a=1), identity) == DataFrame(a_identity=1)

        df8 = aggregate(df7[[1, 3]], sum)
        @test df8[1, :d1_sum] == sum(df7[:d1])

        df8 = aggregate(df7, :d2, [sum, length], sort=true)
        @test df8[1:2, :d2] == ["A", "B"]
        @test size(df8, 1) == 3
        @test size(df8, 2) == 5
        @test sum(df8[:d1_length]) == N
        @test all(df8[:d1_length] .> 0)
        @test df8[:d1_length] == [sum(isequal.(d2, "A")), sum(isequal.(d2, "B")), sum(ismissing.(d2))]
        df8′ = aggregate(df7, 2, [sum, length], sort=true)
        @test df8 ≅ df8′
        adf = aggregate(groupby(df7, :d2, sort=true), [sum, length])
        @test df8 ≅ adf
        adf′ = aggregate(groupby(df7, 2, sort=true), [sum, length])
        @test df8 ≅ adf′
        adf = aggregate(groupby(df7, :d2), [sum, length], sort=true)
        @test sort(df8, [:d1_sum, :d3_sum, :d1_length, :d3_length]) ≅ adf
        adf′ = aggregate(groupby(df7, 2), [sum, length], sort=true)
        @test adf ≅ adf′

        # Check column names
        anonf = x -> sum(x)
        adf = aggregate(df7, :d2, [mean, anonf])
        @test names(adf) == [:d2, :d1_mean, :d3_mean,
                             Symbol(:d1_, nameof(anonf)), Symbol(:d3_, nameof(anonf))]

        df9 = aggregate(df7, :d2, [sum, length], sort=true)
        @test df9 ≅ df8
        df9′ = aggregate(df7, 2, [sum, length], sort=true)
        @test df9′ ≅ df8

        df10 = DataFrame([[1:4;], [2:5;],
                          ["a", "a", "a", "b" ], ["c", "d", "c", "d"]],
                         [:d1, :d2, :d3, :d4])

        gd = groupby(df10, [:d3], sort=true)
        ggd = groupby(gd[1], [:d3, :d4], sort=true) # make sure we can groupby subDataFrames
        @test ggd[1][1, :d3] == "a"
        @test ggd[1][1, :d4] == "c"
        @test ggd[1][2, :d3] == "a"
        @test ggd[1][2, :d4] == "c"
        @test ggd[2][1, :d3] == "a"
        @test ggd[2][1, :d4] == "d"
    end

    @testset "reshape" begin
        d1 = DataFrame(a = Array{Union{Int, Missing}}(repeat([1:3;], inner = [4])),
                    b = Array{Union{Int, Missing}}(repeat([1:4;], inner = [3])),
                    c = Array{Union{Float64, Missing}}(randn(12)),
                    d = Array{Union{Float64, Missing}}(randn(12)),
                    e = Array{Union{String, Missing}}(map(string, 'a':'l')))

        stack(d1, :a)
        d1s = stack(d1, [:a, :b])
        d1s2 = stack(d1, [:c, :d])
        d1s3 = stack(d1)
        d1m = melt(d1, [:c, :d, :e])
        @test d1s[1:12, :c] == d1[:c]
        @test d1s[13:24, :c] == d1[:c]
        @test d1s2 == d1s3
        @test names(d1s) == [:variable, :value, :c, :d, :e]
        @test d1s == d1m
        d1m = melt(d1[[1,3,4]], :a)
        @test names(d1m) == [:variable, :value, :a]

        # Test naming of measure/value columns
        d1s_named = stack(d1, [:a, :b], variable_name=:letter, value_name=:someval)
        @test names(d1s_named) == [:letter, :someval, :c, :d, :e]
        d1m_named = melt(d1[[1,3,4]], :a, variable_name=:letter, value_name=:someval)
        @test names(d1m_named) == [:letter, :someval, :a]

        # test empty measures or ids
        dx = stack(d1, [], [:a])
        @test size(dx) == (0, 3)
        @test names(dx) == [:variable, :value, :a]
        dx = stack(d1, :a, [])
        @test size(dx) == (12, 2)
        @test names(dx) == [:variable, :value]
        dx = melt(d1, [], [:a])
        @test size(dx) == (12, 2)
        @test names(dx) == [:variable, :value]
        dx = melt(d1, :a, [])
        @test size(dx) == (0, 3)
        @test names(dx) == [:variable, :value, :a]

        @test stackdf(d1, :a) == stackdf(d1, [:a])

        # Tests of RepeatedVector and StackedVector indexing
        d1s = stackdf(d1, [:a, :b])
        @test d1s[1][[1,24]] == [:a, :b]
        @test d1s[2][[1,24]] == [1, 4]
        @test_broken d1s[1][true]
        @test_broken d1s[1][1.0]
        @test_broken d1s[2][true]
        @test_broken d1s[2][1.0]

        # Those tests check indexing RepeatedVector/StackedVector by a vector
        d1s[1][trues(24)] == d1s[1]
        d1s[2][trues(24)] == d1s[2]
        d1s[1][:] == d1s[1]
        d1s[2][:] == d1s[2]
        d1s[1][1:24] == d1s[1]
        d1s[2][1:24] == d1s[2]
        [d1s[1][1:12]; d1s[1][13:24]] == d1s[1]
        [d1s[2][1:12]; d1s[2][13:24]] == d1s[2]

        d1s2 = stackdf(d1, [:c, :d])
        d1s3 = stackdf(d1)
        d1m = meltdf(d1, [:c, :d, :e])
        @test d1s[1:12, :c] == d1[:c]
        @test d1s[13:24, :c] == d1[:c]
        @test d1s2 == d1s3
        @test names(d1s) == [:variable, :value, :c, :d, :e]
        @test d1s == d1m
        d1m = meltdf(d1[[1,3,4]], :a)
        @test names(d1m) == [:variable, :value, :a]

        d1s_named = stackdf(d1, [:a, :b], variable_name=:letter, value_name=:someval)
        @test names(d1s_named) == [:letter, :someval, :c, :d, :e]
        d1m_named = meltdf(d1, [:c, :d, :e], variable_name=:letter, value_name=:someval)
        @test names(d1m_named) == [:letter, :someval, :c, :d, :e]

        d1s[:id] = Union{Int, Missing}[1:12; 1:12]
        d1s2[:id] =  Union{Int, Missing}[1:12; 1:12]
        d1us = unstack(d1s, :id, :variable, :value)
        d1us2 = unstack(d1s2)
        d1us3 = unstack(d1s2, :variable, :value)
        @test d1us[:a] == d1[:a]
        @test d1us2[:d] == d1[:d]
        @test d1us2[:3] == d1[:d]

        # test unstack with exactly one key column that is not passed
        df1 = melt(DataFrame(rand(10,10)))
        df1[:id] = 1:100
        @test size(unstack(df1, :variable, :value)) == (100, 11)

        # test empty keycol
        @test_throws ArgumentError unstack(melt(DataFrame(rand(3,2))), :variable, :value)
    end

    @testset "merge" begin
        Random.seed!(1)
        df1 = DataFrame(a = shuffle!(Vector{Union{Int, Missing}}(1:10)),
                        b = rand(Union{Symbol, Missing}[:A,:B], 10),
                        v1 = Vector{Union{Float64, Missing}}(randn(10)))

        df2 = DataFrame(a = shuffle!(Vector{Union{Int, Missing}}(1:5)),
                        b2 = rand(Union{Symbol, Missing}[:A,:B,:C], 5),
                        v2 = Vector{Union{Float64, Missing}}(randn(5)))

        m1 = join(df1, df2, on = :a, kind=:inner)
        @test m1[:a] == df1[:a][df1[:a] .<= 5] # preserves df1 order
        m2 = join(df1, df2, on = :a, kind = :outer)
        @test m2[:a] == df1[:a] # preserves df1 order
        @test m2[:b] == df1[:b] # preserves df1 order
        @test m2[indexin(df1[:a], m2[:a]), :b] == df1[:b]
        @test m2[indexin(df2[:a], m2[:a]), :b2] == df2[:b2]
        @test m2[indexin(df1[:a], m2[:a]), :v1] == df1[:v1]
        @test m2[indexin(df2[:a], m2[:a]), :v2] == df2[:v2]
        @test all(ismissing, m2[map(x -> !in(x, df2[:a]), m2[:a]), :b2])
        @test all(ismissing, m2[map(x -> !in(x, df2[:a]), m2[:a]), :v2])

        df1 = DataFrame(a = Union{Int, Missing}[1, 2, 3],
                        b = Union{String, Missing}["America", "Europe", "Africa"])
        df2 = DataFrame(a = Union{Int, Missing}[1, 2, 4],
                        c = Union{String, Missing}["New World", "Old World", "New World"])

        m1 = join(df1, df2, on = :a, kind = :inner)
        @test m1[:a] == [1, 2]

        m2 = join(df1, df2, on = :a, kind = :left)
        @test m2[:a] == [1, 2, 3]

        m3 = join(df1, df2, on = :a, kind = :right)
        @test m3[:a] == [1, 2, 4]

        m4 = join(df1, df2, on = :a, kind = :outer)
        @test m4[:a] == [1, 2, 3, 4]

        # test with missings (issue #185)
        df1 = DataFrame()
        df1[:A] = ["a", "b", "a", missing]
        df1[:B] = Union{Int, Missing}[1, 2, 1, 3]

        df2 = DataFrame()
        df2[:A] = ["a", missing, "c"]
        df2[:C] = Union{Int, Missing}[1, 2, 4]

        m1 = join(df1, df2, on = :A)
        @test size(m1) == (3,3)
        @test m1[:A] ≅ ["a","a", missing]

        m2 = join(df1, df2, on = :A, kind = :outer)
        @test size(m2) == (5,3)
        @test m2[:A] ≅ ["a", "b", "a", missing, "c"]
    end

    Random.seed!(1)
    df1 = DataFrame(
        a = rand(Union{Symbol, Missing}[:x,:y], 10),
        b = rand(Union{Symbol, Missing}[:A,:B], 10),
        v1 = Vector{Union{Float64, Missing}}(randn(10))
    )

    df2 = DataFrame(
        a = Union{Symbol, Missing}[:x,:y][[1,2,1,1,2]],
        b = Union{Symbol, Missing}[:A,:B,:C][[1,1,1,2,3]],
        v2 = Vector{Union{Float64, Missing}}(randn(5))
    )
    df2[1,:a] = missing

    m1 = join(df1, df2, on = [:a,:b])
    @test m1[:a] == Union{Missing, Symbol}[:x, :x, :y, :y, :y, :x, :x, :x]
    m2 = join(df1, df2, on = [:a,:b], kind = :outer)
    @test ismissing(m2[10,:v2])
    @test m2[:a] ≅ [:x, :x, :y, :y, :y, :x, :x, :y, :x, :y, missing, :y]

    Random.seed!(1)
    function spltdf(d)
        d[:x1] = map(x -> x[1], d[:a])
        d[:x2] = map(x -> x[2], d[:a])
        d[:x3] = map(x -> x[3], d[:a])
        d
    end
    df1 = DataFrame(
        a = ["abc", "abx", "axz", "def", "dfr"],
        v1 = randn(5)
    )
    df1 = spltdf(df1)
    df2 = DataFrame(
        a = ["def", "abc","abx", "axz", "xyz"],
        v2 = randn(5)
    )
    df2 = spltdf(df2)

    m1 = join(df1, df2, on = :a, makeunique=true)
    m2 = join(df1, df2, on = [:x1, :x2, :x3], makeunique=true)
    @test sort(m1[:a]) == sort(m2[:a])

    # test nonunique() with extra argument
    df1 = DataFrame(a = Union{String, Missing}["a", "b", "a", "b", "a", "b"],
                    b = Vector{Union{Int, Missing}}(1:6),
                    c = Union{Int, Missing}[1:3;1:3])
    df = vcat(df1, df1)
    @test findall(nonunique(df)) == collect(7:12)
    @test findall(nonunique(df, :)) == collect(7:12)
    @test findall(nonunique(df, Colon())) == collect(7:12)
    @test findall(nonunique(df, :a)) == collect(3:12)
    @test findall(nonunique(df, [:a, :c])) == collect(7:12)
    @test findall(nonunique(df, [1, 3])) == collect(7:12)
    @test findall(nonunique(df, 1)) == collect(3:12)

    # Test unique() with extra argument
    @test unique(df) == df1
    @test unique(df, :) == df1
    @test unique(df, Colon()) == df1
    @test unique(df, 2:3) == df1
    @test unique(df, 3) == df1[1:3,:]
    @test unique(df, [1, 3]) == df1
    @test unique(df, [:a, :c]) == df1
    @test unique(df, :a) == df1[1:2,:]

    #test unique!() with extra argument
    unique!(df, [1, 3])
    @test df == df1

    #test filter() and filter!()
    df = DataFrame(x = [3, 1, 2, 1], y = ["b", "c", "a", "b"])
    @test filter(r -> r[:x] > 1, df) == DataFrame(x = [3, 2], y = ["b", "a"])
    @test filter!(r -> r[:x] > 1, df) === df == DataFrame(x = [3, 2], y = ["b", "a"])
    df = DataFrame(x = [3, 1, 2, 1, missing], y = ["b", "c", "a", "b", "c"])
    @test_throws TypeError filter(r -> r[:x] > 1, df)
    @test_throws TypeError filter!(r -> r[:x] > 1, df)
end


text:
module QCDNUM

using QCDNUM_jll, Libdl

include("initialisation.jl")
include("grid.jl")
include("weights.jl")
include("parameters.jl")
include("evolution.jl")
include("interpolation.jl")
include("zmstf.jl")
include("splint.jl")

end # QCDNUM


text:
module CaimCore

export Dataset
export VideoGraphicDataset, ImageStack, frames
export SessionStorage, Session
export save, load, dataset!
export Accumulator, SimpleAccumulator
export intype, outtype, add!, reset!, summarize
export Feature
export series

include("util.jl")
include("dataset.jl")
include("session.jl")
include("accumulator.jl")
include("feature.jl")

include("imagestack.jl")

end


text:
module Torch

# package code goes here

end # module


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct DedicatedHostGroupProperties <: SwaggerModel
    platformFaultDomainCount::Any # spec type: Union{ Nothing, Int32 } # spec name: platformFaultDomainCount
    hosts::Any # spec type: Union{ Nothing, Vector{SubResourceReadOnly} } # spec name: hosts
    instanceView::Any # spec type: Union{ Nothing, DedicatedHostGroupInstanceView } # spec name: instanceView
    supportAutomaticPlacement::Any # spec type: Union{ Nothing, Bool } # spec name: supportAutomaticPlacement

    function DedicatedHostGroupProperties(;platformFaultDomainCount=nothing, hosts=nothing, instanceView=nothing, supportAutomaticPlacement=nothing)
        o = new()
        validate_property(DedicatedHostGroupProperties, Symbol("platformFaultDomainCount"), platformFaultDomainCount)
        setfield!(o, Symbol("platformFaultDomainCount"), platformFaultDomainCount)
        validate_property(DedicatedHostGroupProperties, Symbol("hosts"), hosts)
        setfield!(o, Symbol("hosts"), hosts)
        validate_property(DedicatedHostGroupProperties, Symbol("instanceView"), instanceView)
        setfield!(o, Symbol("instanceView"), instanceView)
        validate_property(DedicatedHostGroupProperties, Symbol("supportAutomaticPlacement"), supportAutomaticPlacement)
        setfield!(o, Symbol("supportAutomaticPlacement"), supportAutomaticPlacement)
        o
    end
end # type DedicatedHostGroupProperties

const _property_map_DedicatedHostGroupProperties = Dict{Symbol,Symbol}(Symbol("platformFaultDomainCount")=>Symbol("platformFaultDomainCount"), Symbol("hosts")=>Symbol("hosts"), Symbol("instanceView")=>Symbol("instanceView"), Symbol("supportAutomaticPlacement")=>Symbol("supportAutomaticPlacement"))
const _property_types_DedicatedHostGroupProperties = Dict{Symbol,String}(Symbol("platformFaultDomainCount")=>"Int32", Symbol("hosts")=>"Vector{SubResourceReadOnly}", Symbol("instanceView")=>"DedicatedHostGroupInstanceView", Symbol("supportAutomaticPlacement")=>"Bool")
Base.propertynames(::Type{ DedicatedHostGroupProperties }) = collect(keys(_property_map_DedicatedHostGroupProperties))
Swagger.property_type(::Type{ DedicatedHostGroupProperties }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_DedicatedHostGroupProperties[name]))}
Swagger.field_name(::Type{ DedicatedHostGroupProperties }, property_name::Symbol) =  _property_map_DedicatedHostGroupProperties[property_name]

function check_required(o::DedicatedHostGroupProperties)
    (getproperty(o, Symbol("platformFaultDomainCount")) === nothing) && (return false)
    true
end

function validate_property(::Type{ DedicatedHostGroupProperties }, name::Symbol, val)
    if name === Symbol("platformFaultDomainCount")
        Swagger.validate_param(name, "DedicatedHostGroupProperties", :maximum, val, 3, false)
        Swagger.validate_param(name, "DedicatedHostGroupProperties", :minimum, val, 1, false)
    end
end