text:
module BobyqaTests

using Printf
using OptimPack.Powell

function runtests()
    # The test function.
    function f(x::DenseVector{Cdouble})
        fx = 0.0
        n = length(x)
        for i in 4:2:n
            for j in 2:2:i-2
                tempa = x[i - 1] - x[j - 1]
                tempb = x[i] - x[j]
                temp = tempa*tempa + tempb*tempb
                temp = max(temp,1e-6)
                fx += 1.0/sqrt(temp)
            end
        end
        return fx
    end

    # Run the tests.
    bdl = -1.0
    bdu =  1.0
    rhobeg = 0.1
    rhoend = 1e-6
    for m in (5,10)
        q = 2.0*pi/m
        n = 2*m
        x = Array{Cdouble}(undef, n)
        xl = Array{Cdouble}(undef, n)
        xu = Array{Cdouble}(undef, n)
        for i in 1:n
            xl[i] = bdl
            xu[i] = bdu
        end
        for jcase in 1:2
            if jcase == 2
                npt = 2*n + 1
            else
                npt = n + 6
            end
            @printf("\n\n     2D output with M =%4ld,  N =%4ld  and  NPT =%4ld\n",
                    m, n, npt)
            for j in 1:m
                temp = q*j
                x[2*j - 1] = cos(temp)
                x[2*j]     = sin(temp)
            end
            fx = bobyqa!(f, x, xl, xu, rhobeg, rhoend, npt=npt,
                         verbose=2, maxeval=500000)[3]
            @printf("\n***** least function value: %.15e\n", fx)
        end
    end
end

end # module


text:
# You're already almost 1.5km (almost a mile) below the surface of the ocean,
# already so deep that you can't see any sunlight. What you can see, however,
# is a giant squid that has attached itself to the outside of your submarine.
#
# Maybe it wants to play bingo?
#
# Bingo is played on a set of boards each consisting of a 5x5 grid of numbers.
# Numbers are chosen at random, and the chosen number is marked on all boards
# on which it appears. (Numbers may not appear on all boards.) If all numbers
# in any row or any column of a board are marked, that board wins. (Diagonals
# don't count.)
#
# The submarine has a bingo subsystem to help passengers (currently, you and
# the giant squid) pass the time. It automatically generates a random order in
# which to draw numbers and a random set of boards (your puzzle input). For
# example:
#
# 7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1
#
# 22 13 17 11  0
#  8  2 23  4 24
# 21  9 14 16  7
#  6 10  3 18  5
#  1 12 20 15 19
#
#  3 15  0  2 22
#  9 18 13 17  5
# 19  8  7 25 23
# 20 11 10 24  4
# 14 21 16 12  6
#
# 14 21 17 24  4
# 10 16 15  9 19
# 18  8 23 26 20
# 22 11 13  6  5
#  2  0 12  3  7
#
# After the first five numbers are drawn (7, 4, 9, 5, and 11), there are no
# winners, but the boards are marked as follows (shown here adjacent to each
# other to save space):
#
# 22 13 17 11  0         3 15  0  2 22        14 21 17 24  4
#  8  2 23  4 24         9 18 13 17  5        10 16 15  9 19
# 21  9 14 16  7        19  8  7 25 23        18  8 23 26 20
#  6 10  3 18  5        20 11 10 24  4        22 11 13  6  5
#  1 12 20 15 19        14 21 16 12  6         2  0 12  3  7
#
# After the next six numbers are drawn (17, 23, 2, 0, 14, and 21), there are
# still no winners:
#
# 22 13 17 11  0         3 15  0  2 22        14 21 17 24  4
#  8  2 23  4 24         9 18 13 17  5        10 16 15  9 19
# 21  9 14 16  7        19  8  7 25 23        18  8 23 26 20
#  6 10  3 18  5        20 11 10 24  4        22 11 13  6  5
#  1 12 20 15 19        14 21 16 12  6         2  0 12  3  7
#
# Finally, 24 is drawn:
#
# 22 13 17 11  0         3 15  0  2 22        14 21 17 24  4
#  8  2 23  4 24         9 18 13 17  5        10 16 15  9 19
# 21  9 14 16  7        19  8  7 25 23        18  8 23 26 20
#  6 10  3 18  5        20 11 10 24  4        22 11 13  6  5
#  1 12 20 15 19        14 21 16 12  6         2  0 12  3  7
#
# At this point, the third board wins because it has at least one complete row
# or column of marked numbers (in this case, the entire top row is marked: 14
# 21 17 24 4).
#
# The score of the winning board can now be calculated. Start by finding the
# sum of all unmarked numbers on that board; in this case, the sum is 188.
# Then, multiply that sum by the number that was just called when the board
# won, 24, to get the final score, 188 * 24 = 4512.
#
# To guarantee victory against the giant squid, figure out which board will win
# first. What will your final score be if you choose that board?

# read input
open("input.txt", "r") do io
  # read numbers
  global numbers = parse.(Int, split(readline(io), ','))

  # read boards
  global boards = []
  while !eof(io)
    # blank line
    readline(io)

    board = Array{Int, 2}(undef, 5, 5)
    @inbounds for x in 1:5
      board[x, :] = parse.(Int, split(strip(readline(io)), r"\s+"))
    end
    push!(boards, board)
  end
end

# `results` keeps track of how many rows have matched, and how many columns
# have matched, per board. When either of those counts reach 5, bingo! We also
# keep track of the sum of matched numbers per board.
numboards = length(boards)
results = zeros(UInt8, numboards, 10)
sums = zeros(Int, numboards)
for num in numbers, b in 1:numboards
  idx = findfirst(isequal(num), boards[b])
  if !isnothing(idx)
    sums[b] += num
    if (results[b, idx[1]] += 1) == 5 || (results[b, idx[2] + 5] += 1) == 5
      unmarkedsum = sum(boards[b])
      println("Bingo!: ", (unmarkedsum - sums[b]) * num)
      break
    end
  end
end

ext: jl


text:
# Tests for libsvm
function t_libsvm()

iris_class = j4pr.DataGenerator.iris()
regression_values = j4pr.ohenc_integer(j4pr.gety(iris_class), unique(j4pr.gety(iris_class)))
iris_reg = j4pr.datacell(j4pr.getx(iris_class), regression_values)

d = Distances.Euclidean()
tol  = 0.2; # tolerance when comparing results

Wclass = [j4pr.libsvm(), j4pr.libsvm(d), 			# LIBSVM.SVC
     j4pr.libsvm(svmtype=LIBSVM.NuSVC), j4pr.libsvm(d, svmtype=LIBSVM.NuSVC),
     j4pr.libsvm(svmtype=LIBSVM.NuSVC), j4pr.libsvm(d, svmtype=LIBSVM.NuSVC),
     j4pr.libsvm(svmtype=LIBSVM.OneClassSVM), j4pr.libsvm(d, svmtype=LIBSVM.OneClassSVM)]

Wreg = [j4pr.libsvm(svmtype=LIBSVM.NuSVR, probability=false),
     j4pr.libsvm(d, svmtype=LIBSVM.NuSVR, probability=false),
     j4pr.libsvm(svmtype=LIBSVM.EpsilonSVR, probability=false),
     j4pr.libsvm(d, svmtype=LIBSVM.EpsilonSVR, probability=false)]

# Test classification
for w in Wclass
	Test.@test try
		wt1 = iris_class |> w
		wt2 = j4pr.strip(iris_class) |> w

		result = iris_class |> wt1
		result2 = iris_class.x |> wt2

		#println("Not matching: ",sum(abs.(result.x - result2) .>= tol) )
		sum(abs.(result.x - result2) .>= tol) > 0 ? false : true
	catch
		false
	end
end

# Test regression
for w in Wreg
	Test.@test try
		wt1 = iris_reg |> w
		wt2 = j4pr.strip(iris_reg) |> w

		result = iris_reg |> wt1
		result2 = iris_reg.x |> wt2
		#println("Not matching: ",sum(abs.(result.x - result2) .>= tol) )
		sum(abs.(result.x - result2) .>= tol) > 0 ? false : true
	catch
		false
	end
end

end


text:
function julia_cmd(cmd)
    return `
        $(Base.julia_cmd())
        --color=$(Base.have_color ? "yes" : "no")
        --compiled-modules=$(Base.JLOptions().use_compiled_modules != 0 ? "yes" : "no")
        --history-file=no
        --startup-file=$(Base.JLOptions().startupfile != 2 ? "yes" : "no")
        --code-coverage=$(["none", "user", "all"][1+Base.JLOptions().code_coverage])
        $cmd
    `
end

macro check_ir(inst, str)
    quote
        @test occursin($(esc(str)), string($(esc(inst))))
    end
end


text:
using Dates
export TimeAnomaly

daymonth(t) = day(t), month(t)

"""
    TimeAnomaly()
Decompose timeseries `s` into a **sum** `x + r` wher `x` is the same-time average and
`r` is the anomalies. Each unique day+month combination in `t` is identified, and the
values of `s` for each year that has this day+month combination are averaged.
As a result, the time vector `t` must be `<:AbstractVector{<:TimeType}`.

This method is very common in climate science, referred to as simply "anomalies".
"""
struct TimeAnomaly end

decompose(t, s, method::TimeAnomaly) = error("`t` must be `<:AbstractVector{<:TimeType}`")

function decompose(t::AbstractVector{<:TimeType}, s, method::TimeAnomaly)
    @assert length(t) == length(s)
    udates = unique!(sort!(daymonth.(t)))
    c = Dict(u => 0 for u in udates)
    v = Dict(u => zero(eltype(s)) for u in udates)
    x = copy(s)
    # First run: calculate climatology averages
    @inbounds for i in 1:length(t)
        date = daymonth(t[i])
        c[date] += 1
        v[date] += s[i]
    end
    # Second run: make x
    for (key, n) in c
        @inbounds v[key] = v[key]/n # take the average
    end
    @inbounds for i in 1:length(t)
        date = daymonth(t[i])
        x[i] = v[date]
    end
    return x, s .- x
end


text:
@init @require FiniteDifferences="26cc04aa-876d-5657-8c51-4c34ba976000" begin
    using .FiniteDifferences

    function FiniteDifferences.to_vec(X::CollapsedDimArray)
        x_vec, back = to_vec(collapseddim(X))
        s = size(parent(X))
        si = X.si
        sj = X.sj
        ob = X.onebatch
        function CollapsedDimArray_from_vec(x_vec)
            return CollapsedDimArray(reshape(back(x_vec), s), si, sj, ob)
        end
        return x_vec, CollapsedDimArray_from_vec
    end
end

@inline function _sumbatch(ca::CollapsedDimArray)
     return CollapsedDimArray(sum(parent(ca), dims=ntuple(i->i-1+ca.sj, ndims(parent(ca))+1-ca.sj)), ca.si, ca.sj, static(true))
end

using ChainRulesCore
using ChainRulesCore: NoTangent, @thunk
import ChainRulesCore: ProjectTo
function ChainRulesCore.rrule(::Type{CollapsedDimArray}, x, dims, si, sj, onebatch)
    s = size(x)
    function CollapsedDimArray_pullback(Ȳ)
        ∂x = @thunk begin
            tmp = unwrap_collapse(unthunk(Ȳ))
            size(tmp) == s ? tmp : reshape(tmp, s)
        end
        return (NoTangent(), ∂x, NoTangent(), NoTangent(), NoTangent(), NoTangent())
    end
    return CollapsedDimArray(x, dims, si, sj, onebatch), CollapsedDimArray_pullback
end

function ChainRulesCore.rrule(::typeof(parent), x::CollapsedDimArray)
    si, sj, ob = x.si, x.sj, x.onebatch
    function collapsed_parent_pullback(Ȳ)
        ∂x = @thunk CollapsedDimArray(unthunk(Ȳ), si, sj, ob)
        return (NoTangent(), ∂x)
    end
    return parent(x), collapsed_parent_pullback
end

function ChainRulesCore.rrule(::typeof(matmul), A::AbstractVecOrMat, B::AbstractVecOrMat, s)
    Y = matmul(A, B, s)
    function matmul_pullback(Ȳ)
        Ȳ = unthunk(Ȳ)
        Athunk = @thunk matmul(Ȳ, B', s)
        Bthunk = @thunk matmul(A', Ȳ, s)
        sthunk = @thunk sum(reshape(Ȳ, :) .* reshape(Y, :)) * inv(s)
        return (NoTangent(), Athunk, Bthunk, sthunk)
    end
    return Y, matmul_pullback
end

function ProjectTo(ca::CollapsedDimArray)
    dims = size(parent(ca))
    return ProjectTo{CollapsedDimArray}(; dims=dims, si = ca.si, sj = ca.sj, onebatch = ca.onebatch)
end

function (project::ProjectTo{CollapsedDimArray})(dx::AbstractArray)
    dx = unwrap_collapse(dx)
    return CollapsedDimArray(reshape(dx, project.dims), project.si, project.sj, project.onebatch)
end

function (project::ProjectTo{AbstractArray})(dx::CollapsedDimArray)
    dx = reshape(unwrap_collapse(dx), project.axes)
    return project(dx)
end

function ChainRulesCore.rrule(::typeof(matmul), A::AbstractArray, B::AbstractArray, s)
    ProjA = ProjectTo(A)
    ProjB = ProjectTo(B)

    transA, pA = trans(A)
    transB, pB = trans(B)
    a = CollapsedDimArray(pA)
    b = CollapsedDimArray(pB)
    Y = matmul_wrapper(transA, transB, s, a, b)

    function matmul_pullback(Ȳ)
        Ȳ = unthunk(Ȳ)
        Â = trans(transA, a)
        B̂ = trans(transB, b)

        Athunk = @thunk begin
            tmp = matmul(Ȳ, batched_adjoint(B̂), s)
            ProjA(isonebatch(Â) ? _sumbatch(tmp) : tmp)
        end
        Bthunk = @thunk begin
            tmp = matmul(batched_adjoint(Â), Ȳ, s)
            ProjB(isonebatch(B̂) ? _sumbatch(tmp) : tmp)
        end
        sthunk = @thunk sum(reshape(Ȳ, :) .* reshape(unwrap_collapse(Y), :)) * inv(s)
        return (NoTangent(), Athunk, Bthunk, sthunk)
    end
    return Y, matmul_pullback
end


text:
const EMPTY    = 0b00000000 % Int8
const MISSING  = 0b10000000 % Int8
const INT      = 0b00000001 % Int8
const FLOAT    = 0b00000010 % Int8
const DATE     = 0b00000100 % Int8
const DATETIME = 0b00001000 % Int8
const BOOL     = 0b00010000 % Int8
const STRING   = 0b00100000 % Int8
const USER     = 0b01111111 % Int8

typecode(::Missing) = MISSING
typecode(::Int64) = INT
typecode(::Float64) = FLOAT
typecode(::Date) = DATE
typecode(::DateTime) = DATETIME
typecode(::Bool) = BOOL
typecode(::String) = STRING
typecode(::Tuple{Ptr{UInt8}, Int}) = STRING
typecode(::Type{Union{}}) = EMPTY
typecode(::Type{Missing}) = MISSING
typecode(x) = USER

const TYPEMAP = Dict(
    EMPTY    => Union{},
    MISSING  => Missing,
    INT      => Int64,
    FLOAT    => Float64,
    DATE     => Date,
    DATETIME => DateTime,
    BOOL     => Bool,
    STRING   => String,
    (INT | MISSING)      => Union{Int64, Missing},
    (FLOAT | MISSING)    => Union{Float64, Missing},
    (DATE | MISSING)     => Union{Date, Missing},
    (DATETIME | MISSING) => Union{DateTime, Missing},
    (BOOL | MISSING)     => Union{Bool, Missing},
    (STRING | MISSING)   => Union{String, Missing},
)

# initialization case
@inline function promote_typecode(T, S)
    if T === EMPTY || T === S
        return S
    elseif T === MISSING || S === MISSING
        return T | S
    elseif T === INT
        return S === FLOAT ? FLOAT : STRING
    elseif T === FLOAT
        return S === INT ? FLOAT : STRING
    elseif T === DATE
        return S === DATETIME ? DATETIME : STRING
    elseif T === DATETIME
        return S === DATE ? DATETIME : STRING
    elseif T === STRING
        return STRING
    else
        return S === STRING ? (STRING | MISSING) : (promote_typecode(T & ~MISSING, S) | MISSING)
    end
end

# providedtypes: Dict{String, Type}, Dict{Int, Type}, Vector{Type}
initialtype(allowmissing) = (allowmissing === :auto || allowmissing === :none) ? Union{} : Missing
initialtypes(T, ::Nothing, names) = Type[T for _ = 1:length(names)]
initialtypes(T, t::Dict{String, V}, names) where {V} = Type[get(t, string(nm), T) for nm in names]
initialtypes(T, t::Dict{Symbol, V}, names) where {V} = Type[get(t, nm, T) for nm in names]
initialtypes(T, t::Dict{Int, V}, names) where {V}    = Type[get(t, i, T) for i = 1:length(names)]

const EMPTY_LEVELS = Dict{String, Int}[]
const EMPTY_POOLS = CategoricalPool{String, UInt32, CatStr}[]
const MAX_ROWS = 10_000

function detect(types, io, positions, parsinglayers, kwargs, typemap, categorical, transpose, ref, debug)
    len = transpose ? ref[] : length(positions)
    cols = length(types)
    typecodes = [typecode(T) for T in types]
    # @show typecodes

    # prep if categorical
    levels = categorical !== false ? Dict{String, Int}[Dict{String, Int}() for _ = 1:cols] : EMPTY_LEVELS

    lastcode = Base.RefValue(Parsers.SUCCESS)
    rows = 0
    if len > MAX_ROWS
        rng = range(1, length=100, stop=len-100)
        step = min(100, trunc(Int64, Float64(rng.step)))
    else
        rng = 1:len
        step = 1
    end
    for startingrow in rng
        for row = trunc(Int64, startingrow):trunc(Int64, startingrow + step - 1)
            rows += 1
            !transpose && seek(io, positions[row])
            lastcode[] = Parsers.SUCCESS
            for col = 1:cols
                if !transpose && newline(lastcode[])
                    typecodes[col] = promote_typecode(typecodes[col], MISSING)
                    continue
                end
                transpose && seek(io, positions[col])
                # if debug
                #     pos = position(io)
                #     result = Parsers.parse(parsinglayers, io, String)
                #     seek(io, pos)
                # end
                @inbounds T = typecodes[col]
                if T === USER
                    detecttype(STRING, io, parsinglayers, kwargs, levels, row, col, categorical, lastcode)
                else
                    S = detecttype(T & ~MISSING, io, parsinglayers, kwargs, levels, row, col, categorical, lastcode)
                    typecodes[col] = promote_typecode(T, S)
                    debug && (T !== typecodes[col]) && println("row: $row, col: $col, '$(result.result)', promoted to: $(TYPEMAP[typecodes[col]])")
                end
                transpose && setindex!(positions, position(io), col)
            end
        end
    end
    debug && println("scanned $rows / $len = $((rows / len) * 100)% of file to infer types")

    pools = categorical !== false ? Vector{CategoricalPool{String, UInt32, CatStr}}(undef, cols) : EMPTY_POOLS
    for (i, T) in enumerate(typecodes)
        if T < USER
            @inbounds S = TYPEMAP[T]
            if (categorical === true || (categorical !== false &&
                    length(levels[i]) / sum(values(levels[i])) < categorical)) && (T & STRING) > 0
                S = T < 0 ? Union{CatStr, Missing} : CatStr
                pools[i] = CategoricalPool{String, UInt32}(collect(keys(levels[i])))
            end
            @inbounds types[i] = get(typemap, S, S)
        end
    end
    return types, pools
end

function incr!(dict::Dict{String, Int}, key::Tuple{Ptr{UInt8}, Int})
    index = Base.ht_keyindex2!(dict, key)
    if index > 0
        @inbounds dict.vals[index] += 1
        return
    else
        kk::String = convert(String, key)
        @inbounds Base._setindex!(dict, 1, kk, -index)
        return
    end
end

@inline function trytype(io, pos, layers, T, kwargs, lastcode)
    seek(io, pos)
    res = Parsers.parse(layers, io, T; kwargs...)
    lastcode[] = res.code
    return Parsers.ok(res.code) ? typecode(res.result) : EMPTY
end

function detecttype(prevT, io, layers, kwargs, levels, row, col, categorical, lastcode)
    pos = position(io)
    if categorical !== false
        result = Parsers.parse(layers, io, Tuple{Ptr{UInt8}, Int})
        Parsers.ok(result.code) || throw(Error(Parsers.Error(io, result), row, col))
        lastcode[] = result.code
        # @debug "res = $result"
        result.result === missing && return MISSING
        # update levels
        incr!(levels[col], result.result::Tuple{Ptr{UInt8}, Int})
    end
    if prevT === EMPTY || prevT === INT
        int = trytype(io, pos, layers, Int64, kwargs, lastcode)
        int !== EMPTY && return int
    end
    if prevT === EMPTY || prevT === INT || prevT === FLOAT
        float = trytype(io, pos, layers, Float64, kwargs, lastcode)
        float !== EMPTY && return float
    end
    if prevT === EMPTY || prevT === DATE || prevT === DATETIME
        if !haskey(kwargs, :dateformat)
            try
                date = trytype(io, pos, layers, Date, kwargs, lastcode)
                date !== EMPTY && return date
            catch e
            end
            try
                datetime = trytype(io, pos, layers, DateTime, kwargs, lastcode)
                datetime !== EMPTY && return datetime
            catch e
            end
        else
            # use user-provided dateformat
            T = timetype(kwargs.dateformat)
            dt = trytype(io, pos, layers, T, kwargs, lastcode)
            dt !== EMPTY && return dt
        end
    end
    if prevT === EMPTY || prevT === BOOL
        bool = trytype(io, pos, layers, Bool, kwargs, lastcode)
        bool !== EMPTY && return bool
    end
    str = trytype(io, pos, layers, Tuple{Ptr{UInt8}, Int}, kwargs, lastcode)
    return str === MISSING ? MISSING : STRING
end

function timetype(df::Dates.DateFormat)
    date = false
    time = false
    for token in df.tokens
        T = typeof(token)
        if T == Dates.DatePart{'H'}
            time = true
        elseif T == Dates.DatePart{'y'} || T == Dates.DatePart{'Y'}
            date = true
        end
    end
    return ifelse(date & time, DateTime, ifelse(time, Time, Date))
end


text:
function demo_steady_deck(cur_T_bar::AbstractSymbol=symbols(:T_bar); cur_kwargs...)
  cur_dict = Dict(
    :deck => :demo_steady,
    :T_bar => cur_T_bar,
    :is_pulsed => false,
    :H => 1.4,
    :Q => 24.46,
    :epsilon => 0.385,
    :kappa_95 => 1.800,
    :delta_95 => 0.333,
    :nu_n => 0.3972,
    :nu_T => 0.9187,
    :Z_eff => 4.708,
    :f_D => 0.7366,
    :A => 2.856,
    :l_i => 0.900,
    :N_G => 1.2,
    :eta_T => 0.5742,
    :eta_RF => 0.5,
    :tau_FT => 1e6,
    :C_ejima => 0.4,
    :max_beta_N => 0.038,
    :max_q_95 => 2.5,
    :max_P_E => 8000.0,
    :max_P_W => 8.0,
    :max_q_DV => 10.0,
    :B_CS => 12.85,
    :sigma_CS => 800,
    :sigma_TF => 800,
    :J_CS => 150,
    :J_TF => 24.7,
    :k => 0.216,
    :eta_CD => 0.4152,
    :wave_theta => 135.0,
    :eta_LH => 0.6,
    :ignored_limits => [:heat, :pcap]
  )

  merge!(cur_dict, Dict(cur_kwargs))

  BaseReactor(cur_dict)
end


text:
"""
`spy(A; nargs...)` → `Plot`

Description
============

Plots the sparsity pattern for the given matrix `A`.
This means that a scatterplot that resembles the matrix is drawn,
in which only the pixel for non-zero elements of the matrix are set.

If the parameters `width` and `height` are not explicitly specified,
then the function will attempt to preserve the aspect ratio of the matrix,
while also attempting to fit the resulting plot withing the bounding box
specified by `maxwidth` and `maxheight`

Usage
======

    spy(A; maxwidth = 70, maxheight = 40, title = "Sparsity Pattern", width = 0, height = 0, border = :solid, margin = 3, padding = 1, color = :automatic, labels = true, canvas = BrailleCanvas)

Arguments
==========

- **`A`** : The matrix of interest, which non-zero elements should be drawn

- **`maxwidth`** : Maximal number of characters per row that should be used for plotting

- **`maxheight`** : Maximal number of rows that should be used for plotting.

- **`title`** : Text to display on the top of the plot.

- **`width`** : Number of characters per row that should be used for plotting. `0` stands for automatic

- **`height`** : Number of rows that should be used for plotting. `0` stands for automatic

- **`border`** : The style of the bounding box of the plot. Supports `:solid`, `:bold`, `:dashed`, `:dotted`, `:ascii`, and `:none`.

- **`margin`** : Number of empty characters to the left of the whole plot.

- **`padding`** : Space of the left and right of the plot between the labels and the canvas.

- **`color`** : Color of the drawing. Can be any of `:blue`, `:red`, `:yellow`

- **`labels`** : Can be used to hide the labels by setting `labels=false`.

- **`canvas`** : The type of canvas that should be used for drawing.

Returns
========

A plot object of type `Plot{T<:Canvas}`

Author(s)
==========

- Dominique (Github: https://github.com/dpo)
- Christof Stocker (Github: https://github.com/Evizero)
- Jake Bolewski (Github: https://github.com/jakebolewski)

Examples
=========

    julia> spy(sprandn(50, 120, .05))

                              Sparsity Pattern
        ┌────────────────────────────────────────────────────────────┐
      1 │⢀⠀⠒⠀⢄⠂⠀⡀⠀⠀⠀⠰⠀⠐⠀⠀⠀⠀⠂⠀⠀⠀⠠⠰⠀⠀⠀⡀⠄⠀⠠⠀⠀⠀⠀⠀⡀⠀⠀⠀⡀⠐⠀⠐⠀⠀⡀⠀⠀⠀⠀⠀⠀⠂⡀⠀⡀⠠⠀⠀│ > 0
        │⠀⠀⠀⠀⠀⢀⢀⠀⠀⠀⠀⠐⠄⠀⢀⠂⠀⠠⠀⠉⠀⠀⠀⠀⢐⠀⠀⠀⠀⠀⠠⠐⠄⠄⠀⠀⠀⠐⠐⠈⢁⠀⠀⠀⠀⠀⠀⠀⠠⠀⠐⡐⠀⠄⠀⠀⠈⠀⠀⠠│ < 0
        │⡀⠀⠀⠀⡀⠊⠀⠀⠀⢀⢀⠀⠄⠀⠂⡠⠂⠐⠐⠀⠀⠄⠀⠀⠀⠄⠀⠀⠀⠀⡀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠠⠀⠂⠀⠠⠀⠀⠀⠆⠄⠈⠀⢀⠀⠀⠀⠐⠄⠀⠀│
        │⠀⠀⠀⠀⠀⠀⠀⢠⠀⢀⠀⠀⠀⢀⠀⠄⠀⠀⠀⠂⠀⠀⠀⠇⠀⢀⠀⠀⠁⠁⠀⠄⠄⠀⠀⠁⠁⠀⡈⠀⠁⠄⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠀⠀⠀⠀│
        │⠀⠀⠀⠀⠀⠀⠀⠀⠀⡐⢀⠀⠀⠀⠐⠂⠁⢀⠠⠀⠀⠀⠀⠀⠁⠀⠀⠀⠠⠀⠀⠀⠀⢀⠀⢄⠀⠀⠀⠐⠀⠀⠈⠀⠀⠐⠀⠄⠂⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
        │⠠⠀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠠⠈⠀⠀⠀⠀⢀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
        │⠐⠀⠉⠐⠀⠀⠁⠀⠀⠀⠀⠀⠀⠌⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠀⠀⠀⠌⠀⠀⠄⠀⠀⡀⠀⠀⠀⠀⠀⢀⠈⠄⠀⡀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀│
        │⠂⠀⠀⠀⠀⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⡨⠀⠠⠀⠀⠀⠂⠀⠀⠀⠀⠀⠀⠈⡠⠀⡀⠀⠀⠁⠀⠁⠠⠀⠀⠀⠀⠀⠀⠀⠄⡀⠀⠄⡠⠀⠀⠀⠀│
        │⠐⠀⠀⠀⠀⠀⠀⠃⠀⠀⠀⠀⠁⠀⡀⠁⠀⢂⠂⠀⠀⠀⠈⠁⠀⠀⠁⠁⠄⠀⠀⠀⠀⠀⡀⠀⠀⠀⠂⠀⠀⠀⠀⠐⠀⠂⠀⠂⠁⠀⠆⠈⠀⠀⠄⠄⠀⠀⠀⠀│
        │⠀⠀⠀⠠⠀⠁⠀⠀⠀⠀⠂⠀⠠⠀⠀⠌⠀⠀⠂⠄⠀⡀⠂⠀⠀⡀⠠⠁⠄⠀⠀⠀⠀⠀⠄⠈⠀⢂⠐⠀⢀⠀⠠⠀⠄⠁⡀⠀⠀⠐⠀⠀⡐⠀⠀⠀⠁⠀⠀⠔│
        │⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠁⠃⡀⡁⠀⠀⠀⢀⠀⠀⠂⠀⠀⠠⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠬⠀⡀│
        │⠐⠀⠀⠀⠀⠀⠀⠀⠢⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠈⠁⠁⠀⠀⠄⠀⠀⠐⠀⠄⠀⠠⠀⠁⡀⠁⠀⠀⠠⠡⠀⠀⠀⠀⠀⠀⠀⠐⠄⠀⠀⠀⠀⡀│
     50 │⠀⠀⠀⠀⠁⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠂⠀⠀⠀⠀⠀⠀⠐⠀⠈⠂⠀⠀⠀⠀⠀⠀⠀⠀⠠⠈⠀⠀⠀⠀⠀⠀⠂⠀⠄⠀⠀⠀⠂⠁⠀⠀⠀⠂⠀│
        └────────────────────────────────────────────────────────────┘
        1                                                          120
                                  nz = 275

See also
=========

`Plot`, `scatterplot`, `BrailleCanvas`, `BlockCanvas`, `DotCanvas`
"""
function spy{T<:Canvas}(
        A::AbstractMatrix;
        maxwidth::Int  = 0,
        maxheight::Int = 0,
        title::AbstractString = "Sparsity Pattern",
        width::Int  = 0,
        height::Int = 0,
        margin::Int  = 3,
        padding::Int = 1,
        color::Symbol = :automatic,
        labels::Bool = true,
        canvas::Type{T} = BrailleCanvas,
        args...)
    rows, cols, vals = findnz(A)
    nrow, ncol = size(A)
    min_canvheight = ceil(Int, nrow / y_pixel_per_char(T))
    min_canvwidth  = ceil(Int, ncol / x_pixel_per_char(T))
    aspect_ratio = min_canvwidth / min_canvheight
    height_diff = 9
    width_diff  = margin + padding + length(string(ncol)) + 6
    min_plotheight = min_canvheight + height_diff
    min_plotwidth  = min_canvwidth  + width_diff

    # if no size bounds ares specified and the session is in an
    # interactive terminal then use the size of the REPL
    if isinteractive()
        term_height, term_width = Base.tty_size()
        maxheight = maxheight > 0 ? maxheight : term_height - height_diff
        maxwidth  = maxwidth > 0 ? maxwidth : term_width - width_diff
    else
        maxheight = maxheight > 0 ? maxheight : 40
        maxwidth  = maxwidth > 0 ? maxwidth : 70
    end

    # Check if the size of the plot should be derived from the matrix
    # Note: if both width and height are 0, it means that there are no
    #       constraints and the plot should resemble the structure of
    #       the matrix as close as possible
    if width == 0 && height == 0
        # If the interactive code did not take care of this then try
        # to plot the matrix in the correct aspect ratio (within specified bounds)
        if min_canvheight > min_canvwidth
            # long matrix (according to pixel density)
            height = min_canvheight
            width  = height * aspect_ratio
            if width > maxwidth
                width  = maxwidth
                height = width / aspect_ratio
            end
            if height > maxheight
                height = maxheight
                width  = min(height * aspect_ratio, maxwidth)
            end
        else
            # wide matrix
            width  = min_canvwidth
            height = width / aspect_ratio
            if height > maxheight
                height = maxheight
                width  = height * aspect_ratio
            end
            if width > maxwidth
                width = maxwidth
                height = min(width / aspect_ratio, maxheight)
            end
        end
    end
    if width == 0 && height > 0
        width  = min(height * aspect_ratio, maxwidth)
    elseif width > 0 && height == 0
        height = min(width / aspect_ratio, maxheight)
    end
    width  = round(Int, width)
    height = round(Int, height)
    can = T(width, height,
            width  = Float64(ncol) + 1,
            height = Float64(nrow) + 1)
    plot = Plot(can;
                labels = labels, title = title,
                margin = margin, padding = padding, args...)
    height = nrows(plot.graphics)
    width = ncols(plot.graphics)
    plot = if color != :automatic
        points!(plot,
                convert(Vector{Float64}, cols),
                nrow + 1 - convert(Vector{Float64}, rows),
                color)
    else
        pos_idx = vals .> 0
        neg_idx = !pos_idx
        pos_cols = cols[pos_idx]
        pos_rows = rows[pos_idx]
        neg_cols = cols[neg_idx]
        neg_rows = rows[neg_idx]
        points!(plot,
                convert(Vector{Float64}, pos_cols),
                nrow + 1 - convert(Vector{Float64}, pos_rows),
                :red)
        points!(plot,
                convert(Vector{AbstractFloat}, neg_cols),
                nrow + 1 - convert(Vector{Float64}, neg_rows),
                :blue)
        annotate!(plot, :r, 1, "> 0", :red)
        annotate!(plot, :r, 2, "< 0", :blue)
    end
    annotate!(plot, :l, 1, "1")
    annotate!(plot, :l, height, string(nrow))
    annotate!(plot, :bl, "1")
    annotate!(plot, :br, string(ncol))
    xlabel!(plot, string("nz = ", length(vals)))
    return plot
end


text:
export chain

function chain(layersNames,layersDims,netType=:regression)
  global order
  L=length(layersNames);T=1;

  orderGraph=rnnOrderGraph(L,T)
  order=topoSort(orderGraph)
  connectGraph=rnnConnectGraph(L,T)

  if netType==:classification
    net=initNet(layersNames,layersDims,:classification)
    connectNet(net,connectGraph,layersDims)
    net[end].Cost=crossEntropy;net[end].∂Cost=∂crossEntropy
  elseif netType==:regression
    net=initNet(layersNames,layersDims,:regression)
    connectNet(net,connectGraph,layersDims)
    net[end-1].A=linear;net[end-1].∂A=∂linear
  end
  return net
end


text:
### A Pluto.jl notebook ###
# v0.15.1

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
        el
    end
end

# ╔═╡ c2274306-49b5-45c0-ae4b-a3b8dc3a3835
begin
	using DECAES
	using Random
	import PlutoUI

	using CairoMakie
	CairoMakie.activate!(type = "png")

	using Makie.Colors
	Makie.set_theme!(resolution=(1600, 900))
end;

# ╔═╡ 9d4a6681-2b40-442f-8cc8-4ae444bc6215
md"""
ETL = $(@bind ETL_slider PlutoUI.Slider(4:32, default=32, show_value=true))

FA = $(@bind flip_angle_slider PlutoUI.Slider(range(50,180,length=100), default=150, show_value=true))

β = $(@bind refcon_slider PlutoUI.Slider(range(50,180,length=100), default=180, show_value=true))

T21 = $(@bind T21_slider PlutoUI.Slider(range(10e-3, 100e-3, length=100), default=30e-3, show_value=true))

T22 = $(@bind T22_slider PlutoUI.Slider(range(100e-3, 250e-3, length=100), default=150e-3, show_value=true))

MWF = $(@bind MWF_slider PlutoUI.NumberField(0.1:0.01:0.4, default=0.20))
"""

# ╔═╡ dfac902d-bb87-4fea-a898-d6792e9b793b
let
	sliders_md = md"""
	base height = $(@bind base_height PlutoUI.NumberField(5:5:5000, default=750))
	base width = $(@bind base_width PlutoUI.NumberField(5:5:5000, default=1610))

	E1 size = $(@bind E1_size PlutoUI.NumberField(0.01:0.01:1.0, default=0.69))
	E1 pos  = $(@bind E1_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=0.23))

	C size = $(@bind C_size PlutoUI.NumberField(0.01:0.01:1.0, default=0.56))
	C pos  = $(@bind C_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=0.41))

	A size = $(@bind A_size PlutoUI.NumberField(0.01:0.01:1.0, default=0.49))
	A pos  = $(@bind A_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=0.59))

	E2 size = $(@bind E2_size PlutoUI.NumberField(0.01:0.01:1.0, default=0.41))
	E2 pos  = $(@bind E2_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=0.75))

	S size = $(@bind S_size PlutoUI.NumberField(0.01:0.01:1.0, default=0.35))
	S pos  = $(@bind S_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=0.87))

	font = $(@bind decaes_font PlutoUI.Select(
		[
			"Dejavu Sans (default)",
			"Courier Mono",
			"Courier Bold",
			"Purisa Bold",
			"FreeMono",
			"Latin Modern Sans Demi Cond",
			"Liberation Mono",
			"Sawasdee Bold",
			"Carlito",
			"Chilanka",
			"Dyuthi",
			"Latin Modern Sans",
		];
		default = "Chilanka",
	))
	"""

	# Print current variables to terminal
	println("""
	base height = \$(@bind base_height PlutoUI.NumberField(5:5:5000, default=$(base_height)))
	base width = \$(@bind base_width PlutoUI.NumberField(5:5:5000, default=$(base_width)))

	E1 size = \$(@bind E1_size PlutoUI.NumberField(0.01:0.01:1.0, default=$(E1_size)))
	E1 pos  = \$(@bind E1_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=$(E1_pos)))

	C size = \$(@bind C_size PlutoUI.NumberField(0.01:0.01:1.0, default=$(C_size)))
	C pos  = \$(@bind C_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=$(C_pos)))

	A size = \$(@bind A_size PlutoUI.NumberField(0.01:0.01:1.0, default=$(A_size)))
	A pos  = \$(@bind A_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=$(A_pos)))

	E2 size = \$(@bind E2_size PlutoUI.NumberField(0.01:0.01:1.0, default=$(E2_size)))
	E2 pos  = \$(@bind E2_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=$(E2_pos)))

	S size = \$(@bind S_size PlutoUI.NumberField(0.01:0.01:1.0, default=$(S_size)))
	S pos  = \$(@bind S_pos  PlutoUI.NumberField(0.01:0.005:1.0, default=$(S_pos)))
	""")

	sliders_md
end

# ╔═╡ 5cf6be3c-fe58-42a8-840e-8a21a5a81584
begin
	# Global variables from sliders
	textsize = base_height .* [1.0, E1_size, C_size, A_size, E2_size, S_size]
	xposition = 20 .+ base_width .* [0, E1_pos, C_pos, A_pos, E2_pos, S_pos]
	yposition = 20 .+ [100, 50, 25, 15, 5, 0]
	textsize .= ceil.(Int, textsize)
	xposition .= ceil.(Int, xposition)
	yposition .= ceil.(Int, yposition)

	# Julia logo colors
	JLcolors = Makie.Colors.JULIA_LOGO_COLORS
end;

# ╔═╡ 15b31eb3-8ddc-4fab-9bda-41cdbe8bc710
function plot_decaes_text!(ax; textsize, xposition, yposition)
	text!(ax,
		["D", "E", "C", "A", "E", "S"],
		position = tuple.(xposition ./ 1600, yposition ./ 900),
		textsize = textsize,
		align = (:left, :baseline),
		font = decaes_font,
	)
end

# ╔═╡ 446a6ee0-b25b-47ef-b4fc-af59f30d27fd
md"""
EPG decay curve
"""

# ╔═╡ 118177e3-2b40-4cea-bba6-ab48ba492fbd
function plot_epg_curve!(ax, echo_times, epg_curve)
	epg_line = lines!(ax, echo_times, epg_curve;
		linewidth = 14,
		color = JLcolors.purple,
	)
	epg_band = band!(
		ax, echo_times, fill(0, length(echo_times)), epg_curve;
		color = (JLcolors.purple, 0.12),
	)
	return epg_line, epg_band
end;

# ╔═╡ 499d8be9-ca07-40c9-9a22-79bb99ed58fa
md"""
Inset T2 distribution figure:
"""

# ╔═╡ f217fde8-08b8-4f33-8149-69f900847bd3
function plot_t2_dist!(ax, t2maps, t2dist)
	ax.backgroundcolor = :white
	hidespines!(ax)
	hidedecorations!(ax)
	logT2 = t2maps["t2times"] .|> log10

	I = findlast(t2maps["t2times"] .<= 50e-3)
	t2_bands = Any[]
	t2_lines = Any[]
	pushinto!(x) = p -> push!(x, p)
	for (inds, color) in [
			(1:I, JLcolors.red),
			(I:length(t2dist), JLcolors.green),
		]
		band!(ax,
			logT2[inds], fill(0.0,length(logT2[inds])), t2dist[inds];
			color = (color, 0.35),
		) |> pushinto!(t2_bands)
		lines!(ax, logT2[inds], t2dist[inds],
			linewidth = 14, color = color,
		) |> pushinto!(t2_lines)
	end

	return t2_bands, t2_lines
end;

# ╔═╡ 0e7420c8-bfd6-4c91-a7bd-6c205eb24452
md"""
Compute EPG decay curve + corresponding T2 distribution:
"""

# ╔═╡ 02d229c2-e2c0-4a36-bc6a-163778be85b9
function epg_decay_curve(ETL, α, TE, T21, T22, T1, β, MWF, SNR)
	x = (0:ETL-1)./(ETL-1)
	y =    MWF  .* DECAES.EPGdecaycurve(ETL, α, TE, T21, T1, β) .+
		(1-MWF) .* DECAES.EPGdecaycurve(ETL, α, TE, T22, T1, β)
	y .*= 0.995 / maximum(y)
	y = Vector{Float64}(y)

	noise(snr, seed) = 10^(-snr/20) .* randn(MersenneTwister(seed), size(y))
	y .= sqrt.((y .+ noise(SNR, 0)).^2 .+ noise(SNR, 1).^2)

	return x, y
end;

# ╔═╡ db1d1148-7bf7-4a1d-b568-52b55a8ec1f3
function t2_distribution(y::AbstractVector, nT2, TE, T2Range, Reg)
	t2maps, t2dist = T2mapSEcorr(
		reshape(y, 1, 1, 1, :);
		nT2, TE, T2Range, Reg, Silent = true,
	)
	t2dist ./= maximum(t2dist)
	return t2maps, t2dist
end;

# ╔═╡ 7cd9afdf-6675-4416-aec7-9eba65eafbe2
function decaes_logo(;
		T1, TE, SNR, nT2, T2Range, Reg, ETL, α, β, T21, T22, MWF,
		save_figs = false,
	)
	fig = Figure(
		resolution = (1600, 900),
	)

	ax = Axis(
		fig[1, 1],
		aspect = 16/9,
		grid = false,
		ticks = false,
		backgroundcolor = :white,
	)
	xlims!(ax, 0, 1)
	ylims!(ax, 0, 1.0)
	hidespines!(ax)
	# hidespines!(ax, :t, :r) # only top and right
	hidedecorations!(ax)

	# DECAES text
	txt = plot_decaes_text!(ax; textsize, xposition, yposition)

	# Plot EPG decay curve
	echo_times, epg_curve = epg_decay_curve(
		ETL, α, TE, T21, T22, T1, β, MWF, SNR
	)
	epg_line, epg_band = plot_epg_curve!(ax, echo_times, epg_curve)

	# Inset T2 distbn
	ax_sub = Axis(fig, bbox = BBox(800, 1600, 450, 900))
	t2maps, t2dist = t2_distribution(epg_curve, nT2, TE, T2Range, Reg)
	t2_bands, t2_lines = plot_t2_dist!(ax_sub, t2maps, t2dist)

	# Save figures
	if save_figs
		save("logo.png", fig)
		save("logo.svg", fig)
	end

	(; fig, ax, ax_sub, txt, epg_line, epg_band, t2_bands, t2_lines)
end;

# ╔═╡ e55b552a-00a1-44d3-9d0b-dda4ceac1f59
let
	fig, = decaes_logo(;
		# DECAES settings
		T1 = 1.0,
		TE = 10e-3,
		SNR = 60,
		nT2 = 80,
		T2Range = (10e-3, 1.0),
		Reg = "lcurve",

		# Global variables from sliders
		ETL = ETL_slider,
		α = flip_angle_slider,
		β = refcon_slider,
		T21 = T21_slider,
		T22 = T22_slider,
		MWF = MWF_slider,

		save_figs = true,
	)

	fig
end

# ╔═╡ 1b62140b-f949-4470-a150-902c4811eb9b
#=
let
    # animation settings
    nframes = 45
    framerate = 30

	# DECAES settings
	T1 = 1.0
	TE = 10e-3
	SNR = 60
	nT2 = 80
	T2Range = (10e-3, 1.0)
	Reg = "lcurve"

    T22_iterator = cos_range(150e-3, 300e-3; length = nframes, phase = pi/2)
    FA_iterator = cos_range(150, 175; length = nframes, phase = pi)
	tsize_iterator = [
		# # Periodic grow/shrink
		# cos_range(0.950, 1.050; length = nframes, phase = pi/2);

		# Heartbeat
		smooth_bump(1.0, 1.075; width = 0.95, length = 10);
		smooth_bump(1.0, 0.975; width = 0.95, length = 5);
		smooth_bump(1.0, 1.050; width = 0.95, length = 10);
		smooth_bump(1.0, 1.000; width = 0.95, length = 20);
	]
	anim_iterator = Iterators.zip(T22_iterator, FA_iterator, tsize_iterator)

    ETL = ETL_slider
    β = refcon_slider
    T21 = T21_slider
    MWF = MWF_slider

    fig, ax, ax_sub, txt, epg_line, epg_band, t2_bands, t2_lines = decaes_logo(;
        # Global variables
        T1, TE, SNR, nT2, T2Range, Reg,

        # Local variables
        ETL, β, T21, MWF,

        # Variables for gif
        T22 = T22_iterator[1],
		α = FA_iterator[1],
    )

    record(fig, "logo.gif", anim_iterator; framerate = framerate) do (T22, α, tsize)
		# Delete current subplots
		delete!(ax, txt)
        delete!(ax, epg_line)
        delete!(ax, epg_band)
        delete!.(ax_sub, t2_lines)
        delete!.(ax_sub, t2_bands)

        # Replace subplots with updated curves
		txt = plot_decaes_text!(
			ax; textsize = tsize .* textsize, xposition, yposition)
        echo_times, epg_curve = epg_decay_curve(
			ETL, α, TE, T21, T22, T1, β, MWF, SNR)
        epg_line, epg_band = plot_epg_curve!(ax, echo_times, epg_curve)

        t2maps, t2dist = t2_distribution(epg_curve, nT2, TE, T2Range, Reg)
        t2_lines, t2_bands = plot_t2_dist!(ax_sub, t2maps, t2dist)
    end

    PlutoUI.LocalResource("logo.gif")
end
=#

# ╔═╡ 801045fa-d596-485e-84f6-f5c74629cb2d
function cos_range(lo, hi; length, phase)
	θ = range(0, 2π; length) .- phase
	x = (lo+hi)/2 .+ (hi-lo)/2 .* cos.(θ)
	return x
end;

# ╔═╡ 2fc8ef73-b5c2-455a-a1a1-f85cf45fc4ca
function smooth_bump(lo, hi; width = 1, length)
	ϵ = sqrt(eps())
	u = range(-1, 1; length)
	x = @. lo + (hi - lo) * exp(-1 / (1 - clamp(u/width, -1+ϵ, 1-ϵ)^2))
	return x
end;

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
DECAES = "d84fb938-a666-558e-89d9-d531edc6724f"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[compat]
CairoMakie = "~0.6.2"
DECAES = "~0.4.0"
Makie = "~0.14.2"
PlutoUI = "~0.7.9"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[Animations]]
deps = ["Colors"]
git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d"
uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340"
version = "0.4.1"

[[ArgParse]]
deps = ["Logging", "TextWrap"]
git-tree-sha1 = "3102bce13da501c9104df33549f511cd25264d7d"
uuid = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
version = "1.1.4"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[ArrayInterface]]
deps = ["IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "045ff5e1bc8c6fb1ecb28694abba0a0d55b5f4f5"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.1.17"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "a4d07a1c313392a77042855df46c5f534076fab9"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.0"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Statistics", "UUIDs"]
git-tree-sha1 = "ffabdf5297c9038973a0a3724132aa269f38c448"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.1.0"

[[Blosc]]
deps = ["Blosc_jll"]
git-tree-sha1 = "84cf7d0f8fd46ca6f1b3e0305b4b4a37afe50fd6"
uuid = "a74b3585-a348-5f62-a45c-50e91977d574"
version = "0.7.0"

[[Blosc_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Lz4_jll", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "e747dac84f39c62aff6956651ec359686490134e"
uuid = "0b7ba130-8d10-5ba8-a3d6-c5182647fed9"
version = "1.21.0+0"

[[BufferedStreams]]
deps = ["Compat", "Test"]
git-tree-sha1 = "5d55b9486590fdda5905c275bb21ce1f0754020f"
uuid = "e1450e63-4bb3-523b-b2a4-4ffa8c0fd77d"
version = "1.0.0"

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

[[Cairo]]
deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"]
git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b"
uuid = "159f3aea-2a34-519c-b102-8c37f9878175"
version = "1.0.5"

[[CairoMakie]]
deps = ["Base64", "Cairo", "Colors", "FFTW", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "SHA", "StaticArrays"]
git-tree-sha1 = "68628add03c2c7c2235834902aad96876f07756a"
uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
version = "0.6.2"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "dcc25ff085cf548bc8befad5ce048391a7c07d40"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "0.10.11"

[[CodecBzip2]]
deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"]
git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7"
uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd"
version = "0.7.2"

[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"

[[ColorBrewer]]
deps = ["Colors", "JSON", "Test"]
git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4"
uuid = "a2cac450-b92f-5266-8821-25eda20663c8"
version = "0.4.0"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random", "StaticArrays"]
git-tree-sha1 = "ed268efe58512df8c7e224d2e170afd76dd6a417"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.13.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"]
git-tree-sha1 = "42a9b08d3f2f951c9b283ea427d96ed9f1f30343"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.9.5"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "dc7dedc2c2aa9faf59a55c622760a25cbefbe941"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.31.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[DECAES]]
deps = ["ArgParse", "Dierckx", "DocStringExtensions", "LightXML", "LinearAlgebra", "Logging", "LoggingExtras", "MAT", "NIfTI", "NLopt", "Parameters", "PolynomialRoots", "ProgressMeter", "Random", "SIMD", "SpecialFunctions", "StaticArrays", "Statistics", "TimerOutputs", "UnsafeArrays"]
git-tree-sha1 = "dceb9f969bd37e56bf889c151fb2a128ec91418f"
uuid = "d84fb938-a666-558e-89d9-d531edc6724f"
version = "0.4.0"

[[DataAPI]]
git-tree-sha1 = "ee400abb2298bd13bfc3df1c412ed228061a2385"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.7.0"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "4437b64df1e0adccc3e5d1adbc3ac741095e4677"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.9"

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[Dierckx]]
deps = ["Dierckx_jll"]
git-tree-sha1 = "5fefbe52e9a6e55b8f87cb89352d469bd3a3a090"
uuid = "39dd38d3-220a-591b-8e3c-4c3a8c710a94"
version = "0.5.1"

[[Dierckx_jll]]
deps = ["CompilerSupportLibraries_jll", "Libdl", "Pkg"]
git-tree-sha1 = "a580560f526f6fc6973e8bad2b036514a4e3b013"
uuid = "cd4c43a9-7502-52ba-aa6d-59fb2a88580b"
version = "0.0.1+0"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[Distributions]]
deps = ["FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns"]
git-tree-sha1 = "d5fa76fdab7bf54615262bd639e8c2e9bf295444"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.10"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "92d8f9f208637e8d2d28c664051a00569c01493d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.1.5+1"

[[EllipsisNotation]]
deps = ["ArrayInterface"]
git-tree-sha1 = "8041575f021cba5a099a456b4163c9a08b566a02"
uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"
version = "1.1.0"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[ExprTools]]
git-tree-sha1 = "b7e3d17636b348f005f11040025ae8c6f645fe92"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
version = "0.1.6"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
git-tree-sha1 = "f985af3b9f4e278b1d24434cbb546d6092fca661"
uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
version = "1.4.3"

[[FFTW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3676abafff7e4ff07bbd2c42b3d8201f31653dcc"
uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
version = "3.3.9+8"

[[FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "256d8e6188f3f1ebfa1a5d17e072a0efafa8c5bf"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.10.1"

[[FillArrays]]
deps = ["LinearAlgebra", "Random", "SparseArrays"]
git-tree-sha1 = "25b9cc23ba3303de0ad2eac03f840de9104c9253"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "0.12.0"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.93+0"

[[Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[FreeType]]
deps = ["CEnum", "FreeType2_jll"]
git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4"
uuid = "b38be410-82b0-50bf-ab77-7b57e271db43"
version = "4.0.0"

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

[[FreeTypeAbstraction]]
deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics", "StaticArrays"]
git-tree-sha1 = "d51e69f0a2f8a3842bca4183b700cf3d9acce626"
uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
version = "0.9.1"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "4136b8a5668341e58398bb472754bff4ba0456ff"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.3.12"

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "47ce50b742921377301e15005c96e979574e130b"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.1+0"

[[Graphics]]
deps = ["Colors", "LinearAlgebra", "NaNMath"]
git-tree-sha1 = "2c1cf4df419938ece72de17f368a021ee162762e"
uuid = "a2bd30eb-e257-5431-a919-1863eab51364"
version = "1.1.0"

[[Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

[[GridLayoutBase]]
deps = ["GeometryBasics", "InteractiveUtils", "Match", "Observables"]
git-tree-sha1 = "97b481deb387775da2ca751cc542610750bcdfc3"
uuid = "3955a311-db13-416c-9275-1d80ed98e5e9"
version = "0.5.6"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HDF5]]
deps = ["Blosc", "Compat", "HDF5_jll", "Libdl", "Mmap", "Random", "Requires"]
git-tree-sha1 = "1d18a48a037b14052ca462ea9d05dee3ac607d23"
uuid = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
version = "0.15.5"

[[HDF5_jll]]
deps = ["Artifacts", "JLLWrappers", "LibCURL_jll", "Libdl", "OpenSSL_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "fd83fa0bde42e01952757f01149dd968c06c4dba"
uuid = "0234f1f7-429e-5d53-9886-15a909be8d59"
version = "1.12.0+1"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "c6a1fff2fd4b1da29d3dccaffb1e1001244d844e"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.12"

[[HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "8a954fed8ac097d5be04921d595f741115c1b2ad"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+0"

[[IfElse]]
git-tree-sha1 = "28e837ff3e7a6c3cdb252ce49fb412c8eb3caeef"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.0"

[[ImageCore]]
deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"]
git-tree-sha1 = "75f7fea2b3601b58f24ee83617b528e57160cbfd"
uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534"
version = "0.9.1"

[[ImageIO]]
deps = ["FileIO", "Netpbm", "PNGFiles", "TiffImages", "UUIDs"]
git-tree-sha1 = "d067570b4d4870a942b19d9ceacaea4fb39b69a1"
uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
version = "0.5.6"

[[IndirectArrays]]
git-tree-sha1 = "c2a145a145dc03a7620af1444e0264ef907bd44f"
uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
version = "0.5.1"

[[Inflate]]
git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c"
uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
version = "0.1.2"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[IntelOpenMP_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c"
uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0"
version = "2018.0.3+2"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[Interpolations]]
deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
git-tree-sha1 = "1470c80592cf1f0a35566ee5e93c5f8221ebc33a"
uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
version = "0.13.3"

[[IntervalSets]]
deps = ["Dates", "EllipsisNotation", "Statistics"]
git-tree-sha1 = "3cc368af3f110a767ac786560045dceddfc16758"
uuid = "8197267c-284f-5f27-9208-e0e47529a953"
version = "0.5.3"

[[Isoband]]
deps = ["isoband_jll"]
git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137"
uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4"
version = "0.1.1"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.1"

[[JSONSchema]]
deps = ["HTTP", "JSON", "ZipFile"]
git-tree-sha1 = "b84ab8139afde82c7c65ba2b792fe12e01dd7307"
uuid = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
version = "0.3.3"

[[KernelDensity]]
deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"]
git-tree-sha1 = "591e8dc09ad18386189610acafb970032c519707"
uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b"
version = "0.6.3"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[LightXML]]
deps = ["Libdl", "XML2_jll"]
git-tree-sha1 = "e129d9391168c677cd4800f5c0abb1ed8cb3794f"
uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179"
version = "0.9.0"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["DocStringExtensions", "LinearAlgebra"]
git-tree-sha1 = "7bd5f6565d80b6bf753738d2bc40a5dfea072070"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.2.5"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[LoggingExtras]]
deps = ["Dates", "Logging"]
git-tree-sha1 = "dfeda1c1130990428720de0024d4516b1902ce98"
uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36"
version = "0.4.7"

[[Lz4_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "5d494bc6e85c4c9b626ee0cab05daa4085486ab1"
uuid = "5ced341a-0733-55b8-9ab6-a4889d929147"
version = "1.9.3+0"

[[MAT]]
deps = ["BufferedStreams", "CodecZlib", "HDF5", "SparseArrays"]
git-tree-sha1 = "5c62992f3d46b8dce69bdd234279bb5a369db7d5"
uuid = "23992714-dd62-5051-b70f-ba57cb901cac"
version = "0.10.1"

[[MKL_jll]]
deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"]
git-tree-sha1 = "c253236b0ed414624b083e6b72bfe891fbd2c7af"
uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7"
version = "2021.1.1+1"

[[Makie]]
deps = ["Animations", "Artifacts", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "IntervalSets", "Isoband", "KernelDensity", "LinearAlgebra", "MakieCore", "Markdown", "Match", "Observables", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "Serialization", "Showoff", "SignedDistanceFields", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "UnicodeFun"]
git-tree-sha1 = "82f9d9de6892e5470372720d23913d14a08991fd"
uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
version = "0.14.2"

[[MakieCore]]
deps = ["Observables"]
git-tree-sha1 = "7bcc8323fb37523a6a51ade2234eee27a11114c8"
uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b"
version = "0.1.3"

[[MappedArrays]]
deps = ["FixedPointNumbers"]
git-tree-sha1 = "b92bd220c95a8bbe89af28f11201fd080e0e3fe7"
uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
version = "0.3.0"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[Match]]
git-tree-sha1 = "5cf525d97caf86d29307150fcba763a64eaa9cbe"
uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
version = "1.1.0"

[[MathOptInterface]]
deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"]
git-tree-sha1 = "575644e3c05b258250bb599e57cf73bbf1062901"
uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
version = "0.9.22"

[[MathProgBase]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c"
uuid = "fdba3010-5040-5b88-9595-932c9decdf73"
version = "0.7.8"

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "4ea90bd5d3985ae1f9a908bd4500ae88921c5ce7"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.0"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MosaicViews]]
deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"]
git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d"
uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
version = "0.3.3"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[MutableArithmetics]]
deps = ["LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "3927848ccebcc165952dc0d9ac9aa274a87bfe01"
uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
version = "0.2.20"

[[NIfTI]]
deps = ["Base64", "CodecZlib", "MappedArrays", "Mmap", "TranscodingStreams"]
git-tree-sha1 = "ab2dbb0dacaed807bc2b8c6f40c8dfec67a225ef"
uuid = "a3a9e032-41b5-5fc4-967a-a6b7a19844d3"
version = "0.5.6"

[[NLopt]]
deps = ["MathOptInterface", "MathProgBase", "NLopt_jll"]
git-tree-sha1 = "e7b4c6b8e10b8d1238112a21f5cc001138989dc7"
uuid = "76087f3c-5699-56af-9a33-bf431cd00edd"
version = "0.6.2"

[[NLopt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "2b597c46900f5f811bec31f0dcc88b45744a2a09"
uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778"
version = "2.7.0+0"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[Netpbm]]
deps = ["FileIO", "ImageCore"]
git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.2"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[Observables]]
git-tree-sha1 = "fe29afdef3d0c4a8286128d4e45cc50621b1e43d"
uuid = "510215fc-4207-5dde-b226-833fc4488ee2"
version = "0.4.0"

[[OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "2bf78c5fd7fa56d2bbf1efbadd45c1b8789e6f57"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.2"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[PDMats]]
deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
git-tree-sha1 = "4dd403333bcf0909341cfe57ec115152f937d7d8"
uuid = "90014a1f-27ba-587c-ab20-58faa44d9150"
version = "0.11.1"

[[PNGFiles]]
deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"]
git-tree-sha1 = "520e28d4026d16dcf7b8c8140a3041f0e20a9ca8"
uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
version = "0.3.7"

[[Packing]]
deps = ["GeometryBasics"]
git-tree-sha1 = "f4049d379326c2c7aa875c702ad19346ecb2b004"
uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566"
version = "0.4.1"

[[PaddedViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "0fa5e78929aebc3f6b56e1a88cf505bb00a354c4"
uuid = "5432bcbf-9aad-5242-b902-cca2824c8663"
version = "0.5.8"

[[Pango_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9bc1871464b12ed19297fbc56c4fb4ba84988b0d"
uuid = "36c8627f-9965-5494-a995-c6b170f724f3"
version = "1.47.0+0"

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "2276ac65f1e236e0a6ea70baff3f62ad4c625345"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.2"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "c8abc88faa3f7a3950832ac5d6e690881590d6dc"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "1.1.0"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PkgVersion]]
deps = ["Pkg"]
git-tree-sha1 = "a7a7e1a88853564e551e4eba8650f8c38df79b37"
uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688"
version = "0.1.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "501c20a63a34ac1d015d5304da0e645f42d91c9f"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.11"

[[PlutoUI]]
deps = ["Base64", "Dates", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "Suppressor"]
git-tree-sha1 = "44e225d5837e2a2345e69a1d1e01ac2443ff9fcb"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.9"

[[PolygonOps]]
git-tree-sha1 = "c031d2332c9a8e1c90eca239385815dc271abb22"
uuid = "647866c9-e3ac-4575-94e7-e3d426903924"
version = "0.1.1"

[[PolynomialRoots]]
git-tree-sha1 = "5f807b5345093487f733e520a1b7395ee9324825"
uuid = "3a141323-8675-5d76-9d11-e1df1406c778"
version = "1.0.0"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[ProgressMeter]]
deps = ["Distributed", "Printf"]
git-tree-sha1 = "afadeba63d90ff223a6a48d2009434ecee2ec9e8"
uuid = "92933f4c-e287-5a05-a399-4b506db050ca"
version = "1.7.1"

[[QuadGK]]
deps = ["DataStructures", "LinearAlgebra"]
git-tree-sha1 = "12fbe86da16df6679be7521dfb39fbc861e1dc7b"
uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
version = "2.4.1"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[Ratios]]
git-tree-sha1 = "37d210f612d70f3f7d57d488cb3b6eff56ad4e41"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.0"

[[Reexport]]
git-tree-sha1 = "5f6c21241f0f655da3952fd60aa18477cf96c220"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.1.0"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Rmath]]
deps = ["Random", "Rmath_jll"]
git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f"
uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa"
version = "0.7.0"

[[Rmath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7"
uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f"
version = "0.3.0+0"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[SIMD]]
git-tree-sha1 = "9ba33637b24341aba594a2783a502760aa0bff04"
uuid = "fdea26ae-647d-5447-a871-4b548cad5224"
version = "3.3.1"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[SignedDistanceFields]]
deps = ["Random", "Statistics", "Test"]
git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9"
uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96"
version = "0.4.0"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "LogExpFunctions", "OpenSpecFun_jll"]
git-tree-sha1 = "a50550fa3164a8c46747e62063b4d774ac1bcf49"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.5.1"

[[StackViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c"
uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
version = "0.1.1"

[[Static]]
deps = ["IfElse"]
git-tree-sha1 = "2740ea27b66a41f9d213561a04573da5d3823d4b"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.2.5"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "a43a7b58a6e7dc933b2fa2e0ca653ccf8bb8fd0e"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.6"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "2f6792d523d7448bbe2fec99eca9218f06cc746d"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.8"

[[StatsFuns]]
deps = ["LogExpFunctions", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "30cd8c360c54081f806b1ee14d2eecbef3c04c49"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "0.9.8"

[[StructArrays]]
deps = ["Adapt", "DataAPI", "Tables"]
git-tree-sha1 = "44b3afd37b17422a62aea25f04c1f7e09ce6b07f"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.5.1"

[[SuiteSparse]]
deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"

[[Suppressor]]
git-tree-sha1 = "a819d77f31f83e5792a76081eee1ea6342ab8787"
uuid = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
version = "0.2.0"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "8ed4a3ea724dac32670b062be3ef1c1de6773ae8"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.4.4"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[TensorCore]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
version = "0.1.1"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[TextWrap]]
git-tree-sha1 = "9250ef9b01b66667380cf3275b3f7488d0e25faf"
uuid = "b718987f-49a8-5099-9789-dcd902bef87d"
version = "1.0.1"

[[TiffImages]]
deps = ["ColorTypes", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "OffsetArrays", "OrderedCollections", "PkgVersion", "ProgressMeter"]
git-tree-sha1 = "03fb246ac6e6b7cb7abac3b3302447d55b43270e"
uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69"
version = "0.4.1"

[[TimerOutputs]]
deps = ["ExprTools", "Printf"]
git-tree-sha1 = "209a8326c4f955e2442c07b56029e88bb48299c7"
uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
version = "0.5.12"

[[TranscodingStreams]]
deps = ["Random", "Test"]
git-tree-sha1 = "7c53c35547de1c5b9d46a4797cf6d8253807108c"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.5"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[UnicodeFun]]
deps = ["REPL"]
git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
version = "0.4.1"

[[UnsafeArrays]]
git-tree-sha1 = "be71ca7d62a9d61ecaa20e2d0e1920b791623626"
uuid = "c4a57d5a-5b31-53a6-b365-19f8c011fbd6"
version = "1.0.2"

[[WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.3"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[ZipFile]]
deps = ["Libdl", "Printf", "Zlib_jll"]
git-tree-sha1 = "c3a5637e27e914a7a445b8d0ad063d701931e9f7"
uuid = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea"
version = "0.9.3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[isoband_jll]]
deps = ["Libdl", "Pkg"]
git-tree-sha1 = "a1ac99674715995a536bbce674b068ec1b7d893d"
uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4"
version = "0.2.2+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"
"""

# ╔═╡ Cell order:
# ╠═c2274306-49b5-45c0-ae4b-a3b8dc3a3835
# ╠═5cf6be3c-fe58-42a8-840e-8a21a5a81584
# ╟─9d4a6681-2b40-442f-8cc8-4ae444bc6215
# ╟─dfac902d-bb87-4fea-a898-d6792e9b793b
# ╠═e55b552a-00a1-44d3-9d0b-dda4ceac1f59
# ╠═7cd9afdf-6675-4416-aec7-9eba65eafbe2
# ╠═15b31eb3-8ddc-4fab-9bda-41cdbe8bc710
# ╟─446a6ee0-b25b-47ef-b4fc-af59f30d27fd
# ╠═118177e3-2b40-4cea-bba6-ab48ba492fbd
# ╟─499d8be9-ca07-40c9-9a22-79bb99ed58fa
# ╠═f217fde8-08b8-4f33-8149-69f900847bd3
# ╟─0e7420c8-bfd6-4c91-a7bd-6c205eb24452
# ╠═02d229c2-e2c0-4a36-bc6a-163778be85b9
# ╠═db1d1148-7bf7-4a1d-b568-52b55a8ec1f3
# ╠═1b62140b-f949-4470-a150-902c4811eb9b
# ╠═801045fa-d596-485e-84f6-f5c74629cb2d
# ╠═2fc8ef73-b5c2-455a-a1a1-f85cf45fc4ca
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
# ---
# title: 654. Maximum Binary Tree
# id: problem654
# author: Tian Jun
# date: 2020-10-31
# difficulty: Medium
# categories: Tree
# link: <https://leetcode.com/problems/maximum-binary-tree/description/>
# hidden: true
# ---
#
# Given an integer array with no duplicates. A maximum tree building on this
# array is defined as follow:
#
#   1. The root is the maximum number in the array.
#   2. The left subtree is the maximum tree constructed from left part subarray divided by the maximum number.
#   3. The right subtree is the maximum tree constructed from right part subarray divided by the maximum number.
#
# Construct the maximum tree by the given array and output the root node of this
# tree.
#
# **Example 1:**
#
#
#
#     Input: [3,2,1,6,0,5]
#     Output: return the tree root node representing the following tree:
#
#           6
#         /   \
#        3     5
#         \    /
#          2  0
#            \
#             1
#
#
# **Note:**
#
#   1. The size of the given array will be in the range [1,1000].
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


text:
using MultilinearOpt
using JuMP
using LinearAlgebra
using Test

using Gurobi

include("isconvex.jl")
include("constraint_violation.jl")
include("adhya1.jl")
# include("pooling_infra.jl") # requires unavailable csv file
include("pooling.jl")


text:
using DecisionTrees
using DelimitedFiles
using Test

file = joinpath(dirname(pathof(DecisionTrees)), "..", "test/data/car.data")
cars = readdlm(file, ',')
header = ["buying", "maint", "doors", "persons", "lug_boot", "safety", "class"]

@testset "data" begin
    @test size(cars, 1) == 1728
    @test size(cars, 2) == length(header) == 7
end

include("algorithms.jl")
include("measures.jl")
include("node.jl")


text:
;(import Pkg)
;((. Pkg add) (PackageSpec (kw path "https://github.com/BenLauwens/ThinkJulia.jl")))

(using ThinkJulia)

(function (koch t x)
  (function (recur) (koch t (/ x 3)))
  (if (< x 3)
    (forward t x)
    (begin (recur)
           (turn t -60)
           (recur)
           (turn t 120)
           (recur)
           (turn t -60)
           (recur))))

(function (snowflake t x)
  (koch t x)
  (turn t 120)
  (koch t x)
  (turn t 120)
  (koch t x))

(= t (Turtle))
(@svg (snowflake t 300))


text:
type BSONObject
    _wrap_::Ptr{Void}
    _owner_::Any

    BSONObject() = begin
        _wrap_ = ccall(
            (:bson_new, libbson),
            Ptr{Void}, ()
            )
        bsonObject = new(_wrap_, Union{})
        finalizer(bsonObject, destroy)
        return bsonObject
    end

    BSONObject(other::BSONObject) = begin
        _owner_ = Array{UInt8}(128)
        ccall(
                (:bson_copy_to, libbson),
                Void, (Ptr{Void}, Ptr{UInt8}),
                other._wrap_,
                pointer(_owner_)
        )
        bsonObject = new(Ptr{Void}(pointer(_owner_)), _owner_)
        finalizer(bsonObject, destroy)
        return bsonObject
    end

    BSONObject(dict::Associative) = begin
        bsonObject = BSONObject()
        for (k, v) in dict
            append(bsonObject, k, v)
        end
        return bsonObject
    end

    BSONObject(jsonString::AbstractString) = begin
        jsonCStr = string(jsonString)
        bsonError = BSONError()
        _wrap_ = ccall(
            (:bson_new_from_json, libbson),
            Ptr{Void}, (Ptr{UInt8}, Csize_t, Ptr{UInt8}),
            jsonCStr,
            length(jsonCStr),
            bsonError._wrap_
            )
        _wrap_ != C_NULL || error(bsonError)
        bsonObject = new(_wrap_, Union{})
        finalizer(bsonObject, destroy)
        return bsonObject
    end

    BSONObject(data::Ptr{UInt8}, length::Integer, _ref_::Any) = begin
        buffer = Array(UInt8, 128)
        ccall(
            (:bson_init_static, libbson),
            Bool, (Ptr{Void}, Ptr{UInt8}, UInt32),
            buffer, data, length
            ) || error("bson_init_static: failure")
        b = Compat.unsafe_convert(Ptr{Void}, buffer)
        new(b, (_ref_, buffer))
    end

    BSONObject(_wrap_::Ptr{Void}, _owner_::Any) = new(_wrap_, _owner_)
end
export BSONObject

function convert(::Type{AbstractString}, bsonObject::BSONObject)
    cstr = ccall(
        (:bson_as_json, libbson),
        Ptr{UInt8}, (Ptr{Void}, Ptr{UInt8}),
        bsonObject._wrap_,
        C_NULL
        )
    result = String(unsafe_string(cstr))
    ccall(
        (:bson_free, libbson),
        Void, (Ptr{Void},),
        cstr
        )
    return result
end
export convert

string(bsonObject::BSONObject) = convert(AbstractString, bsonObject)

show(io::IO, bsonObject::BSONObject) = print(io, "BSONObject($(convert(AbstractString, bsonObject)))")
export show

length(bsonObject::BSONObject) =
    ccall(
        (:bson_count_keys, libbson),
        UInt32, (Ptr{Void},),
        bsonObject._wrap_
        )
export length

function append(bsonObject::BSONObject, key::AbstractString, val::Bool)
    keyCStr = string(key)
    ccall(
        (:bson_append_bool, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Bool),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        val
        ) || error("libBSON: overflow")
end
function append(bsonObject::BSONObject, key::AbstractString, val::Real)
    keyCStr = string(key)
    ccall(
        (:bson_append_double, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Cdouble),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        val
        ) || error("libBSON: overflow")
end
using Base.Dates: datetime2unix
function append(bsonObject::BSONObject, key::AbstractString, val::Union{Date,DateTime})
    keyCStr = string(key)
    ts = (typeof(val) == Date ? datetime2unix(DateTime(val)) : datetime2unix(val)) * 1000
    ccall(
        (:bson_append_date_time, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Clong),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        ts
        ) || error("libBSON: overflow")
end
function append(bsonObject::BSONObject, key::AbstractString, val::BSONObject)
    keyCStr = string(key)
    ccall(
        (:bson_append_document, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Ptr{UInt8}),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        val._wrap_
        ) || error("libBSON: overflow")
end
function append(bsonObject::BSONObject, key::AbstractString, val::Union{Int8, UInt8, Int16, UInt16, Int32, UInt32})
    keyCStr = string(key)
    ccall(
        (:bson_append_int32, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Cint),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        val
        ) || error("libBSON: overflow")
end
function append(bsonObject::BSONObject, key::AbstractString, val::Union{Int64, UInt64})
    keyCStr = string(key)
    ccall(
        (:bson_append_int64, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Clong),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        val
        ) || error("libBSON: overflow")
end
function append(bsonObject::BSONObject, key::AbstractString, val::BSONOID)
    keyCStr = string(key)
    ccall(
        (:bson_append_oid, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Ptr{UInt8}),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        val._wrap_
        ) || error("libBSON: overflow")
end
append(bsonObject::BSONObject, key::AbstractString, val::Char) = append(bsonObject, key, string(val))
function append(bsonObject::BSONObject, key::AbstractString, val::AbstractString)
    keyCStr = string(key)
    valUTF8 = String(val)
    ccall(
        (:bson_append_utf8, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Ptr{UInt8}, Cint),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        valUTF8,
        sizeof(valUTF8)
        ) || error("libBSON: overflow")
end
function append(bsonObject::BSONObject, key::AbstractString, val::Void)
    append_null(bsonObject, key)
end
function append(bsonObject::BSONObject, key::AbstractString, val::Symbol)
    if val == :null
        append_null(bsonObject, key)
    elseif val == :minkey
        append_minkey(bsonObject, key)
    elseif val == :maxkey
        append_maxkey(bsonObject, key)
    else
        append(bsonObject, key, string(val))
    end
end
function append(bsonObject::BSONObject, key::AbstractString, val::Associative)
    keyCStr = string(key)
    childBuffer = Array(UInt8, 128)
    ccall(
        (:bson_append_document_begin, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Ptr{Void}),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        childBuffer
        ) || error("bson_append_document_begin: failure")
    childBSON = BSONObject(Compat.unsafe_convert(Ptr{Void}, childBuffer), childBuffer)
    for (k, v) in val
        append(childBSON, k, v)
    end
    ccall(
        (:bson_append_document_end, libbson),
        Bool, (Ptr{Void}, Ptr{Void}),
        bsonObject._wrap_,
        childBuffer
        ) || error("bson_append_document_end: failure")
end
function append(bsonObject::BSONObject, key::AbstractString, val::Vector)
    keyCStr = string(key)
    childBuffer = Array(UInt8, 128)
    ccall(
        (:bson_append_array_begin, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint, Ptr{Void}),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr),
        childBuffer
        ) || error("bson_append_array_begin: failure")
    childBSONArray = BSONArray(Compat.unsafe_convert(Ptr{Void}, childBuffer), childBuffer)
    for element in val
        append(childBSONArray, element)
    end
    ccall(
        (:bson_append_array_end, libbson),
        Bool, (Ptr{Void}, Ptr{Void}),
        bsonObject._wrap_,
        childBuffer
        ) || error("bson_append_array_end: failure")
end
export append

function append_null(bsonObject::BSONObject, key::AbstractString)
    keyCStr = string(key)
    ccall(
        (:bson_append_null, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr)
        ) || error("libBSON: overflow")
end
export append_null

function append_minkey(bsonObject::BSONObject, key::AbstractString)
    keyCStr = string(key)
    ccall(
        (:bson_append_minkey, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr)
        ) || error("libBSON: overflow")
end
export append_minkey

function append_maxkey(bsonObject::BSONObject, key::AbstractString)
    keyCStr = string(key)
    ccall(
        (:bson_append_maxkey, libbson),
        Bool, (Ptr{Void}, Ptr{UInt8}, Cint),
        bsonObject._wrap_,
        keyCStr,
        length(keyCStr)
        ) || error("libBSON: overflow")
end
export append_maxkey

dict(bsonObject::BSONObject) = begin
    d = Dict{Any, Any}()
    for (k, v) in bsonObject
        if isa(v, BSONObject)
            d[k] = dict(v)
        elseif isa(v, BSONArray)
            d[k] = vector(v)
        else
            d[k] = v
        end
    end
    return d
end
export dict

# Private

function destroy(bsonObject::BSONObject)
    ccall(
        (:bson_destroy, libbson),
        Void, (Ptr{Void},),
        bsonObject._wrap_
        )
end


text:
using LockPatternComplexity
using Test

@testset "LockPatternComplexity.jl" begin
    # Tests should execute without errors.
    grid = Grid(3)
    line_types = LineTypes(grid)
    symmetries = Symmetries(grid)
    bounds = Bounds(grid)
    data(grid)
    tmp = mktempdir()
    create_instance(3, tmp)
    extract_solutions(joinpath(@__DIR__, "output"))
    @test true
end


text:
"""
    static_slice(A, sizes)
    static_slice(A, code)

Slice array `A` into an `AbstractArray{StaticArray}`,
with the slices always belonging to the first few indices, i.e. `code = (:,:,...,*,*)`.
Prefers to get `sizes = Size(size(A)[1:ncolons])` for stability,
but if given code instead it will do what it can.

Typically produces `reshape(reinterpret(SArray...`; copy this to get `Array{SArray}`,
or call `static_slice(A, sizes, false)` to omit the reshape.
"""
@inline function static_slice(A::AbstractArray{T,N}, sizes::Size{tup}, finalshape::Bool=true) where {T,N,tup}
    IN = length(tup)
    IT = SArray{Tuple{tup...}, T, IN, prod(tup)}
    if N-IN>1 && finalshape
        finalsize = size(A)[1+IN:end]
        reshape(reinterpret(IT, vec(A)), finalsize)
    else
        reinterpret(IT, vec(A)) # always a vector
    end
end

function static_slice(A::AbstractArray{T,N}, code::Tuple, finalshape::Bool=true) where {T,N}
    N == length(code) ||  throw(ArgumentError("static_glue needs length($(pretty(code))) == ndims(A)"))
    iscodesorted(code) || throw(ArgumentError("static_glue needs a sorted code, not $(pretty(code))"))
    sizes = Size(ntuple(d -> size(A,d), countcolons(code))...)
    static_slice(A, sizes, finalshape)
end

"""
    static_glue(A)

Glues the output of `static_slice` back into one array, again with `code = (:,:,...,*,*)`.
For `MArray` slices, which can't be reinterpreted, this reverts to `red_glue`.
"""
@inline function static_glue(A::AbstractArray{IT}, finalshape=true) where {IT<:SArray}
    if finalshape
        finalsize = (size(IT)..., size(A)...)
        reshape(reinterpret(eltype(IT), A), finalsize)
    else
        reinterpret(eltype(eltype(A)), A)
    end
end

function static_glue(A::AbstractArray{IT}, finalshape=true) where {IT<:MArray}
    code = defaultcode(ndims(IT), ndims(A))
    red_glue(A, code)
end

function glue(A::AbstractArray{IT,ON}, code::Tuple) where {IT<:StaticArray,ON}
    if iscodesorted(code)
        static_glue(A)
    elseif code == (*,:)
        PermuteDims(static_glue(A))
    else
        copy_glue(A, code)
    end
end


text:
using Revise

using Test

using Pkg; Pkg.activate(".")
using HypergraphModularity
using StatsBase
using Combinatorics

# just testing that these run correctly at the moment
@testset "Ω" begin

    kmax = 10

    # general partitionize-based intensity function
    Ω = partitionIntensityFunction(p->sum(p), kmax)
    @test typeof(Ω) == IntensityFunction

    # all-or-nothing cut
    Ω = allOrNothingIntensityFunction(x->(x[1]+1)^(-x[2]), kmax)
    @test typeof(Ω) == IntensityFunction

    # number of unique elements in z: generalizes all-or-nothing
    Ω = sumOfExteriorDegreesIntensityFunction((x, α)->(x[1]+1)^(-α[x[2]]*x[2]), kmax)
    @test typeof(Ω) == IntensityFunction
end

n = 20
Z = rand(1:5, n)
ϑ = dropdims(ones(1,n) + rand(1,n), dims = 1)
μ = mean(ϑ)
kmax = 4

ω(x, α) = (x[1]+1)^(-α[x[2]]*x[2])

α = repeat([2.0], kmax)

Ω = sumOfExteriorDegreesIntensityFunction(ω, kmax)
H = sampleSBM(Z, ϑ, Ω;α=α, kmax=kmax, kmin = 1)

@testset "HSBM Sampling" begin
    @test length(keys(H.E)) == kmax
end

# test for dyadic log likelihood
# currently broken, need to fix.

##
@testset "dyadic likelihood" begin
    ωᵢ = 1.0
    ωₒ = 0.1
    L₁ = dyadicLogLikelihood(H, Z, ωᵢ, ωₒ; weighted=false, binary=false, constants = false)
    L₂ = HypergraphModularity.dyadicLogLikelihoodDirect(H, Z, ωᵢ, ωₒ)
    @test L₁ ≈ L₂
end
##

##
##

@testset "cut" begin
    cut1 = first_term_eval(H, Z, Ω;α=α)
    Hyp, w = HypergraphModularity.hyperedge_formatting(H)
    cut2 = HypergraphModularity.first_term_v2(Hyp,w,Z,Ω;α=α)
    cut3 = HypergraphModularity.first_term_v3(H, Z, Ω;α=α)
    @test cut1 ≈ cut2
    @test cut2 ≈ cut3
    @test cut1 ≈ cut3

# CutDiff appears to be off, unclear whether related to refactor
    @testset "cutdiff" begin
        Hyp, w = hyperedge_formatting(H)
        node2edges = EdgeMap(H)
        I = rand(1:n)
        J = Z[I] + 1
        a = NaiveCutDiff(H,Z,I,J,Ω;α=α)
        b = HypergraphModularity.NaiveCutDiff2(Hyp, w, node2edges,Z,I,J,Ω;α=α)

        c = CutDiff(Hyp,w,node2edges,Z,I,J,Ω; α=α)

        @test a ≈ b
        # @test a ≈ c
        # @test b ≈ c

        # now we'll test multi-node cutdiff
        # this tests the implementation in diffs.jl.

        to_move = findall(==(3), Z)
        t = 1

        C = HypergraphModularity.evalCuts(H, Z,  Ω)

        ΔC = HypergraphModularity.cutDiff(C, to_move, t, Z, Hyp, w, node2edges, Ω)

        Z_ = copy(Z)
        Z_[to_move] .= t

        C_new = HypergraphModularity.evalCuts(H, Z_,  Ω)

        @test C_new == C + ΔC
    end
end

D = H.D

@testset "vol" begin

    @testset "sums" begin

        all_partitions = collect(Iterators.flatten([(partitions(i,j)) for i =1:kmax for j=1:i]))

        p = [3, 1, 1]

        s1 = HypergraphModularity.evalSumNaive(p, Z, D)
        s2 = HypergraphModularity.evalSumNaive2(p, Z, D)

        @test s1 == s2

        sumsNaive = HypergraphModularity.evalSumsNaive(Z,D,kmax)
        sumsPV    = HypergraphModularity.evalSumsPV(Z,D,kmax)
        sums      = HypergraphModularity.evalSums(Z,D,kmax)[3]

        @test all([sumsNaive[p] == sumsPV[p] for p in all_partitions])
        @test all([sumsNaive[p] == sums[p] for p in all_partitions])
    end

    @testset "voldiff" begin

        ℓ = maximum(Z) # number of total groups

        # let's move all the nodes in group 4 to group 5
        to_move = findall(==(4), Z)
        t = 5
        Z_ = copy(Z)

        # first we'll step through, moving each node one-by-one
        V, μ, M = evalSums(Z, D, kmax; constants=false, bigInt=false);
        for i in to_move
            ΔV, Δμ, ΔM = increments(V, μ, M, i, t, D, Z_)
            V, μ, M = HypergraphModularity.addIncrements(V, μ, M, ΔV, Δμ, ΔM)
            # carry out the change in membership
            Z_[i] = t
        end
        step_wise = M

        # next we'll compute the complete set of increments at once
        V, μ, M = evalSums(Z, D, kmax; constants=false, bigInt=false);
        ΔV, Δμ, ΔM = increments(V, μ, M, to_move, t, D, Z)
        V, μ, M = HypergraphModularity.addIncrements(V, μ, M, ΔV, Δμ, ΔM)
        batch = M
        #
        @test all([step_wise[p] == batch[p] for p in keys(M)])
    end

    @testset "second term" begin

        # aggregation
        ℓ = 0
        bigInt = true
        V, μ, M = evalSums(Z, H, ℓ, bigInt)
        M̂ = HypergraphModularity.aggregateSums(M, Ω)
        @test sum(values(M)) ≈ sum(values(M̂))

        s1 = sum(Ω.ω(Ω.aggregator(p), α)*M[p] for p in keys(M))
        s2 = sum(Ω.ω(p̂, α)*M̂[p̂] for p̂ in keys(M̂))

        @test s1 ≈ s2

        s1 = HypergraphModularity.second_term_eval(H, Z, Ω; α=α)
        s2 = HypergraphModularity.naiveSecondTerm(H, Z, Ω; α=α)

        @test s1 ≈ s2
    end
end

@testset "modularity" begin

    Q_naive = HypergraphModularity.modularityNaive(H, Z, Ω;α=α)
    Q = modularity(H, Z, Ω;α=α)
    @test Q_naive ≈ Q
end

@testset "log likelihood" begin
    Ω = estimateΩEmpirically(H, Z; aggregator = p -> [length(p) == 1, sum(p)], bigNums = true)
    L = HypergraphModularity.logLikelihoodNaive(H, Z, Ω; α=α)
    L̄ = logLikelihood(H, Z, Ω;α=α)
    @test Float64(L) ≈ Float64(sum(L̄))
end

@testset "hyperlouvain" begin
    """
    more a test that the code successfully runs than a meaningful test of correctness
    """
    Z_ = HyperLouvain(H,kmax,Ω,100,true;α=α, verbose=true)
    Z_ = SuperNodeLouvain(H,kmax,Ω,100,true;α=α, verbose=true)
end

max_stars_repo_name: PhilChodrow/HypergraphModularity

max_issues_repo_name: PhilChodrow/HypergraphModularity

max_forks_repo_name: PhilChodrow/HypergraphModularity