text:
module CSV

using Mmap, Dates, Random, Unicode, Parsers, Tables, CategoricalArrays, WeakRefStrings

@inline Parsers.intern(::Type{WeakRefString{UInt8}}, x::Tuple{Ptr{UInt8}, Int}) = WeakRefString(x)

substitute(::Type{Union{T, Missing}}, ::Type{T1}) where {T, T1} = Union{T1, Missing}
substitute(::Type{T}, ::Type{T1}) where {T, T1} = T1
substitute(::Type{Missing}, ::Type{T1}) where {T1} = Missing

newline(code::Parsers.ReturnCode) = (code & Parsers.NEWLINE) > 0

const CatStr = CategoricalString{UInt32}

struct Error <: Exception
    error::Parsers.Error
    row::Int
    col::Int
end

function Base.showerror(io::IO, e::Error)
    println(io, "CSV.Error on row=$(e.row), column=$(e.col):")
    showerror(io, e.error)
end

struct File{transpose, columnaccess, I, P, KW}
    names::Vector{Symbol}
    types::Vector{Type}
    name::String
    io::I
    parsinglayers::P
    positions::Vector{Int}
    originalpositions::Vector{Int}
    currentrow::Base.RefValue{Int}
    lastparsedcol::Base.RefValue{Int}
    lastparsedcode::Base.RefValue{Parsers.ReturnCode}
    kwargs::KW
    pools::Vector{CategoricalPool{String, UInt32, CatStr}}
    strict::Bool
end

function Base.show(io::IO, f::File{transpose}) where {transpose}
    println(io, "CSV.File(\"$(f.name)\", rows=$(transpose ? missing : length(f.positions))):")
    show(io, Tables.schema(f))
end

const EMPTY_TYPEMAP = Dict{Type, Type}()

"""
    CSV.File(source::Union{String, IO}; kwargs...) => CSV.File

Read a csv input (a filename given as a String, or any other IO source), returning a `CSV.File` object.
Opens the file and uses passed arguments to detect the number of columns and column types.
The returned `CSV.File` object supports the [Tables.jl](https://github.com/JuliaData/Tables.jl) interface
and can iterate `CSV.Row`s. `CSV.Row` supports `propertynames` and `getproperty` to access individual row values.
Note that duplicate column names will be detected and adjusted to ensure uniqueness (duplicate column name `a` will become `a_1`).
For example, one could iterate over a csv file with column names `a`, `b`, and `c` by doing:

```julia
for row in CSV.File(file)
    println("a=\$(row.a), b=\$(row.b), c=\$(row.c)")
end
```

By supporting the Tables.jl interface, a `CSV.File` can also be a table input to any other table sink function. Like:

```julia
# materialize a csv file as a DataFrame
df = CSV.File(file) |> DataFrame

# load a csv file directly into an sqlite database table
db = SQLite.DB()
tbl = CSV.File(file) |> SQLite.load!(db, "sqlite_table")
```

Supported keyword arguments include:
* File layout options:
  * `header=1`: the `header` argument can be an `Int`, indicating the row to parse for column names; or a `Range`, indicating a span of rows to be combined together as column names; or an entire `Vector of Symbols` or `Strings` to use as column names
  * `normalizenames=false`: whether column names should be "normalized" into valid Julia identifier symbols
  * `datarow`: an `Int` argument to specify the row where the data starts in the csv file; by default, the next row after the `header` row is used
  * `skipto::Int`: similar to `datarow`, specifies the number of rows to skip before starting to read data
  * `footerskip::Int`: number of rows at the end of a file to skip parsing
  * `limit`: an `Int` to indicate a limited number of rows to parse in a csv file
  * `transpose::Bool`: read a csv file "transposed", i.e. each column is parsed as a row
  * `comment`: a `String` that occurs at the beginning of a line to signal parsing that row should be skipped
  * `use_mmap::Bool=!Sys.iswindows()`: whether the file should be mmapped for reading, which in some cases can be faster
* Parsing options:
  * `missingstrings`, `missingstring`: either a `String`, or `Vector{String}` to use as sentinel values that will be parsed as `missing`; by default, only an empty field (two consecutive delimiters) is considered `missing`
  * `delim=','`: a `Char` or `String` that indicates how columns are delimited in a file
  * `ignorerepeated::Bool=false`: whether repeated (consecutive) delimiters should be ignored while parsing; useful for fixed-width files with delimiter padding between cells
  * `quotechar='"'`, `openquotechar`, `closequotechar`: a `Char` (or different start and end characters) that indicate a quoted field which may contain textual delimiters or newline characters
  * `escapechar='"'`: the `Char` used to escape quote characters in a text field
  * `dateformat::Union{String, Dates.DateFormat, Nothing}`: a date format string to indicate how Date/DateTime columns are formatted in a delimited file
  * `decimal`: a `Char` indicating how decimals are separated in floats, i.e. `3.14` used '.', or `3,14` uses a comma ','
  * `truestrings`, `falsestrings`: `Vectors of Strings` that indicate how `true` or `false` values are represented
* Column Type Options:
  * `types`: a Vector or Dict of types to be used for column types; a Dict can map column index `Int`, or name `Symbol` or `String` to type for a column, i.e. Dict(1=>Float64) will set the first column as a Float64, Dict(:column1=>Float64) will set the column named column1 to Float64 and, Dict("column1"=>Float64) will set the column1 to Float64
  * `typemap::Dict{Type, Type}`: a mapping of a type that should be replaced in every instance with another type, i.e. `Dict(Float64=>String)` would change every detected `Float64` column to be parsed as `Strings`
  * `allowmissing=:all`: indicate how missing values are allowed in columns; possible values are `:all` - all columns may contain missings, `:auto` - auto-detect columns that contain missings or, `:none` - no columns may contain missings
  * `categorical::Union{Bool, Real}=false`: if `true`, columns detected as `String` are returned as a `CategoricalArray`; alternatively, the proportion of unique values below which `String` columns should be treated as categorical (for example 0.1 for 10%)
  * `strict::Bool=false`: whether invalid values should throw a parsing error or be replaced with missing values
"""
function File(source::Union{String, IO};
    # file options
    # header can be a row number, range of rows, or actual string vector
    header::Union{Integer, UnitRange{Int}, Vector}=1,
    normalizenames::Bool=false,
    # by default, data starts immediately after header or start of file
    datarow::Int=-1,
    skipto::Union{Nothing, Int}=nothing,
    footerskip::Int=0,
    limit::Union{Nothing, Int}=nothing,
    transpose::Bool=false,
    comment::Union{String, Nothing}=nothing,
    use_mmap::Bool=!Sys.iswindows(),
    # parsing options
    missingstrings=String[],
    missingstring="",
    delim::Union{Char, String}=",",
    ignorerepeated::Bool=false,
    quotechar::Union{UInt8, Char}='"',
    openquotechar::Union{UInt8, Char, Nothing}=nothing,
    closequotechar::Union{UInt8, Char, Nothing}=nothing,
    escapechar::Union{UInt8, Char}='"',
    dateformat::Union{String, Dates.DateFormat, Nothing}=nothing,
    decimal::Union{UInt8, Char, Nothing}=nothing,
    truestrings::Union{Vector{String}, Nothing}=nothing,
    falsestrings::Union{Vector{String}, Nothing}=nothing,
    # type options
    types=nothing,
    typemap::Dict=EMPTY_TYPEMAP,
    allowmissing::Symbol=:all,
    categorical::Union{Bool, Real}=false,
    strict::Bool=false,
    debug::Bool=false,
    kw...)

    isa(source, AbstractString) && (isfile(source) || throw(ArgumentError("\"$source\" is not a valid file")))
    (types !== nothing && any(x->!isconcretetype(x) && !(x isa Union), types isa Dict ? values(types) : types)) && throw(ArgumentError("Non-concrete types passed in `types` keyword argument, please provide concrete types for columns: $types"))
    io = getio(source, use_mmap)

    consumeBOM!(io)

    kwargs = getkwargs(dateformat, decimal, getbools(truestrings, falsestrings))
    d = string(delim)
    whitespacedelim = d == " " || d == "\t"
    missingstrings = isempty(missingstrings) ? [missingstring] : missingstrings
    parsinglayers = Parsers.Sentinel(missingstrings) |>
                    x->Parsers.Strip(x, d == " " ? 0x00 : ' ', d == "\t" ? 0x00 : '\t') |>
                    (openquotechar !== nothing ? x->Parsers.Quoted(x, openquotechar, closequotechar, escapechar, !whitespacedelim) : x->Parsers.Quoted(x, quotechar, escapechar, !whitespacedelim)) |>
                    x->Parsers.Delimited(x, d, "\n", "\r", "\r\n"; ignore_repeated=ignorerepeated)

    header = (isa(header, Integer) && header == 1 && (datarow == 1 || skipto == 1)) ? -1 : header
    isa(header, Integer) && datarow != -1 && (datarow > header || throw(ArgumentError("data row ($datarow) must come after header row ($header)")))
    datarow = datarow == -1 ? (isa(header, Vector) ? 0 : last(header)) + 1 : datarow # by default, data starts on line after header
    datarow = skipto !== nothing ? skipto : datarow

    if transpose
        # need to determine names, columnpositions (rows), and ref
        rows, names, positions = datalayout_transpose(header, parsinglayers, io, datarow, footerskip, normalizenames)
        originalpositions = copy(positions)
        ref = Ref{Int}(min(something(limit, typemax(Int)), rows))
        columnaccess = false
    else
        names, datapos = datalayout(header, parsinglayers, io, datarow, normalizenames)
        eof(io) && return File{false, true, typeof(io), typeof(parsinglayers), typeof(kwargs)}(names, Type[Missing for _ in names], getname(source), io, parsinglayers, Int64[], Int64[], Ref{Int}(0), Ref{Int}(0), Ref(Parsers.SUCCESS), kwargs, CategoricalPool{String, UInt32, CatStr}[], strict)
        positions = rowpositions(io, quotechar % UInt8, escapechar % UInt8, limit, parsinglayers, comment === nothing ? nothing : Parsers.Trie(comment))
        originalpositions = Int64[]
        footerskip > 0 && resize!(positions, length(positions) - footerskip)
        ref = Ref{Int}(0)
        # if the # of cells in the file is less than 500K
        columnaccess = (length(names) * length(positions)) < 500_000
        debug && @show positions
    end

    if types isa Vector
        pools = Vector{CategoricalPool{String, UInt32, CatStr}}(undef, length(types))
        for col = 1:length(types)
            T = types[col]
            if T !== Missing && Base.nonmissingtype(T) <: CatStr
                pools[col] = CategoricalPool{String, UInt32}()
            end
        end
    else
        types, pools = detect(initialtypes(initialtype(allowmissing), types, names), io, positions, parsinglayers, kwargs, typemap, categorical, transpose, ref, debug)
        if allowmissing === :none
            # make sure we didn't detect any missing values in any columns
            if any(T->T >: Missing, types)
                throw(ArgumentError("`allowmissing=:none`, but missing values were detected in csv file: $types"))
            end
        end
    end

    !transpose && seek(io, positions[1])
    return File{transpose, columnaccess, typeof(io), typeof(parsinglayers), typeof(kwargs)}(names, types, getname(source), io, parsinglayers, positions, originalpositions, Ref(1), ref, Ref(Parsers.SUCCESS), kwargs, pools, strict)
end

include("filedetection.jl")
include("typedetection.jl")
include("tables.jl")

getio(str::String, use_mmap) = IOBuffer(use_mmap ? Mmap.mmap(str) : Base.read(str))
getio(io::IO, use_mmap) = io
getname(str::String) = str
getname(io::I) where {I <: IO} = string("<", I, ">")

function consumeBOM!(io)
    # BOM character detection
    startpos = position(io)
    if !eof(io) && Parsers.peekbyte(io) == 0xef
        Parsers.readbyte(io)
        (!eof(io) && Parsers.readbyte(io) == 0xbb) || seek(io, startpos)
        (!eof(io) && Parsers.readbyte(io) == 0xbf) || seek(io, startpos)
    end
    return
end

getbools(::Nothing, ::Nothing) = nothing
getbools(trues::Vector{String}, falses::Vector{String}) = Parsers.Trie(append!([x=>true for x in trues], [x=>false for x in falses]))
getbools(trues::Vector{String}, ::Nothing) = Parsers.Trie(append!([x=>true for x in trues], ["false"=>false]))
getbools(::Nothing, falses::Vector{String}) = Parsers.Trie(append!(["true"=>true], [x=>false for x in falses]))

getkwargs(df::Nothing, dec::Nothing, bools::Nothing) = NamedTuple()
getkwargs(df::String, dec::Nothing, bools::Nothing) = (dateformat=Dates.DateFormat(df),)
getkwargs(df::Dates.DateFormat, dec::Nothing, bools::Nothing) = (dateformat=df,)

getkwargs(df::Nothing, dec::Union{UInt8, Char}, bools::Nothing) = (decimal=dec % UInt8,)
getkwargs(df::String, dec::Union{UInt8, Char}, bools::Nothing) = (dateformat=Dates.DateFormat(df), decimal=dec % UInt8)
getkwargs(df::Dates.DateFormat, dec::Union{UInt8, Char}, bools::Nothing) = (dateformat=df, decimal=dec % UInt8)

getkwargs(df::Nothing, dec::Nothing, bools::Parsers.Trie) = (bools=bools,)
getkwargs(df::String, dec::Nothing, bools::Parsers.Trie) = (dateformat=Dates.DateFormat(df), bools=bools)
getkwargs(df::Dates.DateFormat, dec::Nothing, bools::Parsers.Trie) = (dateformat=df, bools=bools)

getkwargs(df::Nothing, dec::Union{UInt8, Char}, bools::Parsers.Trie) = (decimal=dec % UInt8, bools=bools)
getkwargs(df::String, dec::Union{UInt8, Char}, bools::Parsers.Trie) = (dateformat=Dates.DateFormat(df), decimal=dec % UInt8, bools=bools)
getkwargs(df::Dates.DateFormat, dec::Union{UInt8, Char}, bools::Parsers.Trie) = (dateformat=df, decimal=dec % UInt8, bools=bools)

include("write.jl")
include("deprecated.jl")
include("validate.jl")
include("transforms.jl")

function __init__()
    Threads.resize_nthreads!(VALUE_BUFFERS)
    return
end

"""
`CSV.read(fullpath::Union{AbstractString,IO}, sink=DataFrame; kwargs...)` => `typeof(sink)`

Parses a delimited file into a Julia structure (a DataFrame by default, but any valid Tables.jl sink function can be provided).

Minimal error-reporting happens w/ `CSV.read` for performance reasons; for problematic csv files, try [`CSV.validate`](@ref) which takes exact same arguments as `CSV.read` and provides much more information for why reading the file failed.

Positional arguments:

* `fullpath`: can be a file name (String) of the location of the csv file or `IO` object to read the csv from directly
* `sink`: `DataFrame` by default, but may also be any other Tables.jl sink function

Supported keyword arguments include:
* File layout options:
  * `header=1`: the `header` argument can be an `Int`, indicating the row to parse for column names; or a `Range`, indicating a span of rows to be combined together as column names; or an entire `Vector of Symbols` or `Strings` to use as column names
  * `normalizenames=false`: whether column names should be "normalized" into valid Julia identifier symbols
  * `datarow`: an `Int` argument to specify the row where the data starts in the csv file; by default, the next row after the `header` row is used
  * `skipto::Int`: similar to `datarow`, specifies the number of rows to skip before starting to read data
  * `footerskip::Int`: number of rows at the end of a file to skip parsing
  * `limit`: an `Int` to indicate a limited number of rows to parse in a csv file
  * `transpose::Bool`: read a csv file "transposed", i.e. each column is parsed as a row
  * `comment`: a `String` that occurs at the beginning of a line to signal parsing that row should be skipped
  * `use_mmap::Bool=!Sys.iswindows()`: whether the file should be mmapped for reading, which in some cases can be faster
* Parsing options:
* `missingstrings`, `missingstring`: either a `String`, or `Vector{String}` to use as sentinel values that will be parsed as `missing`; by default, only an empty field (two consecutive delimiters) is considered `missing`
  * `delim=','`: a `Char` or `String` that indicates how columns are delimited in a file
  * `ignorerepeated::Bool=false`: whether repeated (consecutive) delimiters should be ignored while parsing; useful for fixed-width files with delimiter padding between cells
  * `quotechar='"'`, `openquotechar`, `closequotechar`: a `Char` (or different start and end characters) that indicate a quoted field which may contain textual delimiters or newline characters
  * `escapechar='\\'`: the `Char` used to escape quote characters in a text field
  * `dateformat::Union{String, Dates.DateFormat, Nothing}`: a date format string to indicate how Date/DateTime columns are formatted in a delimited file
  * `decimal`: a `Char` indicating how decimals are separated in floats, i.e. `3.14` used '.', or `3,14` uses a comma ','
  * `truestrings`, `falsestrings`: `Vectors of Strings` that indicate how `true` or `false` values are represented
* Column Type Options:
  * `types`: a Vector or Dict of types to be used for column types; a Dict can map column index `Int`, or name `Symbol` or `String` to type for a column, i.e. Dict(1=>Float64) will set the first column as a Float64, Dict(:column1=>Float64) will set the column named column1 to Float64 and, Dict("column1"=>Float64) will set the column1 to Float64
  * `typemap::Dict{Type, Type}`: a mapping of a type that should be replaced in every instance with another type, i.e. `Dict(Float64=>String)` would change every detected `Float64` column to be parsed as `Strings`
  * `allowmissing=:all`: indicate how missing values are allowed in columns; possible values are `:all` - all columns may contain missings, `:auto` - auto-detect columns that contain missings or, `:none` - no columns may contain missings
  * `categorical::Union{Bool, Real}=false`: if `true`, columns detected as `String` are returned as a `CategoricalArray`; alternatively, the proportion of unique values below which `String` columns should be treated as categorical (for example 0.1 for 10%)
  * `strict::Bool=false`: whether invalid values should throw a parsing error or be replaced with missing values
"""
function read end

function read(fullpath::Union{AbstractString,IO}, sink=DataFrame, args...; append::Bool=false, transforms::AbstractDict=Dict{Int,Function}(), kwargs...)
    if !isempty(args)
        Base.depwarn("`CSV.read(source, $sink, $args)` is deprecated; pass a valid Tables.jl sink function as the 2nd argument directly", nothing)
        sink = sink(args...)
    end
    if append
        Base.depwarn("`CSV.read(source; append=true)` is deprecated in favor of sink-specific options; e.g. DataFrames supports `CSV.File(filename) |> x->append!(existing_df, x)` to append the rows of a csv file to an existing DataFrame", nothing)
        if sink isa DataFrame
            sink = x->append!(sink, x)
        end
    end
    f = CSV.File(fullpath; kwargs...)
    if !isempty(transforms)
        Base.depwarn("`CSV.read(source; transforms=Dict(...)` is deprecated in favor of `CSV.File(source) |> transform(col1=x->...) |> DataFrame`", nothing)
        return f |> transform(transforms) |> sink
    end
    return f |> sink
end

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 RunCommandResultProperties <: SwaggerModel
    output::Any # spec type: Union{ Nothing, Any } # spec name: output

    function RunCommandResultProperties(;output=nothing)
        o = new()
        validate_property(RunCommandResultProperties, Symbol("output"), output)
        setfield!(o, Symbol("output"), output)
        o
    end
end # type RunCommandResultProperties

const _property_map_RunCommandResultProperties = Dict{Symbol,Symbol}(Symbol("output")=>Symbol("output"))
const _property_types_RunCommandResultProperties = Dict{Symbol,String}(Symbol("output")=>"Any")
Base.propertynames(::Type{ RunCommandResultProperties }) = collect(keys(_property_map_RunCommandResultProperties))
Swagger.property_type(::Type{ RunCommandResultProperties }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_RunCommandResultProperties[name]))}
Swagger.field_name(::Type{ RunCommandResultProperties }, property_name::Symbol) =  _property_map_RunCommandResultProperties[property_name]

function check_required(o::RunCommandResultProperties)
    true
end

function validate_property(::Type{ RunCommandResultProperties }, name::Symbol, val)
end

ext: jl


text:
mutable struct ForwardRelaxer{TR <: TangentRenormalizer,
                              TT <: Real,
                              } <: AbstractStage
    le_solver::TR
    t_forward_tran::TT
end

ForwardRelaxer(prob::CLVProblem, ::CLVProblem, ::CLVSolution) =
    ForwardRelaxer(prob)
ForwardRelaxer(prob::CLVProblem) = ForwardRelaxer(get_le_solver(prob),
                                                  prob.t_forward_tran)

stage_index(frx::ForwardRelaxer) = frx.le_solver.i
Base.length(frx::ForwardRelaxer) =
    ceil(Int, frx.t_forward_tran / frx.le_solver.t_renorm)
step!(frx::ForwardRelaxer) = step!(frx.le_solver)

mutable struct ForwardDynamics{S <: CLVSolution,
                               T <: TangentRenormalizer,
                               } <: AbstractStage
    le_solver::T
    i::Int
    sol::S
    R_history::Vector{UTM}

    ForwardDynamics(le_solver::T, sol::S) where {S, T} =
        new{S, T}(le_solver, 0, sol, sol.R_history)
end

ForwardDynamics(frx::ForwardRelaxer, ::CLVProblem, sol::CLVSolution) =
    ForwardDynamics(frx.le_solver, sol)

Base.length(fitr::ForwardDynamics) = length(fitr.R_history)

@inline function step!(fitr::ForwardDynamics)
    step!(fitr.le_solver)
    i = (fitr.i += 1)
    # TODO: this assignment check if lower half triangle is zero; skip that
    fitr.R_history[i] .= CLV.R_prev(fitr)
    record!(fitr, Val{:G})
    record!(fitr, Val{:x})
    return fitr
end

record!(fitr::ForwardDynamics{<:CLVSolG}, ::Type{Val{:G}}) =
    fitr.sol.G_history[fitr.i] .= CLV.G(fitr)

record!(fitr::ForwardDynamics{<:CLVSolX}, ::Type{Val{:x}}) =
    fitr.sol.x_history[fitr.i] .= phase_state(fitr)

const ForwardPass = Union{ForwardRelaxer, ForwardDynamics}

current_result(fitr::ForwardPass) = CLV.G(fitr)
phase_state(fitr::ForwardPass) = phase_state(fitr.le_solver)

mutable struct BackwardRelaxer <: AbstractStage
    num_backward_tran::Int
    R_history::Vector{UTM}
    C::UTM
    i::Int
end

BackwardRelaxer(fitr::ForwardDynamics, prob::CLVProblem, sol::CLVSolution) =
    BackwardRelaxer(sol.num_backward_tran,
                    fitr.R_history,
                    UTM(eye(fitr.R_history[end])),  # TODO: randomize
                    -1)

Base.length(brx::BackwardRelaxer) = brx.num_backward_tran

mutable struct BackwardDynamics{with_D,
                                S <: CLVSolution,
                                } <: AbstractStage
    sol::S
    R_history::Vector{UTM}
    C::UTM
    i::Int
    D_diag::Vector{Float64}

    function BackwardDynamics{with_D}(sol::S, R_history, C, i = -1,
                                      ) where {with_D, S}
        if sol isa CLVSolD && ! with_D
            error("with_D (= $with_D) has to be true when :D is",
                  " in record flag.")
        end
        bitr = new{with_D, S}(sol, R_history, C, i)
        if sol isa CLVSolC
            bitr.sol.C_history[end] .= CLV.C(bitr)
        end
        if sol isa CLVSolD
            bitr.sol.D_history[end] .= NaN
        end
        if with_D
            bitr.D_diag = similar(C, size(C, 1))
        end
        return bitr
    end
end

const BackwardDynamicsRecC = BackwardDynamics{with_D, <:CLVSolC} where {with_D}
const BackwardDynamicsRecD = BackwardDynamics{true, <:CLVSolD}
const BackwardDynamicsWithD = BackwardDynamics{true}

BackwardDynamics(brx::BackwardRelaxer, args...) =
    BackwardDynamics{false}(brx, args...)
BackwardDynamics{with_D}(brx::BackwardRelaxer,
                         ::CLVProblem,
                         sol,
                         ) where {with_D} =
    BackwardDynamics{with_D}(
        sol,
        brx.R_history[1:end - brx.i - 1],
        brx.C)

Base.length(bitr::BackwardDynamics) = length(bitr.R_history)

const BackwardPass = Union{BackwardRelaxer, BackwardDynamics}

stage_index(stage::BackwardPass) = stage.i + 1  # TODO: don't

@inline function step!(bitr::BackwardPass)
    i = (bitr.i += 1)
    R = bitr.R_history[end-i]
    C = bitr.C

    # C₀ = R⁻¹ C₁ D  (Eq. 32, Ginelli et al., 2013)
    A_ldiv_B!(R, C)
    # now:  C = R⁻¹ C₁
    for i in 1:size(C, 1)
        # C[:, i] /= norm(@view C[:, i])
        C[:, i] /= Dᵢᵢ⁻¹(bitr, i)
    end
    # now:  C = C₀ = R⁻¹ C₁ D

    record!(bitr, Val{:C})
    record!(bitr, Val{:D})
end

@inline Dᵢᵢ⁻¹(C::AbstractArray, i) = norm(@view C[:, i])
@inline Dᵢᵢ⁻¹(bitr::BackwardPass, i) = Dᵢᵢ⁻¹(bitr.C, i)
@inline function Dᵢᵢ⁻¹(bitr::BackwardDynamicsWithD, i)
    di = Dᵢᵢ⁻¹(bitr.C, i)
    bitr.D_diag[i] = 1 / di
    return di
end

function record!(bitr::BackwardDynamicsRecC, ::Type{Val{:C}})
    n = length(bitr.sol.C_history) - bitr.i - 1
    if n > 0
        bitr.sol.C_history[n] .= CLV.C(bitr)
    end
    # TODO: maybe save n=0 too
    # TODO: this assignment check if lower half triangle is zero; skip that
end

function record!(bitr::BackwardDynamicsRecD, ::Type{Val{:D}})
    n = length(bitr.sol.D_history) - bitr.i - 1
    if n > 0
        bitr.sol.D_history[n] .= bitr.D_diag
    end
    # TODO: maybe save n=0 too
end

current_result(bitr::BackwardPass) = bitr.C


text:
# ps3000_open_unit_async.jl

export ps3000_open_unit_async

function ps3000_open_unit_async()
  open_unit_async_status = ccall((:ps3000_open_unit_async, ps3000driver), Int16, ())
  return open_unit_async_status
end

#=
open_unit_async_status
0 if there is a previous open operation in progress
1 if the call has successfully initiated an open operation
=#


text:
using Documenter, ConstructionBase

makedocs(;
    modules=[ConstructionBase],
    format=Documenter.HTML(),
    pages=[
        "Home" => "index.md",
    ],
    repo="https://github.com/JuliaObjects/ConstructionBase.jl/blob/{commit}{path}#L{line}",
    sitename="ConstructionBase.jl",
    authors="Takafumi Arakaki, Rafael Schouten, Jan Weidner",
    strict=true,
)

deploydocs(;
    repo="github.com/JuliaObjects/ConstructionBase.jl",
)


text:
import Base.length

length(leaf::Leaf) = 1
length(tree::Node) = length(tree.left) + length(tree.right)
length(ensemble::Ensemble) = length(ensemble.trees)

depth(leaf::Leaf) = 0
depth(tree::Node) = 1 + max(depth(tree.left), depth(tree.right))

# Functions for determining the predictors used in a tree

function get_predictors_used!(tree, col_indcs)
    if isa(tree, Leaf)
        return nothing
    else
        push!(col_indcs, tree.col_idx)
        get_predictors_used!(tree.left, col_indcs)
        get_predictors_used!(tree.right, col_indcs)
    end
end

# Given a tree, this function returns the indices of the
# columns used at each node. Note that surrogates are ignored.
function predictors_used(tree)
    col_indcs = Array{Int}(0)
    get_predictors_used!(tree, col_indcs)
    return unique(col_indcs)
end

function add_missing(dat::DataFrame, pr)
    d = Bernoulli(pr)
    X = copy(dat)
    n, p = size(X)
    for j = 1:p
        X[:, j] = convert(DataArray{Any, 1}, X[:, j])
        for i = 1:n
            if rand(d) == 1
                X[i, j] = NA
            end
        end
    end
    return X
end

function mean_impute(v)
    μ = mean(dropna(v))
    n = length(v)
    res = zeros(n)
    for i = 1:n
        if isna(v[i])
            res[i] = μ
        else
            res[i] = v[i]
        end
    end
    res
end

function as_floats(X)
    n, p = size(X)
    out = copy(X)

    for j = 1:p
        if eltype(X[:, j]) <: Integer
            out[:, j] = convert(DataArray{Float64, 1}, X[:, j])
        end
    end
    return out
end

function print_tree(leaf::Leaf, depth=-1, indent=0)
    matches = find(leaf.values .== leaf.majority)
    ratio = string(length(matches)) * "/" * string(length(leaf.values))
    println("$(leaf.majority) : $(ratio)")
end

function print_tree(tree::Node, depth=-1, indent=0)
    if depth == indent
        println()
        return
    end
    println("Feature $(tree.col_idx), Threshold $(tree.split_value)")
    print("    " ^ indent * "L-> ")
    print_tree(tree.left, depth, indent + 1)
    print("    " ^ indent * "R-> ")
    print_tree(tree.right, depth, indent + 1)
end

function show(io::IO, leaf::Leaf)
    println(io, "Decision Leaf")
    println(io, "Majority: $(leaf.majority)")
    print(io,   "Samples:  $(length(leaf.values))")
end

function show(io::IO, tree::Node)
    println(io, "Decision Tree")
    println(io, "Leaves: $(length(tree))")
    print(io,   "Depth:  $(depth(tree))")
end

function show(io::IO, ensemble::Ensemble)
    println(io, "Ensemble of Decision Trees")
    println(io, "Trees:      $(length(ensemble))")
    println(io, "Avg Leaves: $(mean([length(tree) for tree in ensemble.trees]))")
    print(io,   "Avg Depth:  $(mean([depth(tree) for tree in ensemble.trees]))")
end


text:
function getLLVMIR(io,f,types)
    InteractiveUtils.code_llvm(io, f, types; raw=false, dump_module=false, optimize=true)
end

function getLLVMIRTofile(filename,@nospecialize(fun),types)
    open(filename,write=true) do f
        io = IOBuffer()
        getLLVMIR(io,fun,types)
        write(f,take!(io))
    end
    return
end

function reparse(s)
    funcdefplace = readline(s)[4:end]
    funcdef = readline(s)
    Label = String
    cur_block::Label = ""
    blocks = Dict{Label,Vector{Tuple{String,Vector{String}}}}()
    graphs = Dict{Label,Vector{Label}}()
    entry = nothing
    commentstack = String[funcdefplace]
    while !eof(s)
        rawline = readline(s)
        if rawline == "}" && eof(s)
            break
        end
        line = strip(rawline)
        # end of block
        if isempty(line)
            continue
        end
        # is a nested comment
        if line[1] == ';'
            line = strip(line[2:end])
            m = match(r"^(@.*)",line)
            if !isnothing(m)
                commentstack[end] = m.match
                continue
            end
            m = match(r"[│]+ *(@.*)",line)
            if !isnothing(m)
                commentstack[end] = m.match
                continue
            end
            m = match(r"[│]*([┌]+) *(@.*)",line)
            if !isnothing(m)
                l = length(m.captures[1])
                @assert l == 1 "Multiple introduction of comment"
                push!(commentstack,m.match)
                continue
            end
            m = match(r"[│]*([└]+)",line)
            if !isnothing(m)
                l = length(m.captures[1])
                for _ in 1:l
                    pop!(commentstack)
                end
                continue
            end
            println(line)
            error("unreachable")
        end
        m = match(r"^([^: ]+):",line)
        # start of a new block
        if !isnothing(m)
            cur_block = m.captures[1]
            blocks[cur_block] = []
            if isnothing(entry)
                entry = cur_block
            end
            m = match(r"; preds =(.*)",line)
            if !isnothing(m)
                prelabel = map(x->x[2:end],strip.(split(strip(m.captures[1]),',')))
                for l in prelabel
                    if !haskey(graphs,l)
                        graphs[l] = Label[]
                    end
                    push!(graphs[l],cur_block)
                end
            end
            continue
        end
        push!(blocks[cur_block],(rawline,copy(commentstack)))
    end
    if isnothing(entry)
        error("entry is empty")
    end
    pushfirst!(blocks[entry],(strip(funcdef,[' ','\n','{']),[funcdefplace]))
    return funcdef,graphs,blocks
end

function rundot(filename;dir="",typ="svg",io=stdout)
    srcpath = joinpath(dir,filename)
    run(pipeline(`dot -T$typ $srcpath`;stdout=io))
end

function geneNode(blocks,graphs)
    i = 0
    totallabel = []
    indexdict = Dict{String,Int}()
    edges = []
    for label in keys(blocks)
        s = join(map(x->"    "*strip(x[1])*"\\l",blocks[label]),"")
        s = label*":\\l"*s
        s = replace(s,r"\""=>raw"\\\"")
        indexdict[label] = i
        push!(totallabel,"node$i  [label=\"$s\"];")
        i+=1
    end
    for label in keys(blocks)
        if haskey(graphs,label)
            i1 = indexdict[label]
            for child in graphs[label]
                if haskey(indexdict,child)
                    i2 = indexdict[child]
                    push!(edges,"node$i1 -> node$i2;")
                end
            end
        end
    end
    nodestr = join(totallabel,'\n')
    edgestr = join(edges,'\n')
    return (indexdict,"""
        digraph G{
            mindist=0.75;
            ranksep=0.75;
            node [style=filled,fillcolor="#f8f8f8",margin=\"0.1,0.05\",shape=box,]
            $nodestr
            $edgestr
        }
    """)
end

const HTMLTEMPLATE = open(joinpath(@__DIR__,"template.html")) do f
    read(f,String)
end
const SVGTEMPLATE = open(joinpath(@__DIR__,"template.svg")) do f
    read(f,String)
end

function llvm2graphfile(fun,types,filepath,filetype="html")
    # reflection to get the llvm of function
    io = IOBuffer()
    getLLVMIR(io,fun,types)
    io = IOBuffer(String(take!(io)))
    # reparse the ir to get the graph
    funcdef,graphs,blocks = reparse(io)
    name = "$(string(fun))_$(join(string.(types.parameters),'_'))"*".gv"
    if length(name) > 100
        name = name[1:100]
    end
    # convert the graph to dot file
    indexdict,fullstr = geneNode(blocks,graphs)
    open(joinpath(filepath,name),write=true) do f
        write(f,fullstr)
    end
    # run dot to get svg/html file
    io = IOBuffer()
    rundot(joinpath(filepath,name);dir="",io=io)
    rm(joinpath(filepath,name))
    #post process the svg/html to add comment and remove default title
    s = String(take!(io))
    html = parsehtml(s).root.children[2][1]
    revdict = Dict([indexdict[i]=>i for i in keys(indexdict)])
    for node in eachmatch(Selector("g [class=node]"),html)
        nodename = node.children[1].children[1].text
        #pushfirst!(node.children,r)
        label = revdict[parse(Int,nodename[5:end])]
        intrs = blocks[label]
        alltext = eachmatch(Selector("text"),node)[2:end]
        if length(intrs) != length(alltext)
            global debug = Base.@locals
            error()
        end
        io = IOBuffer()
        for i in eachindex(alltext)
            d = alltext[i].attributes
            datamsg = ""*join(replace(intrs[i][2],'`'=>"&#39"),"<br>")*""
            replace(datamsg,r"[│┌└]+"=>" ")
            if !isempty(strip(datamsg)) && filetype=="html"
                d["data-msg"] = datamsg
                d["onmousemove"] = "showTooltip(evt);"
                d["onmouseout"] = "hideTooltip();"
            end
            text = alltext[i].children[1].text
            print_llvm_tokens(io,text)
            s = parsehtml(String(take!(io))).root.children[2].children
            empty!(alltext[i].children)
            append!(alltext[i].children,s)
        end
    end
    # finally, output svg or html
    if filetype=="svg"
        s = replace(SVGTEMPLATE,"TEMPLATE"=>string(html))
    elseif filetype =="html"
        s = replace(HTMLTEMPLATE,"TEMPLATE"=>string(html))
    else
        error()
    end
    htmlname = joinpath(filepath,splitext(name)[1]*".$filetype")
    open(htmlname,write=true) do f
        write(f,s)
    end
    return htmlname
end

max_stars_repo_name: ChenNingCong/IRViewer

max_issues_repo_name: ChenNingCong/IRViewer

max_forks_repo_name: ChenNingCong/IRViewer


text:
module IKMimic

using RigidBodyDynamics
using RigidBodyDynamics.Graphs: target, TreePath
import RigidBodyDynamics.CustomCollections
using RigidBodyDynamics.PDControl: group_error
using Rotations
using Compat

const VectorView{T} = SubArray{T, 1, Vector{T}, Tuple{UnitRange{Int}}, true}
const MatrixView{T} = SubArray{T, 2, Matrix{T}, Tuple{UnitRange{Int}, UnitRange{Int}}, false}

#=
Given the current state of the reference model, x1, find an associated
state of the target model, x2, to match the position of a collection of
bodies and the orientation of another collection of bodies between the
two models.

Currently assumes that the origins and orientations of the matching bodies
are identical in the two models.

To do that, we create a function y = f(x), such that y is the concatenation
of the positions, velocities, orientations, and twists of the target bodies.
We then linearize f: y ≈ f(x0) + J (x - x0) = y0 + J (x - x0)

We now have an optimization problem:

minimize ||J (x2 - x20) + y20 - y10 ||^2
  x2

= ||Jx2 + (y20 - y10 - Jx20) || ^2
= ||Jx2 + b||^2
    where b = (y20 - y10 - J x20)
= x2'J'Jx2 + 2b'Jx2 + b'b

which we can solve exactly by setting its gradient to zero:

J'Jx2 + J'b = 0

x2 = (J'J) \ -J'b

alternatively, we can perform a gradient descent update:

x2 = x2 - α * (J'Jx2 + J'b)

=#

struct PointTask{T}
    path_to_body::TreePath{RigidBody{T}, Joint{T}}
    jac::Spatial.PointJacobian{Matrix{T}}
    J_q::MatrixView{T}
    J_v::MatrixView{T}
end

struct PointError{T}
    reference_body::RigidBody{T}
    result_body::RigidBody{T}
    e_q::VectorView{T}
    e_v::VectorView{T}
end

function update!(task::PointTask, state::MechanismState, J_qdot_to_v)
    body = target(task.path_to_body)
    p = transform_to_root(state, body) * Point3D(default_frame(body), 0., 0, 0)
    point_jacobian!(task.jac, state, task.path_to_body, p)
    task.J_v .= task.jac.J

    # task.J_q .= task.jac.J * parent(J_qdot_to_v)
    A_mul_B!(task.J_q, task.jac.J, parent(J_qdot_to_v))
    nothing
end

function update!(e::PointError, reference_state::MechanismState, result_state::MechanismState)
    H1 = transform_to_root(reference_state, e.reference_body)
    H2 = transform_to_root(result_state, e.result_body)
    T1 = twist_wrt_world(reference_state, e.reference_body)
    T2 = twist_wrt_world(result_state, e.result_body)
    e.e_q .= group_error(translation(H2), translation(H1))
    ṗ1 = point_velocity(T1, H1 * Point3D(default_frame(e.reference_body), 0., 0, 0))
    @framecheck ṗ1.frame root_frame(reference_state.mechanism)
    ṗ2 = point_velocity(T2, H2 * Point3D(default_frame(e.result_body), 0., 0, 0))
    @framecheck ṗ2.frame root_frame(result_state.mechanism)
    e.e_v .= group_error(ṗ2.v, ṗ1.v)
    nothing
end

struct OrientationTask{T}
    path_to_body::TreePath{RigidBody{T}, Joint{T}}
    jac::Spatial.GeometricJacobian{Matrix{T}}
    J_q::MatrixView{T}
    J_v::MatrixView{T}
end

struct OrientationError{T}
    reference_body::RigidBody{T}
    result_body::RigidBody{T}
    e_q::VectorView{T}
    e_v::VectorView{T}
end

function update!(task::OrientationTask, state::MechanismState, J_qdot_to_v)
    body = target(task.path_to_body)
    geometric_jacobian!(task.jac, state, task.path_to_body)
    task.J_v .= angular(task.jac)

    # task.J_q .= angular(task.jac) * J_qdot_to_v
    A_mul_B!(task.J_q, angular(task.jac), parent(J_qdot_to_v))
    nothing
end

function update!(e::OrientationError, reference_state::MechanismState, result_state::MechanismState)
    H1 = transform_to_root(reference_state, e.reference_body)
    H2 = transform_to_root(result_state, e.result_body)
    T1 = twist_wrt_world(reference_state, e.reference_body)
    T2 = twist_wrt_world(result_state, e.result_body)
    rot = RodriguesVec(group_error(rotation(H2), rotation(H1)))
    e.e_q .= (rot.sx, rot.sy, rot.sz)
    e.e_v .= group_error(angular(T2), angular(T1))
    nothing
end

struct TaskMap{T}
    point_tasks::Vector{PointTask{T}}
    point_errors::Vector{PointError{T}}
    orientation_tasks::Vector{OrientationTask{T}}
    orientation_errors::Vector{OrientationError{T}}
    J::Matrix{T}
    y2_minus_y1::Vector{T}
    J_qdot_to_v::CustomCollections.SegmentedBlockDiagonalMatrix{T, Matrix{T}}

    function TaskMap{T}(result_mechanism::Mechanism{T}, point_matches::AbstractVector{Tuple{RigidBody{T}, RigidBody{T}}}, orientation_matches::AbstractVector{Tuple{RigidBody{T}, RigidBody{T}}}) where {T}
        nq = num_positions(result_mechanism)
        nv = num_velocities(result_mechanism)
        ny = 6 * (length(point_matches) + length(orientation_matches))
        J = zeros(ny, nq + nv)
        y2_minus_y1 = zeros(ny)

        point_tasks = PointTask{T}[]
        point_errors = PointError{T}[]
        row = 1
        for (reference_body, result_body) in point_matches
            path_to_body = path(result_mechanism, root_body(result_mechanism), result_body)
            I = row - 1 + (1:6)
            J_q = view(J, I[1:3], 1:nq)
            J_v = view(J, I[4:6], nq + (1:nv))  # TODO: missing ∂ṗ/∂q
            jac = PointJacobian(zeros(3, nv), root_frame(result_mechanism))
            task = PointTask{T}(path_to_body, jac, J_q, J_v)
            e_q = view(y2_minus_y1, I[1:3])
            e_v = view(y2_minus_y1, I[4:6])
            err = PointError{T}(reference_body, result_body, e_q, e_v)
            push!(point_tasks, task)
            push!(point_errors, err)
            row += 6
        end
        orientation_tasks = OrientationTask{T}[]
        orientation_errors = OrientationError{T}[]
        for (reference_body, result_body) in orientation_matches
            path_to_body = path(result_mechanism, root_body(result_mechanism), result_body)
            I = row - 1 + (1:6)
            J_q = view(J, I[1:3], 1:nq)
            J_v = view(J, I[4:6], nq + (1:nv))  # TODO: missing ∂ω/∂q
            jac = GeometricJacobian(default_frame(result_body), root_frame(result_mechanism), root_frame(result_mechanism), zeros(3, nv), zeros(3, nv))
            task = OrientationTask{T}(path_to_body, jac, J_q, J_v)
            e_q = view(y2_minus_y1, I[1:3])
            e_v = view(y2_minus_y1, I[4:6])
            err = OrientationError{T}(reference_body, result_body, e_q, e_v)
            push!(orientation_tasks, task)
            push!(orientation_errors, err)
            row += 6
        end

        # TODO: this jacobian could be allocated without actually constructing
        # a MechanismState
        J_qdot_to_v = RigidBodyDynamics.configuration_derivative_to_velocity_jacobian(MechanismState(result_mechanism))

        new{T}(point_tasks, point_errors, orientation_tasks, orientation_errors, J, y2_minus_y1, J_qdot_to_v)
    end
end

function TaskMap(reference_mechanism::Mechanism{T}, result_mechanism::Mechanism{T}, point_matches::AbstractVector{<:AbstractString}, orientation_matches::AbstractVector{<:AbstractString}) where {T}
    TaskMap{T}(result_mechanism,
        [(findbody(reference_mechanism, b), findbody(result_mechanism, b)) for b in point_matches],
        [(findbody(reference_mechanism, b), findbody(result_mechanism, b)) for b in orientation_matches])
end

function TaskMap(reference_mechanism::Mechanism, result_mechanism::Mechanism, point_and_orientation_matches::AbstractVector)
    TaskMap(reference_mechanism, result_mechanism, point_and_orientation_matches, point_and_orientation_matches)
end

function update!(task_map::TaskMap, reference_state::MechanismState, result_state::MechanismState)
    J_qdot_to_v = task_map.J_qdot_to_v
    RigidBodyDynamics.configuration_derivative_to_velocity_jacobian!(J_qdot_to_v, result_state)
    for task in task_map.point_tasks
        update!(task, result_state, J_qdot_to_v)
    end
    for task in task_map.orientation_tasks
        update!(task, result_state, J_qdot_to_v)
    end
    for e in task_map.point_errors
        update!(e, reference_state, result_state)
    end
    for e in task_map.orientation_errors
        update!(e, reference_state, result_state)
    end
end

struct IKMimicWorkspace{T}
    task_map::TaskMap{T}
    A::Matrix{T}
    b::Vector{T}
    A_fact::Base.RefValue{LinAlg.Cholesky{T, Matrix{T}}}
    g::Vector{T}
    x1::Vector{T}
    q1::VectorView{T}
    v1::VectorView{T}
    x2::Vector{T}
    q2::VectorView{T}
    v2::VectorView{T}

    function IKMimicWorkspace{T}(reference_mechanism::Mechanism{T}, result_mechanism::Mechanism{T}, task_map::TaskMap{T}) where {T}
        x1 = zeros(num_positions(reference_mechanism) + num_velocities(reference_mechanism))
        q1 = view(x1, 1:num_positions(reference_mechanism))
        v1 = view(x1, num_positions(reference_mechanism) + (1:num_velocities(reference_mechanism)))
        x2 = zeros(num_positions(result_mechanism) + num_velocities(result_mechanism))
        q2 = view(x2, 1:num_positions(result_mechanism))
        v2 = view(x2, num_positions(result_mechanism) + (1:num_velocities(result_mechanism)))

        # Need to temporarily make A pos def so we can easily allocate its
        # cholfact, so we initialize it to I
        A = Matrix(1.0I, length(x2), length(x2))
        b = fill(0.0, length(task_map.y2_minus_y1))
        A_fact = cholfact!(A)
        g = fill(0.0, length(x2))
        new{T}(task_map, A, b, Ref(A_fact), g, x1, q1, v1, x2, q2, v2)
    end
end

function IKMimicWorkspace(reference_mechanism::Mechanism{T}, result_mechanism::Mechanism{T}, args...) where {T}
    task_map = TaskMap(reference_mechanism, result_mechanism, args...)
    IKMimicWorkspace{T}(reference_mechanism, result_mechanism, task_map)
end

IKMimicWorkspace(x1::MechanismState, x2::MechanismState, args...) =
    IKMimicWorkspace(x1.mechanism, x2.mechanism, args...)

function clamp_to_position_bounds!(q::AbstractVector, joints::AbstractVector{<:Joint})
    i = 1
    for joint in joints
        for bound in position_bounds(joint)
            q[i] = clamp(q[i], bound)
            i += 1
        end
    end
    @assert i == length(q) + 1
end

function update!(work::IKMimicWorkspace, reference_state::MechanismState, result_state::MechanismState)
    update!(work.task_map, reference_state, result_state)
    copy!(work.q1, configuration(reference_state))
    copy!(work.v1, velocity(reference_state))
    copy!(work.q2, configuration(result_state))
    copy!(work.v2, velocity(result_state))
    J = work.task_map.J

    # A = J' * J
    At_mul_B!(work.A, J, J)

    # b = work.task_map.y2_minus_y1 - J * work.x2
    A_mul_B!(work.b, J, work.x2)
    work.b .= work.task_map.y2_minus_y1 .- work.b

    # work.x2 .= A \ (-J' * b)
    At_mul_B!(work.g, J, work.b)
    work.g .*= -1
    work.A_fact[] = cholfact!(Hermitian(work.A))
    A_ldiv_B!(work.x2, work.A_fact[], work.g)

    clamp_to_position_bounds!(work.q2, tree_joints(result_state.mechanism))
end

function ik_mimic!(result_state::MechanismState, reference_state::MechanismState, work::IKMimicWorkspace)
    update!(work, reference_state, result_state)
    set_configuration!(result_state, work.q2)
    set_velocity!(result_state, work.v2)
    nothing
end

function ik_mimic!(result_state, reference_state, args...)
    work = IKMimicWorkspace(reference_state.mechanism, result_state.mechanism, args...)
    ik_mimic!(result_state, reference_state, work)
end

# struct BodyData{T}
#     body::RigidBody{T}
#     path_to_body::TreePath{RigidBody{T}, Joint{T}}
#     J_geometric::Spatial.GeometricJacobian{Matrix{T}}
#     A_q_angular::MatrixView{T}
#     b_q_angular::VectorView{T}
#     A_q_linear::MatrixView{T}
#     b_q_linear::VectorView{T}
#     A_v_angular::MatrixView{T}
#     b_v_angular::VectorView{T}
#     A_v_linear::MatrixView{T}
#     b_v_linear::VectorView{T}
# end

# struct BodyMap{T}
#     body_data::Vector{BodyData{T}}
#     J_q_to_v::CustomCollections.SegmentedBlockDiagonalMatrix{T, Matrix{T}}
#     A::Matrix{T}
#     b::Vector{T}
#     x0::Vector{T}
#     b0::Vector{T}

#     function BodyMap(state::MechanismState{T}, bodynames::AbstractVector{<:AbstractString}) where {T}
#         mechanism = state.mechanism
#         nq = num_positions(state)
#         nv = num_velocities(state)
#         A = zeros(12 * length(bodynames), nq + nv)
#         b = zeros(12 * length(bodynames))
#         x0 = zeros(nq + nv)
#         b0 = similar(b)
#         J_q_to_v = RigidBodyDynamics.configuration_derivative_to_velocity_jacobian(state)
#         row = 1
#         bodydata = Vector{BodyData{T}}()
#         for bodyname in bodynames
#             body = findbody(mechanism, bodyname)
#             path_to_body = path(mechanism, root_body(mechanism), body)
#             J_geometric = geometric_jacobian(state, path_to_body)
#             rows = row:(row + 11)
#             A_q_angular = view(A, rows[1:3], 1:nq)
#             b_q_angular = view(b, rows[1:3])
#             A_q_linear = view(A, rows[4:6], 1:nq)
#             b_q_linear = view(b, rows[4:6])
#             A_v_angular = view(A, rows[7:9], nq + (1:nv))
#             b_v_angular = view(b, rows[7:9])
#             A_v_linear = view(A, rows[10:12], nq + (1:nv))
#             b_v_linear = view(b, rows[10:12])
#             push!(bodydata,
#                 BodyData{T}(body,
#                     path_to_body,
#                     J_geometric,
#                     A_q_angular,
#                     b_q_angular,
#                     A_q_linear,
#                     b_q_linear,
#                     A_v_angular,
#                     b_v_angular,
#                     A_v_linear,
#                     b_v_linear,
#                ))
#             row += 12
#         end
#         new{T}(bodydata, J_q_to_v, A, b, x0, b0)
#     end
# end

# function update_linearization!(data::BodyData, state::MechanismState, J_q_to_v)
#     geometric_jacobian!(data.J_geometric, state, data.path_to_body)
#     A_mul_B!(data.A_q_angular, angular(data.J_geometric), parent(J_q_to_v))
#     A_mul_B!(data.A_q_linear, linear(data.J_geometric), parent(J_q_to_v))
#     data.A_v_angular .= angular(data.J_geometric)
#     data.A_v_linear .= linear(data.J_geometric)
#     H = transform_to_root(state, data.body)
#     r = RodriguesVec(rotation(H))
#     data.b_q_angular .= (r.sx, r.sy, r.sz)
#     data.b_q_linear .= translation(H)
#     T = twist_wrt_world(state, data.body)
#     data.b_v_angular .= angular(T)
#     data.b_v_linear .= linear(T)
#     nothing
# end

# function update_linearization!(bodymap::BodyMap, state::MechanismState)
#     RigidBodyDynamics.configuration_derivative_to_velocity_jacobian!(bodymap.J_q_to_v, state)
#     for data in bodymap.body_data
#         update_linearization!(data, state, bodymap.J_q_to_v)
#     end
#     copy!(bodymap.x0, configuration(state))
#     copy!(bodymap.x0, CartesianRange((num_positions(state)+(1:num_velocities(state)),)), velocity(state), CartesianRange((1:num_velocities(state),)))
#     A_mul_B!(bodymap.b0, bodymap.A, bodymap.x0)
#     bodymap.b .= bodymap.b .- bodymap.b0;
#     nothing
# end

# _unwrap(x::Real, y::Real) = x + (mod((y - x) + π, 2π) - π)

# function _unwrap!(dest::BodyData, src::BodyData)
#     dest.b_q_angular .= _unwrap.(src.b_q_angular, dest.b_q_angular)
#     dest.b_v_angular .= _unwrap.(src.b_v_angular, dest.b_v_angular)
# end

# function _unwrap!(dest::BodyMap, src::BodyMap)
#     for i in eachindex(dest.body_data)
#         _unwrap!(dest.body_data[i], src.body_data[i])
#     end
# end

# mutable struct IKMimicWorkspace{T}
#     reference::BodyMap{T}
#     result::BodyMap{T}
#     H::Matrix{T}
#     H_fact::LinAlg.Cholesky{T, Matrix{T}}
#     p1::Vector{T}
#     f1::Vector{T}
#     f2::Vector{T}
#     x2::Vector{T}

#     function IKMimicWorkspace(reference::BodyMap{T}, result::BodyMap{T}) where {T}
#         H = eye(T, size(result.A, 2), size(result.A, 2))
#         H_fact = cholfact!(H)
#         p1 = zeros(T, size(reference.A, 1))
#         f1 = zeros(T, size(result.A, 2))
#         f2 = zeros(T, size(result.A, 2))
#         x2 = zeros(T, size(result.A, 2))
#         new{T}(reference, result, H, H_fact, p1, f1, f2, x2)
#     end
# end

# function IKMimicWorkspace(reference::MechanismState, result::MechanismState, bodynames::AbstractVector{<:AbstractString})
#     IKMimicWorkspace(BodyMap(reference, bodynames), BodyMap(result, bodynames))
# end

# struct SensitivityWorkspace{T}
#     A2tA1::Matrix{T}
#     J::Matrix{T}

#     function SensitivityWorkspace{T}(reference_nx::Integer, result_nx::Integer) where {T}
#         new{T}(zeros(T, result_nx, reference_nx),
#                zeros(T, result_nx, reference_nx))
#     end

# end

# function mimic_update!(work::IKMimicWorkspace)
#     _unwrap!(work.reference, work.result)
#     A1 = work.reference.A
#     b1 = work.reference.b
#     A2 = work.result.A
#     b2 = work.result.b

#     A_mul_B!(work.p1, A1, work.reference.x0)
#     work.p1 .= work.p1 .+ b1

#     At_mul_B!(work.H, A2, A2)

#     At_mul_B!(work.f1, A2, work.p1)
#     At_mul_B!(work.f2, A2, b2)
#     work.f1 .= work.f1 .- work.f2
#     work.H_fact = cholfact!(Hermitian(work.H))
#     A_ldiv_B!(work.x2, work.H_fact, work.f1)

# end

# function ik_mimic!(result::MechanismState, reference::MechanismState, work::IKMimicWorkspace, iters=1)
#     update_linearization!(work.reference, reference)
#     for i in 1:iters
#         update_linearization!(work.result, result)
#         mimic_update!(work)
#         nq = num_positions(result)
#         nv = num_velocities(result)
#         set_configuration!(result, work.x2[1:nq])
#         set_velocity!(result, work.x2[1 + (1:nv)])
#         # copy!(result, work.x2)
#     end
#     nothing
# end

# function ik_mimic!(result::MechanismState, reference::MechanismState, bodynames::AbstractVector{<:AbstractString}, iters=1)
#     work = IKMimicWorkspace(BodyMap(reference, bodynames),
#                             BodyMap(result, bodynames))
#     ik_mimic!(result, reference, work, iters)
# end

# function sensitivity(work::IKMimicWorkspace{T}) where {T}
#     sensitivity!(
#         SensitivityWorkspace{T}(
#             size(work.reference.A, 2), size(work.result.A, 2)),
#         work)
# end

# function sensitivity!(sensitivity_work::SensitivityWorkspace,
#                       work::IKMimicWorkspace)
#     At_mul_B!(sensitivity_work.A2tA1, work.result.A, work.reference.A)
#     A_ldiv_B!(sensitivity_work.J, work.H_fact, sensitivity_work.A2tA1)
#     sensitivity_work.J
# end

# (A2' * A2) \ (A2' * (A1 * x + b1) - A2' * b2)
# (A2' * A2) \ (A2' * A1) * x + (const)

# function mimic_update!(variable::BodyMap, reference::BodyMap)
#     _unwrap!(reference, variable)
#     p1 = reference.A * reference.x0 + reference.b
#     A2 = variable.A
#     b2 = variable.b
#     x2 = (A2' * A2) \ (A2' * p1 - A2' * b2)
#     copy!(variable.state, x2)
# end

end # module


text:
using Test
using DualDecomposition
using JuMP, Ipopt, GLPK
using MPI
using LinearAlgebra

const DD = DualDecomposition

include("farmer.jl")
include("mpi.jl")
include("investment.jl")
include("heuristics.jl")


text:
using Aqua
using Test
using NCDatasets
using EmpiricalOrthogonalFunctions

testdir = @__DIR__
datadir = joinpath(testdir, "data")

ds = NCDataset(joinpath(datadir,"sst.mnmean.1990-present.nc"))

@testset "EmpiricalOrthogonalFunctions" begin

    sst = ds["sst"][:]
    dsin = copy(sst)

    # @testset "EOF Construction" begin
        eof = EmpiricalOrthogonalFunction(dsin)

        dsin = permutedims(sst,(3,1,2))
        eof = EmpiricalOrthogonalFunction(dsin; timedim=1)

        dsin = permutedims(sst,(1,3,2))
        eof = EmpiricalOrthogonalFunction(dsin; timedim=2)
    # end

    # @testset "EOF Analysis" begin

        # @testset "eigenvals" begin
            @test totalanomalyvar(eof) ≈ 2673.0002f0 atol=1e-3
            @test eigenvalues(eof,n=5)[1] ≈ 1332.6342
            @test variancefraction(eof, n=100)[1] ≈ 0.4985537f0 atol=1e-3
        # end

        # @testset "pcs" begin
            @test pcs(eof,n=1)[1,1] ≈ -10.937908 atol=1e-3
            @test pcs(eof,scaling=:divide)[1,1] ≈ -0.299626 atol=1e-3
            @test pcs(eof,scaling=:multiply, n=10)[1,1] ≈ -399.291
        # end

        # @testset "eofs" begin
            @test eofs(eof,n=5)[1,:] ≈ [0.0279191, -0.00658843, 0.02273, -0.00208263, 0.0347027] atol=1e-3
            @test eofs(eof,n=2,scaling=:divide)[1,:] ≈ [0.000764796, -0.000231014] atol=1e-3
            @test eofs(eof,n=3,scaling=:multiply)[1,:] ≈ [ 1.01919, -0.1879, 0.293734] atol=1e-3
        # end

        # @testset "projection" begin
            @test all((reshape(reconstruct(eof), size(sst)) ≈ sst)...)
            @test projectfield(eof, collect(eof.dataset))[1,1] ≈ 230.678 atol=1e-3
        # end

        # @testset "rotation" begin
            reof = orthorotation(eof,n=4)

            @test eofs(reof)[1,:] ≈ [0.02492, -0.00625398, 0.0254053, 0.00619081] atol=1e-3

        # end
    # end
end

close(ds)

Aqua.test_all(EmpiricalOrthogonalFunctions)

# end tests


text:
"""
    aic(max_loglike, k)

Computes the Akaike Information Criterion (AIC).

# Arguments
* `max_loglike`: the log likelihood evaluated at the maximum likelihood estimate
* `k`: the number of parameters in the model

# Returns
* `aic::Real`: AIC value
"""
aic(max_loglike, k) = 2 * (k - max_loglike)

"""
    bic(max_loglike, k)

Computes the Bayesian Information Criterion (AIC).

# Arguments
* `max_loglike`: the log likelihood evaluated at the maximum likelihood estimate
* `k`: the number of parameters in the model
* `n`: the number of observations in the data

# Returns
* `bic::Real`: BIC value
"""
bic(max_loglike, k, n) = k * log(n) - 2 * max_loglike


text:
"""
    side_panel(content...)

A narrow/side control (1/3 width) panel to be embedded in a `sidebar_layout`

Should only be used as part of a `sidebar_layout`
"""
function side_panel(content...)
    (UIElement("""<v-col cols = "4"><v-card><v-card-text>"""),
    content...,
    UIElement("</v-card-text></v-card></v-col>"))
end

"""
     main_panel(content...)

A main (2/3 width) panel to be embedded in a `sidebar_layout`

Should only be used as part of a `sidebar_layout`
"""
function main_panel(content...)
    (UIElement("""<v-col cols = "8"><v-card><v-card-text>"""),
    content...,
    UIElement("</v-card-text></v-card></v-col>"))
end

"""
    sidebar_layout(leftpanel, rightpanel)

Create a side bar layout for your app: a 1/3 width control panel and a 2/3 width
main/output panel.
"""
function sidebar_layout(leftpanel, rightpanel)
    (UIElement("""<v-container cols = "12"><v-row>"""),
    leftpanel, rightpanel,
    UIElement("</v-row></v-container>"))
end

"""
    custom_grid_layout(content...)

Create a container to contain a custom layout.

Containers embed rows (which embed columns) to create layouts.
"""
function custom_grid_layout(content...)
    (UIElement("<v-container cols = \"12\">"), content, UIElement("</v-container>"))
end

"""
    custom_grid_row(content...)

Create a row for a custom layout

Rows wrap columns.
"""
function custom_grid_row(content...)
    (UIElement("<v-row>"), content, UIElement("</v-row>"))
end

"""
    custom_grid_column(content...; width = 12)

Create a layout column that covers width/12 of the row

Columns must be contained in rows (`custom_grid_row`)
"""
function custom_grid_column(content...; width = 12)
    (UIElement("<v-col cols = \"$width\">"), content, UIElement("</v-col>"))
end

"""
    custom_card(content...)

Create a 'card' to contain content. Cards are boxes with drop shadows.

For use in `custom_grid_layout`s, to define sections of the page inside a column
"""
function custom_card(content...)
    (UIElement("<v-card><v-card-text>"), content, UIElement("</v-card></v-card-text>"))
end

struct TabPanel
    title::String
    content
    model
end

"""
    tabs_layout(tabs...; vertical = false)

Create a tab layout -- app (or inset) with pages that can be navigated to using
a series of tabs
"""
function tabs_layout(tabs...; vertical = false)

    start = UIElement("""
    <v-tabs
      background-color="indigo darken-4"
      dark
      $(vertical ? "vertical" : "")
      centered>""")

    tab_buttons = [UIElement("""<v-tab >$(tab.title)</v-tab>""") for (i, tab) in enumerate(tabs)]

    tab_content = ()
    for (i, tab) in enumerate(tabs)
        tab_content = (tab_content..., UIElement("""<v-tab-item>
          <v-card>"""), tab.content, tab.model,
          UIElement("""</v-card></v-tab-item>"""))
    end
    (start, tab_buttons..., tab_content, UIElement("</v-tabs>"))
end

"""
    tab_panel(title, content)

Define a panel for use in a tab layout

`tab_panel` should only be used as input to a `tabs_layout`
"""
function tab_panel(title, content)
    content = unroll(content)
    length(extract_uitype(UIFooter, content)) > 0 && error("Tab panels cannot contain a `footer`")
    length(extract_uitype(UIHeader, content)) > 0 && error("Tab panels cannot contain a `header`")

    model = extract_uitype(UIModel, content)
    content = extract_uitype(UIElement, content)

    TabPanel(title, content, model)
end

"""
    div(content...)

Create an html `<div>` and wrap `content` in it
"""

div(content...) = tag_wrap("div", content...)

"""
    span(content...)

Create an html `<span>` and wrap `content` in it
"""

span(content...) = tag_wrap("span", content...)

"""
    expansion_panel_list(items...)

Create a list of expansion panel items. `items` should _only_ be a set of `expansion_panel`s
"""
function expansion_panel_list(items...)
    tag_wrap("v-expansion-panels", items)
end

"""
    expansion_panel(header, content)

Create an expansion panel with that appears as `header` in the list and can expanded to also
show `content`

Should only be used inside an `expansion_panel_list`

If you need to include multiple elements inside `header` or `content`, wrap them as a tuple.
"""
function expansion_panel(header, content)
    tag_wrap("v-expansion-panel",
        (tag_wrap("v-expansion-panel-header", header),
        tag_wrap("v-expansion-panel-content", content)))
end

"""
    header(content, color, dark)

Define a custom app bar header. `content` should be html that will be included inside the
<v-app-bar> tag. See [Vuetify documentation](https://vuetifyjs.com/) for more information (or
a simple example is included in the Matte documentation).
"""
function header(content::AbstractString, color::AbstractString, dark::Bool)
    UIHeader("""
    <div>
    <v-app-bar
    color="$color"
    $(dark ? "dark" : "")>
        $content
    </v-app-bar>
    </div>
    """)
end

"""
    footer(content, bgcolor = "grey lighten-4")

Add a footer to your UI, containing `content`. If you need to include multiple elements
inside `content`, wrap them as a tuple.
"""
function footer(content, bgcolor = "grey lighten-4")
    (UIFooter("""<v-footer
      color = "$bgcolor">
      <v-col
        class="text-center"
        cols="12">"""),
    convert_uielement(UIFooter,unroll(content)),
    UIFooter("""
      </v-col>
    </v-footer>"""))
end

"""
    content_panel(content...)

Create the main content panel for your `footer_control_layout`. Should only be used as an
input to `footer_control_layout`.
"""
function content_panel(content...)
    content
end

"""
    control_panel(content...)

Create the control panel for your `footer_control_layout`. Should only be used as an input
to `footer_control_layout`.
"""
function control_panel(content...)
    content
end

"""
    footer_control_layout(main_panel, control_panel)

Creates a footer control layout, with a sticky/fixed-position footer at the bottom containing
the controls for the app, and the main content at the top.
"""
function footer_control_layout(main_panel, control_panel)
    UIElement("""<v-container><v-row><v-col cols = "12"><v-card><v-card-text>"""),
    main_panel,
    UIElement("</v-card-text></v-card></v-col></v-row></v-container>"),
    UIFooter("""<v-footer color = "white" fixed>
    <v-container><v-row><v-col
        class="text-center"
        cols="12">
    <v-card>
    <v-card-text>"""),
    convert_uielement(UIFooter,unroll(control_panel)),
    UIFooter("""
    </v-card-text>
    </v-card>
    </v-col>
    </v-row></v-container>
    </v-footer>""")
end


text:
using SirenSeq

"""
Options for a `csound` orchestra file `.orc` file to be generated.
"""
type CsHead
	dacStr::AbstractString  # csound options string
	sr::Int  # sample rate
	ksmps::Int  # samples per control cycle
end

CsHead() = CsHead("-odac",44100,32)

"""
A sound font `sf2` file reference.
"""
type SoundFont
	path::AbstractString
end

function Base.isequal(x::SoundFont, y::SoundFont)
	isequal(x.path,y.path)
end

"""
Abstract type for all `csound` instruments
"""
abstract CsInstr

"""
A single fluid synth instrument.
Give each instrument a unique name.
The same names will be used in the generated `csound` orchestra file.
"""
type FluidInst <: CsInstr
	name::AbstractString
	soundfont::SoundFont
	bank::Int # bank number in soundfont file
	prog::Int # program number in soundfont file
	isMono::Bool # else is stereo
end

FluidInst(name::AbstractString, sf::SoundFont, bank::Int, prog::Int) = FluidInst(name,sf,bank,prog,false)

FluidInst(name::AbstractString, sf::SoundFont, inst::Tuple{Int,Int}) = FluidInst(name,sf,inst[1],inst[2],false)

## name of oinstrument as will appear in the csound files
function instrName(n::FluidInst)
	"fluidI_$(n.name)"
end

"""
	makeOrc(head::CsHead, ns; path::AbstractString=\"temp\")

Generates a `csound` orchestra file at `path.orc`.

`head` defines some options of to-be-generated file \\
`ns` is a list of instruments (`<:CsInstr`) \\
`path` is the file name (do not append \".orc\", that is done automatically)
"""
function makeOrc(head::CsHead, ns; path::AbstractString="temp")
	file = open("$(path).orc","w")
	s =
"""

sr = $(head.sr)
ksmps = $(head.ksmps)
nchnls = 2
0dbfs = 1

"""
	write(file,s)
	sfs = Set{SoundFont}()
	nsns = Set{AbstractString}()
	for n in ns
		if !isa(n,CsInstr) ; throw(ErrorException("second argument (ns) must be a list of instruments (<:CsInstr)")) ; end
		pushSfs!(sfs,n)
		push!(nsns,n.name)
		for ch in n.name
			if 'A'>ch || 'z'<ch ; throw(ErrorException("invalid instrument name: $(n.name)")) ; end
		end
	end
	if length(nsns) < length(ns) ; throw(ErrorException("all instruments must have unique names")) ; end
	i = 1
	sfd = Dict{SoundFont,Int}()
	for sf in sfs
		sfd[sf] = i
		s = generateSfOrg(sf,i)
		i += 1
		write(file,s)
	end
	if i>1 ; write(file,"\n") ; end
	for n in ns
		s = generateInstrOrg(n,sfd)
		write(file,s)
	end
	close(file)
	println("orchestra file written to:\n  $(path).orc")
end

function pushSfs!(sfs::Set{SoundFont}, n::FluidInst)
	push!(sfs,n.soundfont)
end

## Generates the `csound` orchestra file part for a single soundfont
function generateSfOrg(sf::SoundFont, i::Int)
	s = "giSf$(i)  sfload  \"$(sf.path)\"\n"
	s
end

## Generates the `csound` orchestra file part for a single instrument
function generateInstrOrg(n::FluidInst, sfd::Dict{SoundFont,Int})
	nn = instrName(n)
	s =
"""
giPre_$(n.name)  sfpreset  $(n.prog), $(n.bank), giSf$(sfd[n.soundfont]), 0

	instr $(nn)

ivel = p5
ifrq = p4
ikey = int(69 + 12*log2(ifrq/440))
iamp = 0dbfs/16384
iamp = iamp*ivel/127
aVl, aVr  sfplay3  ivel, ikey, iamp, ifrq, giPre_$(n.name), 1
	outs  aVl, aVr

	endin

"""
	s
end


text:
#=
The text needs to be uploaded into a 2D texture, with 1D alignement, as there is no way to vary the row length, which would be a big waste of memory.
This is why there is the need, to prepare offsets information about where exactly new lines reside.
If the string doesn't contain a new line, the text is restricted to one line, which is uploaded into one 1D texture.
This is important for differentiation between multi-line and single line text, which might need different treatment
=#
function visualize(style::Style{:Default}, text::String, data::Dict{Symbol, Any})
  glypharray          = toglypharray(text)
  data[:style_group]  = Texture([data[:color]])
  data[:textlength]   = length(text) # needs to get remembered, as glypharray is usually bigger than the text
  data[:lines]        = count(x->x=='\n', text)
  textGPU             = Texture(glypharray)
  # To make things simple for now, checks if the texture is too big for the GPU are done by 'Texture' and an error gets thrown there.
  return visualize(style, textGPU, data)
end

# This is the low-level text interface, which simply prepares the correct shader and cameras
function visualize(::Style{:Default}, text::Texture{GLGlyph{Uint16}, 4, 2}, data::Dict{Symbol, Any})
  screen             = data[:screen]
  camera             = screen.orthographiccam
  renderdata         = merge(data, data[:font].data) # merge font texture and uv informations -> details @ GLFont/src/types.jl

  view = @compat Dict(
    "GLSL_EXTENSIONS" => "#extension GL_ARB_draw_instanced : enable"
  )
  renderdata[:text]           = text
  renderdata[:projectionview] = camera.projectionview
  shader = TemplateProgram(
    Pkg.dir("GLText", "src", "textShader.vert"), Pkg.dir("GLText", "src", "textShader.frag"),
    view=view, attributes=renderdata, fragdatalocation=[(0, "fragment_color"),(1, "fragment_groupid")]
  )
  obj = instancedobject(renderdata, data[:textlength], shader, GL_TRIANGLES, textboundingbox)
  prerender!(obj, enabletransparency, glDisable, GL_DEPTH_TEST, glDisable, GL_CULL_FACE,)
  return obj
end
function visualize(style::Style{:Default}, text::Vector{GLGlyph{Uint16}}, data::Dict{Symbol, Any})
  textstride = data[:stride]
  data[:textlength] = length(text) # remember text
  if length(text) % textstride != 0
    append!(text, Array(GLGlyph{Uint16}, textstride-(length(text)%textstride))) # append if can't be reshaped with 1024
  end
  data[:style_group]  = Texture([data[:color]])
  # To make things simple for now, checks if the texture is too big for the GPU are done by 'Texture' and an error gets thrown there.
  return visualize(style, Texture(reshape(text, textstride, div(length(text), textstride))), data)
end
function textboundingbox(obj)
  glypharray  = data(obj[:text])
  advance     = obj[:advance]
  newline     = obj[:newline]

  maxv = Vector3(typemin(Float32))
  minv = Vector3(typemax(Float32))
  glyphbox = Vec3(12,24,0)
  for elem in glypharray[1:obj.alluniforms[:textlength]]

    currentpos = elem.row*advance + elem.line*newline

    maxv = maxper(maxv, currentpos + glyphbox)
    minv = minper(minv, currentpos)
  end
  AABB(minv+newline, maxv)
end


text:
"""
    cliffords_sampler(;input::Input, interf::Interferometer)

Sample photons according to the [`Bosonic`](@ref) case following
[Clifford & Clifford](https://arxiv.org/pdf/2005.04214.pdf) algorithm performed
(at most) in ``O(n2^m + Poly(n,m))`` time and ``O(m)`` space.
"""
function cliffords_sampler(;input::Input, interf::Interferometer)

    m = input.m
    n = input.n
    perm_n_ = permutations(1:n)

    U = interf.U
    A = U[:, 1:n]
    A = A[:, nthperm(1:n, rand(1:factorial(big(n))))]

    weight_array = [abs(A[i,1])^2 for i in 1:m]
    sample_array = [wsample(1:m, Weights(weight_array))]

    for k in 2:n
        k_ = collect(1:k)
        permanent_matrix = reshape(A[sample_array, k_], length(sample_array), k)
        unormalized_pmf = LaplaceExpansion(permanent_matrix, A[:,k_])
        weight_array = unormalized_pmf/sum(unormalized_pmf)
        push!(sample_array, wsample(1:m, Weights(weight_array)))
    end

    return sort(sample_array)

end


text:
# Autogenerated wrapper script for Vulkan_Headers_jll for any
export vk_xml

## Global variables
PATH = ""
LIBPATH = ""
LIBPATH_env = "LD_LIBRARY_PATH"
LIBPATH_default = ""

# Relative path to `vk_xml`
const vk_xml_splitpath = ["share", "vulkan", "registry", "vk.xml"]

# This will be filled out by __init__() for all products, as it must be done at runtime
vk_xml_path = ""

# vk_xml-specific global declaration
# This will be filled out by __init__()
vk_xml = ""

"""
Open all libraries
"""
function __init__()
    global artifact_dir = abspath(artifact"Vulkan_Headers")

    # Initialize PATH and LIBPATH environment variable listings
    global PATH_list, LIBPATH_list
    global vk_xml_path = normpath(joinpath(artifact_dir, vk_xml_splitpath...))

    global vk_xml = vk_xml_path
    # Filter out duplicate and empty entries in our PATH and LIBPATH entries
    filter!(!isempty, unique!(PATH_list))
    filter!(!isempty, unique!(LIBPATH_list))
    global PATH = join(PATH_list, ':')
    global LIBPATH = join(vcat(LIBPATH_list, [joinpath(Sys.BINDIR, Base.LIBDIR, "julia"), joinpath(Sys.BINDIR, Base.LIBDIR)]), ':')
end  # __init__()


text:
using NordicEcon
using Documenter

DocMeta.setdocmeta!(NordicEcon, :DocTestSetup, :(using NordicEcon); recursive=true)

makedocs(;
    modules=[NordicEcon],
    authors="Erik Engheim <erik.engheim@mac.com> and contributors",
    repo="https://github.com/ordovician/NordicEcon.jl/blob/{commit}{path}#{line}",
    sitename="NordicEcon.jl",
    format=Documenter.HTML(;
        prettyurls=get(ENV, "CI", "false") == "true",
        assets=String[],
    ),
    pages=[
        "Home" => "index.md",
    ],
)

max_stars_repo_name: ordovician/NordicEcon

max_issues_repo_name: ordovician/NordicEcon

max_forks_repo_name: ordovician/NordicEcon


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "OpenLDAPClient"
version = v"2.4.50"

# Collection of sources required to complete build
sources = [
    ArchiveSource("https://www.openldap.org/software/download/OpenLDAP/openldap-release/openldap-2.4.50.tgz", "5cb57d958bf5c55a678c6a0f06821e0e5504d5a92e6a33240841fbca1db586b8")
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir
apk add groff
cd openldap*

#needed to build shared libraries
if [[ "${target}" == *-freebsd* || "${target}" == powerpc* || "${target}" == *-mingw* ]]; then
	libtoolize --force --copy
	AUTOMAKE=/bin/true autoreconf -fi
fi

#need a posix regex
if [[ "${target}" == *-mingw* ]]; then
	cp ${prefix}/include/pcreposix.h ${prefix}/include/regex.h
	export LDFLAGS="-lpcreposix-0 -L${prefix}/bin"
fi

if [[ "${target}" != *-freebsd* ]]; then
    # The mac build tries to pick up libraries from system root, but our build
    # of OpenSSL seems to be incomplete (it's missing some important symbols),
    # so let's keep this file for FreeBSD until we get reports it doesn't work.
    rm -f /opt/${target}/${target}/sys-root/usr/lib/libcrypto.*
    rm -f /opt/${target}/${target}/sys-root/usr/lib/libssl.*
    rm -f /opt/${target}/${target}/sys-root/usr/lib/libsasl2.*
    rm -f /lib/libcrypto.so*
    rm -f /usr/lib/libcrypto.so*
    rm -f /lib/libssl.so*
    rm -f /usr/lib/libssl.so*
fi

./configure --prefix=${prefix} \
    --build=${MACHTYPE} \
    --host=${target} \
    --disable-slapd \
    --without-yielding_select \
    --disable-static \
    --enable-shared \
    --enable-modules=yes \
    --enable-hdb=no \
    --enable-bdb=no
sed -in-place 's/#define NEED_MEMCMP_REPLACEMENT 1/\/\* #undef NEED_MEMCMP_REPLACEMENT \*\//' include/portable.h

make depend
make -j${nproc}
make install

if [[ "${target}" == *-mingw* ]]; then
    # Cover up the traces of the hack
    rm ${prefix}/include/regex.h
fi
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = supported_platforms()
products = [
    ExecutableProduct("ldapdelete", :ldapdelete),
    LibraryProduct("libldap", :libldap),
    ExecutableProduct("ldapsearch", :ldapsearch),
    ExecutableProduct("ldapwhoami", :ldapwhoami),
    LibraryProduct("liblber", :liblber),
    ExecutableProduct("ldapurl", :ldapurl),
    ExecutableProduct("ldappasswd", :ldappasswd),
    ExecutableProduct("ldapmodify", :ldapmodify),
    ExecutableProduct("ldapexop", :ldapexop),
    ExecutableProduct("ldapmodrdn", :ldapmodrdn),
    LibraryProduct("libldap_r", :libldap_r),
    ExecutableProduct("ldapcompare", :ldapcompare)
]

# Dependencies that must be installed before this package can be built
dependencies = [
    Dependency(PackageSpec(name="OpenSSL_jll", uuid="458c3c95-2e84-50aa-8efc-19380b2a3a95"))
    Dependency(PackageSpec(name="PCRE_jll",  uuid="2f80f16e-611a-54ab-bc61-aa92de5b98fc"))
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies)

max_stars_repo_name: jpsamaroo/Yggdrasil

max_issues_repo_name: jpsamaroo/Yggdrasil

max_forks_repo_name: jpsamaroo/Yggdrasil


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

mutable struct IoK8sApiCoreV1PodAffinityTerm <: SwaggerModel
    labelSelector::Any # spec type: Union{ Nothing, IoK8sApimachineryPkgApisMetaV1LabelSelector } # spec name: labelSelector
    namespaces::Any # spec type: Union{ Nothing, Vector{String} } # spec name: namespaces
    topologyKey::Any # spec type: Union{ Nothing, String } # spec name: topologyKey

    function IoK8sApiCoreV1PodAffinityTerm(;labelSelector=nothing, namespaces=nothing, topologyKey=nothing)
        o = new()
        validate_property(IoK8sApiCoreV1PodAffinityTerm, Symbol("labelSelector"), labelSelector)
        setfield!(o, Symbol("labelSelector"), labelSelector)
        validate_property(IoK8sApiCoreV1PodAffinityTerm, Symbol("namespaces"), namespaces)
        setfield!(o, Symbol("namespaces"), namespaces)
        validate_property(IoK8sApiCoreV1PodAffinityTerm, Symbol("topologyKey"), topologyKey)
        setfield!(o, Symbol("topologyKey"), topologyKey)
        o
    end
end # type IoK8sApiCoreV1PodAffinityTerm

const _property_map_IoK8sApiCoreV1PodAffinityTerm = Dict{Symbol,Symbol}(Symbol("labelSelector")=>Symbol("labelSelector"), Symbol("namespaces")=>Symbol("namespaces"), Symbol("topologyKey")=>Symbol("topologyKey"))
const _property_types_IoK8sApiCoreV1PodAffinityTerm = Dict{Symbol,String}(Symbol("labelSelector")=>"IoK8sApimachineryPkgApisMetaV1LabelSelector", Symbol("namespaces")=>"Vector{String}", Symbol("topologyKey")=>"String")
Base.propertynames(::Type{ IoK8sApiCoreV1PodAffinityTerm }) = collect(keys(_property_map_IoK8sApiCoreV1PodAffinityTerm))
Swagger.property_type(::Type{ IoK8sApiCoreV1PodAffinityTerm }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_IoK8sApiCoreV1PodAffinityTerm[name]))}
Swagger.field_name(::Type{ IoK8sApiCoreV1PodAffinityTerm }, property_name::Symbol) =  _property_map_IoK8sApiCoreV1PodAffinityTerm[property_name]

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

function validate_property(::Type{ IoK8sApiCoreV1PodAffinityTerm }, name::Symbol, val)
end


text:
module CairoMakie

using AbstractPlotting
using AbstractPlotting: Scene, Lines, Text, Image, Heatmap, Scatter, @key_str, broadcast_foreach
using AbstractPlotting: convert_attribute, @extractvalue, LineSegments, to_ndim, NativeFont
using AbstractPlotting: @info, @get_attribute, Combined
using Colors, GeometryTypes
using AbstractPlotting: to_value, to_colormap, extrema_nan
using FileIO, StaticArrays
using LinearAlgebra
import Cairo
using Cairo: CairoContext, CairoARGBSurface, CairoSVGSurface

@enum RenderType SVG PNG

const LIB_CAIRO = if isdefined(Cairo, :libcairo)
    Cairo.libcairo
else
    Cairo._jl_libcairo
end

struct CairoBackend <: AbstractPlotting.AbstractBackend
    typ::RenderType
    path::String
end

function to_mime(x::RenderType)
    x == SVG && return MIME"image/svg+xml"()
    return MIME"image/png"()
end

to_mime(x::CairoBackend) = to_mime(x.typ)

function CairoBackend(path::String)
    ext = splitext(path)[2]
    typ = if ext == ".png"
        PNG
    elseif ext == ".svg"
        SVG
    else
        error("Unsupported extension: $ext")
    end
    CairoBackend(typ, path)
end

struct CairoScreen{S} <: AbstractPlotting.AbstractScreen
    scene::Scene
    surface::S
    context::CairoContext
    pane::Nothing#Union{CairoGtkPane, Void}
end
# # we render the scene directly, since we have no screen dependant state like in e.g. opengl
Base.insert!(screen::CairoScreen, scene::Scene, plot) = nothing

# Default to Window+Canvas as backing device
function CairoScreen(scene::Scene)
    w, h = size(scene)
    surf = CairoRGBSurface(w, h)
    ctx = CairoContext(surf)
    CairoScreen(scene, surf, ctx, nothing)
end

function CairoScreen(scene::Scene, path::Union{String, IO}; mode = :svg)
    w, h = round.(Int, scene.camera.resolution[])
    # TODO: Add other surface types (PDF, etc.)
    if mode == :svg
        surf = CairoSVGSurface(path, w, h)
    else
        error("No available Cairo surface for mode $mode")
    end
    ctx = CairoContext(surf)
    CairoScreen(scene, surf, ctx, nothing)
end

function project_position(scene, point, model)
    res = scene.camera.resolution[]
    p4d = to_ndim(Vec4f0, to_ndim(Vec3f0, point, 0f0), 1f0)
    clip = scene.camera.projectionview[] * model * p4d
    p = (clip ./ clip[4])[Vec(1, 2)]
    p = Vec2f0(p[1], -p[2])
    ((((p .+ 1f0) / 2f0) .* (res .- 1f0)) .+ 1f0)
end

project_scale(scene::Scene, s::Number, model = Mat4f0(I)) = project_scale(scene, Vec2f0(s), model)

function project_scale(scene::Scene, s, model = Mat4f0(I))
    p4d = to_ndim(Vec4f0, s, 0f0)
    p = (scene.camera.projectionview[] * model * p4d)[Vec(1, 2)] ./ 2f0
    p .* scene.camera.resolution[]
end

function draw_segment(scene, ctx, point::Point, model, c, linewidth, linestyle, primitive, idx, N)
    pos = project_position(scene, point, model)
    function stroke()
        Cairo.set_line_width(ctx, Float64(linewidth))
        Cairo.set_source_rgba(ctx, red(c), green(c), blue(c), alpha(c))
        if linestyle != nothing
            #set_dash(ctx, linestyle, 0.0)
        end
        Cairo.stroke(ctx)
    end
    if !all(isfinite.(pos))
        stroke() # stroke last points, ignore this one (NaN for disconnects)
    else
        if isa(primitive, LineSegments)
            if isodd(idx) # on each odd move to
                Cairo.move_to(ctx, pos[1], pos[2])
            else
                Cairo.line_to(ctx, pos[1], pos[2])
                stroke() # stroke after each segment
            end
        else
            if idx == 1
                Cairo.move_to(ctx, pos[1], pos[2])
            else
                Cairo.line_to(ctx, pos[1], pos[2])
                Cairo.move_to(ctx, pos[1], pos[2])
            end
        end
    end
    if idx == N && isa(primitive, Lines) # after adding all points, lines need a stroke
        stroke()
    end
end

function draw_segment(scene, ctx, point::Tuple{<: Point, <: Point}, model, c, linewidth, linestyle, primitive, idx, N)
    draw_segment(scene, ctx, point[1], model, c, linewidth, linestyle, primitive, 1 + (idx - 1) * 2, N)
    draw_segment(scene, ctx, point[2], model, c, linewidth, linestyle, primitive, (idx - 1) * 2, N)
end

function draw_atomic(::Scene, ::CairoScreen, x)
    @warn "$(typeof(x)) is not supported by cairo right now"
end

struct FaceIterator{Iteration, T, F, ET} <: AbstractVector{ET}
    data::T
    faces::F
end

function (::Type{FaceIterator{Typ}})(data::T, faces::F) where {Typ, T, F}
    FaceIterator{Typ, T, F}(data, faces)
end
function (::Type{FaceIterator{Typ, T, F}})(data::AbstractVector, faces::F) where {Typ, F, T}
    FaceIterator{Typ, T, F, NTuple{3, eltype(data)}}(data, faces)
end
function (::Type{FaceIterator{Typ, T, F}})(data::T, faces::F) where {Typ, T, F}
    FaceIterator{Typ, T, F, NTuple{3, T}}(data, faces)
end
function FaceIterator(data::AbstractVector, faces)
    if length(data) == length(faces)
        FaceIterator{:PerFace}(data, faces)
    else
        FaceIterator{:PerVert}(data, faces)
    end
end

Base.size(fi::FaceIterator) = size(fi.faces)
Base.getindex(fi::FaceIterator{:PerFace}, i::Integer) = fi.data[i]
Base.getindex(fi::FaceIterator{:PerVert}, i::Integer) = fi.data[fi.faces[i]]
Base.getindex(fi::FaceIterator{:Const}, i::Integer) = ntuple(i-> fi.data, 3)

function per_face_colors(color, colormap, colorrange, vertices, faces, uv)
    if color isa Colorant
        return FaceIterator{:Const}(color, faces)
    elseif color isa AbstractArray
        if color isa AbstractVector{<: Colorant}
            return FaceIterator(color, faces)
        elseif color isa AbstractVector{<: Number}
            cvec = AbstractPlotting.interpolated_getindex.((colormap,), color, (colorrange,))
            return FaceIterator(cvec, faces)
        elseif color isa AbstractMatrix{<: Colorant} && uv !== nothing
            cvec = map(uv) do uv
                wsize = reverse(size(color))
                wh = wsize .- 1
                x, y = round.(Int, Tuple(uv) .* wh) .+ 1
                return color[size(color, 1) - (y - 1), x]
            end
            # TODO This is wrong and doesn't actually interpolate
            # Inside the triangle sampling the color image
            return FaceIterator(cvec, faces)
        end
    end
    error("Unsupported Color type: $(typeof(color))")
end

function color2tuple3(c)
    (red(c), green(c), blue(c))
end
function colorant2tuple4(c)
    (red(c), green(c), blue(c), alpha(c))
end

mesh_pattern_set_corner_color(pattern, id, c::Color3) =
    Cairo.mesh_pattern_set_corner_color_rgb(pattern, id, color2tuple3(c)...)
mesh_pattern_set_corner_color(pattern, id, c::Colorant{T,4} where T) =
    Cairo.mesh_pattern_set_corner_color_rgba(pattern, id, colorant2tuple4(c)...)

function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Mesh)
    @get_attribute(primitive, (color,))

    colormap = get(primitive, :colormap, nothing) |> to_value |> to_colormap
    colorrange = get(primitive, :colorrange, nothing) |> to_value

    ctx = screen.context
    model = primitive.model[]
    mesh = primitive[1][]
    vs = vertices(mesh); fs = faces(mesh)
    uv = hastexturecoordinates(mesh) ? texturecoordinates(mesh) : nothing
    pattern = Cairo.CairoPatternMesh()
    cols = per_face_colors(color, colormap, colorrange, vs, fs, uv)
    for (f, (c1, c2, c3)) in zip(fs, cols)
        t1, t2, t3 =  project_position.(scene, vs[f], (model,)) #triangle points
        Cairo.mesh_pattern_begin_patch(pattern)

        Cairo.mesh_pattern_move_to(pattern, t1...)
        Cairo.mesh_pattern_line_to(pattern, t2...)
        Cairo.mesh_pattern_line_to(pattern, t3...)

        mesh_pattern_set_corner_color(pattern, 0, c1)
        mesh_pattern_set_corner_color(pattern, 1, c2)
        mesh_pattern_set_corner_color(pattern, 2, c3)

        Cairo.mesh_pattern_end_patch(pattern)

        Cairo.set_source(ctx, pattern)
        Cairo.close_path(ctx)
        Cairo.paint(ctx)
    end
    nothing
end

function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Union{Lines, LineSegments})
    fields = @get_attribute(primitive, (color, linewidth, linestyle))
    ctx = screen.context
    model = primitive[:model][]
    positions = primitive[1][]
    isempty(positions) && return
    N = length(positions)
    broadcast_foreach(1:N, positions, color, linewidth) do i, point, c, linewidth
        draw_segment(scene, ctx, point, model, c, linewidth, linestyle, primitive, i, N)
    end
    nothing
end

function to_cairo_image(img::AbstractMatrix{<: AbstractFloat}, attributes)
    AbstractPlotting.@get_attribute attributes (colormap, colorrange)
    imui32 = to_uint32_color.(AbstractPlotting.interpolated_getindex.(Ref(colormap), img, (colorrange,)))
    to_cairo_image(imui32, attributes)
end

function to_cairo_image(img::Matrix{UInt32}, attributes)
    CairoARGBSurface([img[j, i] for i in size(img, 2):-1:1, j in 1:size(img, 1)])
end
to_uint32_color(c) = reinterpret(UInt32, convert(ARGB32, c))
function to_cairo_image(img, attributes)
    to_cairo_image(to_uint32_color.(img), attributes)
end

function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Image)
    draw_image(scene, screen, primitive)
end

function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Union{Heatmap, Image})
    draw_image(scene, screen, primitive)
end

function draw_image(scene, screen, attributes)
    ctx = screen.context
    image = attributes[3][]
    x, y = attributes[1][], attributes[2][]
    model = attributes[:model][]
    imsize = (extrema_nan(x), extrema_nan(y))
    xy_ = project_position(scene, Point2f0(first.(imsize)), model)
    xymax_ = project_position(scene, Point2f0(last.(imsize)), model)
    xy = min.(xy_, xymax_)
    xymax = max.(xy_, xymax_)
    w, h = xymax .- xy
    interp = to_value(get(attributes, :interpolate, true))
    interp = interp ? Cairo.FILTER_BEST : Cairo.FILTER_NEAREST
    s = to_cairo_image(image, attributes)
    Cairo.rectangle(ctx, xy..., w, h)
    Cairo.save(ctx)
    Cairo.translate(ctx, xy[1], xy[2])
    Cairo.scale(ctx, w / s.width, h / s.height)
    Cairo.set_source_surface(ctx, s, 0, 0)
    p = Cairo.get_source(ctx)
    # Set filter doesn't work!?
    Cairo.pattern_set_filter(p, interp)
    Cairo.fill(ctx)
    Cairo.restore(ctx)
end
_extract_color(cmap, range, c) = to_color(c)
_extract_color(cmap, range, c::RGBf0) = RGBAf0(c, 1.0)
_extract_color(cmap, range, c::RGBAf0) = c
function _extract_color(cmap, range, c::Number)
    AbstractPlotting.interpolated_getindex(cmap, c, range)
end
function extract_color(cmap, range, c)
    c = _extract_color(cmap, range, c)
    red(c), green(c), blue(c), alpha(c)
end

function draw_marker(ctx, marker, pos, scale, strokecolor, strokewidth)
    pos += Point2f0(scale[1] / 2, -scale[2] / 2)
    Cairo.arc(ctx, pos[1], pos[2], scale[1] / 2, 0, 2*pi)
    Cairo.fill(ctx)
    sc = to_color(strokecolor)
    if strokewidth > 0.0
        Cairo.set_source_rgba(ctx, red(sc), green(sc), blue(sc), alpha(sc))
        Cairo.set_line_width(ctx, Float64(strokewidth))
        Cairo.stroke(ctx)
    end
end

function draw_marker(ctx, marker::Char, pos, scale, strokecolor, strokewidth)
    pos += Point2f0(scale[1] / 2, -scale[2] / 2)

    #TODO this shouldn't be hardcoded, but isn't available in the plot right now
    font = AbstractPlotting.assetpath("DejaVu Sans")
    Cairo.select_font_face(
        ctx, font,
        Cairo.FONT_SLANT_NORMAL,
        Cairo.FONT_WEIGHT_NORMAL
    )
    Cairo.move_to(ctx, pos[1], pos[2])
    mat = scale_matrix(scale...)
    set_font_matrix(ctx, mat)
    Cairo.show_text(ctx, string(marker))
    Cairo.fill(ctx)
end

function draw_marker(ctx, marker::Union{Rect, Type{<: Rect}}, pos, scale, strokecolor, strokewidth)
    s2 = Point2f0(scale[1], -scale[2])
    Cairo.rectangle(ctx, pos..., s2...)
    Cairo.fill(ctx);
    if strokewidth > 0.0
        sc = to_color(strokecolor)
        Cairo.set_source_rgba(ctx, red(sc), green(sc), blue(sc), alpha(sc))
        Cairo.set_line_width(ctx, Float64(strokewidth))
        Cairo.stroke(ctx)
    end
end

function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Scatter)
    fields = @get_attribute(primitive, (color, markersize, strokecolor, strokewidth, marker, marker_offset))
    @get_attribute(primitive, (transform_marker,))

    cmap = get(primitive, :colormap, nothing) |> to_value |> to_colormap
    crange = get(primitive, :colorrange, nothing) |> to_value
    ctx = screen.context
    model = primitive[:model][]
    positions = primitive[1][]
    isempty(positions) && return
    size_model = transform_marker ? model : Mat4f0(I)
    broadcast_foreach(primitive[1][], fields...) do point, c, markersize, strokecolor, strokewidth, marker, mo
        scale = project_scale(scene, markersize, size_model)
        pos = project_position(scene, point, model)
        mo = project_scale(scene, mo, size_model)
        pos += Point2f0(mo[1], -mo[2])
        Cairo.set_source_rgba(ctx, extract_color(cmap, crange, c)...)
        m = convert_attribute(marker, key"marker"(), key"scatter"())
        draw_marker(ctx, m, pos, scale, strokecolor, strokewidth)
    end
    nothing
end

scale_matrix(x, y) = Cairo.CairoMatrix(x, 0.0, 0.0, y, 0.0, 0.0)
function rot_scale_matrix(x, y, q)
    sx, sy, sz = 2q[4]*q[1], 2q[4]*q[2], 2q[4]*q[3]
    xx, xy, xz = 2q[1]^2, 2q[1]*q[2], 2q[1]*q[3]
    yy, yz, zz = 2q[2]^2, 2q[2]*q[3], 2q[3]^2
    m = Cairo.CairoMatrix(
        x, 1 - (xx + zz), yz + sx,
        y, yz - sx, 1 - (xx + yy)
    )
    m
end

function set_font_matrix(cr, matrix)
    ccall((:cairo_set_font_matrix, LIB_CAIRO), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cr.ptr, Ref(matrix))
end

function set_ft_font(cr, font)
    font_face = ccall(
        (:cairo_ft_font_face_create_for_ft_face, LIB_CAIRO),
        Ptr{Cvoid}, (Ptr{Cvoid}, Cint),
        font, 0
    )
    ccall((:cairo_set_font_face, LIB_CAIRO), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cr.ptr, font_face)
end
fontname(x::String) = x
fontname(x::Symbol) = string(x)
function fontname(x::NativeFont)
    ft_rect = unsafe_load(x[1])
    unsafe_string(ft_rect.family_name)
end

function fontscale(atlas, scene, c, font, s)
    s = (s ./ atlas.scale[AbstractPlotting.glyph_index!(atlas, c, font)]) ./ 0.02
    project_scale(scene, s)
end

function to_rel_scale(atlas, c, font, scale)
    gs = atlas.scale[AbstractPlotting.glyph_index!(atlas, c, font)]
    (scale ./ 0.02) ./ gs
end

function calc_position(
        last_pos, start_pos,
        atlas, glyph, font,
        scale, lineheight = 1.5
    )
    advance_x, advance_y = AbstractPlotting.glyph_advance!(atlas, glyph, font, scale)
    if AbstractPlotting.isnewline(glyph)
        return Point2f0(start_pos[1], last_pos[2] - advance_y * lineheight) #reset to startx
    else
        return last_pos + Point2f0(advance_x, 0)
    end
end

function calc_position(glyphs, start_pos, scales, fonts, atlas)
    positions = zeros(Point2f0, length(glyphs))
    last_pos  = Point2f0(start_pos)
    s, f = AbstractPlotting.iter_or_array(scales), AbstractPlotting.iter_or_array(fonts)
    c1 = first(glyphs)
    for (i, (c2, scale, font)) in enumerate(zip(glyphs, s, f))
        c2 == '\r' && continue # stupid windows!
        positions[i] = last_pos
        last_pos = calc_position(last_pos, start_pos, atlas, c2, font, scale)
    end
    positions
end
function layout_text(
        string::AbstractString, startpos::VecTypes{N, T}, textsize::Number,
        font, align, rotation, model
    ) where {N, T}
    offset_vec = to_align(align)
    ft_font = to_font(font)
    rscale = to_textsize(textsize)
    rot = to_rotation(rotation)
    atlas = AbstractPlotting.get_texture_atlas()
    mpos = model * Vec4f0(to_ndim(Vec3f0, startpos, 0f0)..., 1f0)
    pos = AbstractPlotting.to_ndim(Point3f0, mpos, 0)
    scales = Vec2f0[AbstractPlotting.glyph_scale!(atlas, c, ft_font, rscale) for c in string]
    positions2d = calc_position(string, Point2f0(0), rscale, ft_font, atlas)
    aoffset = AbstractPlotting.align_offset(Point2f0(0), positions2d[end], atlas, rscale, ft_font, offset_vec)
    aoffsetn = AbstractPlotting.to_ndim(Point3f0, aoffset, 0f0)
    positions = map(positions2d) do p
        pn = rot * (AbstractPlotting.to_ndim(Point3f0, p, 0f0) .+ aoffsetn)
        pn .+ (pos)
    end
    positions, scales
end

function draw_atomic(scene::Scene, screen::CairoScreen, primitive::Text)
    ctx = screen.context
    @get_attribute(primitive, (textsize, color, font, align, rotation, model))
    txt = to_value(primitive[1])
    position = primitive.attributes[:position][]
    N = length(txt)
    atlas = AbstractPlotting.get_texture_atlas()
    if position isa StaticArrays.StaticArray # one position to place text
        position, textsize = layout_text(
            txt, position, textsize,
            font, align, rotation, model
        )
    end
    broadcast_foreach(1:N, position, textsize, color, font, rotation) do i, p, ts, cc, f, r
        Cairo.save(ctx)
        char = txt[i]
        rels = to_rel_scale(atlas, char, f, ts)
        pos = project_position(scene, p, Mat4f0(I))
        Cairo.move_to(ctx, pos[1], pos[2])
        Cairo.set_source_rgba(ctx, red(cc), green(cc), blue(cc), alpha(cc))
        Cairo.select_font_face(
            ctx, fontname(f),
            Cairo.FONT_SLANT_NORMAL,
            Cairo.FONT_WEIGHT_NORMAL
        )
        #set_ft_font(ctx, f)
        ts = fontscale(atlas, scene, char, f, ts)
        mat = scale_matrix(ts...)
        set_font_matrix(ctx, mat)
        # set_font_size(ctx, 16)
        # TODO this only works in 2d
        Cairo.rotate(ctx, 2acos(r[4]))
        Cairo.show_text(ctx, string(txt[i]))
        Cairo.restore(ctx)
    end
    nothing
end

function cairo_clear(screen::CairoScreen)
    ctx = screen.context
    w, h = Cairo.width(ctx), Cairo.height(ctx)
    Cairo.rectangle(ctx, 0, 0, w, h)
    # FIXME: Cairo.set_source_rgb(ctx, screen.scene.theme[:color]...)
    Cairo.fill(ctx)
end

function draw_background(screen::CairoScreen, scene::Scene)
    cr = screen.context
    Cairo.save(cr)
    if scene.clear[]
        bg = to_color(theme(scene, :backgroundcolor)[])
        Cairo.set_source_rgba(cr, red(bg), green(bg), blue(bg), alpha(bg));    # light gray
        r = pixelarea(scene)[]
        Cairo.rectangle(cr, minimum(r)..., widths(r)...) # background
        fill(cr)
    end
    Cairo.restore(cr)
    foreach(child_scene-> draw_background(screen, child_scene), scene.children)
end

function draw_plot(scene::Scene, screen::CairoScreen, primitive::Combined)
    isempty(primitive.plots) && return draw_atomic(scene, screen, primitive)
    for plot in primitive.plots
        draw_plot(scene, screen, plot)
    end
end

function draw_plot(screen::CairoScreen, scene::Scene)
    Cairo.save(screen.context)
    Cairo.translate(screen.context, minimum(pixelarea(scene)[])...)
    for elem in scene.plots
        draw_plot(scene, screen, elem)
    end
    Cairo.restore(screen.context)
    for child in scene.children
        draw_plot(screen, child)
    end
    return
end

function cairo_draw(screen::CairoScreen, scene::Scene)
    AbstractPlotting.update!(scene)
    draw_background(screen, scene)
    draw_plot(screen, scene)
    return
end

function AbstractPlotting.backend_display(x::CairoBackend, scene::Scene)
    return open(x.path, "w") do io
        AbstractPlotting.backend_show(x, io, to_mime(x), scene)
    end
end

function AbstractPlotting.colorbuffer(screen::CairoScreen)
    # TODO this is super slow, we need to design the colorbuffer
    # api to be able to reuse a RGB surface
    FileIO.save(display_path("png"), screen.scene)
    return FileIO.load(display_path("png"))
end

AbstractPlotting.backend_showable(x::CairoBackend, m::MIME"image/svg+xml", scene::Scene) = x.typ == SVG
AbstractPlotting.backend_showable(x::CairoBackend, m::MIME"image/png", scene::Scene) = x.typ == PNG

function AbstractPlotting.backend_show(x::CairoBackend, io::IO, ::MIME"image/svg+xml", scene::Scene)
    screen = CairoScreen(scene, io)
    cairo_draw(screen, scene)
    Cairo.finish(screen.surface)
    return screen
end

function AbstractPlotting.backend_show(x::CairoBackend, io::IO, m::MIME"image/png", scene::Scene)
    screen = CairoScreen(scene, io)
    cairo_draw(screen, scene)
    Cairo.write_to_png(screen.surface, io)
    return screen
end

function AbstractPlotting.backend_show(x::CairoBackend, io::IO, m::MIME"image/jpeg", scene::Scene)
    screen = nothing
    open(display_path("png"), "w") do fio
        screen = AbstractPlotting.backend_show(x, fio, MIME"image/png"(), scene)
    end
    FileIO.save(FileIO.Stream(format"JPEG", io),  FileIO.load(display_path("png")))
    return screen
end

function __init__()
    activate!()
    AbstractPlotting.register_backend!(AbstractPlotting.current_backend[])
end

function display_path(type::String)
    if !(type in ("svg", "png"))
        error("Only \"svg\" and \"png\" are allowed for `type`. Found: $(type)")
    end
    return joinpath(@__DIR__, "display." * type)
end

function activate!(; inline = true, type = "svg")
    AbstractPlotting.current_backend[] = CairoBackend(display_path(type))
    AbstractPlotting.use_display[] = !inline
    return
end

end


text:
struct Spec
    id
    reward_threshold
    nondeterministic
    max_episode_steps
end