text:
using Test
import GDAL
import ArchGDAL; const AG = ArchGDAL

@testset "Testing FeatureLayer Methods" begin
    AG.registerdrivers() do
        AG.read("data/point.geojson") do dataset
            AG.createcopy(dataset, "tmp/point.geojson") do tmpcopy
                @test AG.nlayer(tmpcopy) == 1
                # AG.deletelayer!(tmpcopy, 0)
                # @test AG.nlayer(tmpcopy) == 0
                tmplayer = AG.getlayer(tmpcopy,0)
                @test AG.isignored(AG.getgeomfielddefn(AG.getlayerdefn(tmplayer),0)) == false
                AG.setignoredfields!(tmplayer, ["OGR_GEOMETRY"])
                @test AG.isignored(AG.getgeomfielddefn(AG.getlayerdefn(tmplayer),0)) == true
                AG.synctodisk!(tmplayer)
            end
            rm("tmp/point.geojson")

            layer = AG.getlayer(dataset, 0)
            @test sprint(print, AG.getspatialref(layer)) == "Spatial Reference System: +proj=longlat +datum=WGS84 +no_defs "
            @test AG.getfidcolname(layer) == ""
            @test AG.getgeomcolname(layer) == ""
            @test AG.nreference(layer) == 0
            AG.reference(layer)
            @test AG.nreference(layer) == 1
            AG.dereference(layer)
            @test AG.nreference(layer) == 0
            AG.setspatialfilter!(layer,100,-1,100.1,1)
            @test AG.toWKT(AG.getspatialfilter(layer)) == "POLYGON ((100 -1,100 1,100.1 1.0,100.1 -1.0,100 -1))"
            AG.clone(AG.getspatialfilter(layer)) do poly
                n = 0; for feature in layer; n += 1 end; @test n == 2
                AG.clearspatialfilter!(layer)
                @test sprint(print, AG.getspatialfilter(layer)) == "NULL Geometry"
                n = 0; for feature in layer; n += 1 end; @test n == 4

                @testset "Test with setting to index of geomfield" begin
                    AG.setspatialfilter!(layer, 0, poly)
                    n = 0; for feature in layer; n += 1 end; @test n == 2
                    AG.clearspatialfilter!(layer, 0)
                    n = 0; for feature in layer; n += 1 end; @test n == 4

                    AG.setattributefilter!(layer, "FID = 2")
                    n = 0; for feature in layer; n += 1 end; @test n == 1
                    AG.setattributefilter!(layer, "FID = 3")
                    n = 0; for feature in layer; n += 1 end; @test n == 2
                    AG.clearattributefilter!(layer)
                    n = 0; for feature in layer; n += 1 end; @test n == 4
                    AG.setnextbyindex!(layer, 2)
                    n = 0; for feature in layer; n += 1 end; @test n == 2
                    @test AG.testcapability(layer,"OLCRandomWrite") == false
                end
            end
            @test AG.findfieldindex(layer,"FID", true) == 0
            @test AG.findfieldindex(layer,"FID", false) == 0
            @test AG.findfieldindex(layer,"pointname", true) == 1
            @test AG.findfieldindex(layer,"pointname", false) == 1
            @test AG.findfieldindex(layer,"geom", true) == -1
            @test AG.findfieldindex(layer,"geom", true) == -1
            @test AG.findfieldindex(layer,"rubbish", true) == -1
            @test AG.findfieldindex(layer,"rubbish", false) == -1
            @test sprint(print, AG.getextent(layer, 0, true)) == "GDAL.OGREnvelope(100.0, 100.2785, 0.0, 0.0893)"
            @test sprint(print, AG.getextent(layer, true)) == "GDAL.OGREnvelope(100.0, 100.2785, 0.0, 0.0893)"
        end
    end
end

# Untested:
# setfeature!(layer::FeatureLayer, feature::Feature)
# deletefeature!(layer::FeatureLayer, i::Integer)
# creategeomfield!(layer::FeatureLayer, field::GeomFieldDefn, approx::Bool = false)
# deletefield!(layer::FeatureLayer, i::Integer)
# reorderfields!(layer::FeatureLayer, indices::Vector{Cint})
# reorderfield!(layer::FeatureLayer, oldpos::Integer, newpos::Integer)
# alterfielddefn!(layer::FeatureLayer, i::Integer, newfielddefn::FieldDefn, flags::UInt8)
# setignoredfields!(layer::FeatureLayer, fieldnames)
# intersection(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressfunc::Function = GDAL.C.GDALDummyProgress, progressdata = C_NULL)
# union(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressdata = C_NULL, progressfunc::Function = GDAL.C.GDALDummyProgress)
# symdifference(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressfunc::Function = GDAL.C.GDALDummyProgress, progressdata = C_NULL)
# identity(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressfunc::Function = GDAL.C.GDALDummyProgress, progressdata = C_NULL)
# update(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressfunc::Function = GDAL.C.GDALDummyProgress, progressdata = C_NULL)
# clip(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressfunc::Function = GDAL.C.GDALDummyProgress, progressdata = C_NULL)
# erase(input::FeatureLayer, method::FeatureLayer, result::FeatureLayer; options = StringList(C_NULL), progressfunc::Function = GDAL.C.GDALDummyProgress, progressdata = C_NULL)


text:
module ShelfSpaceAllocation

include("model.jl")
include("io.jl")
export ShelfSpaceAllocationModel,
    Specs,
    Params,
    Variables,
    Objectives,
    save_json,
    load_json

include("plotting.jl")
export plot_planogram,
    plot_planograms,
    plot_planogram_no_blocks,
    plot_planograms_no_blocks,
    plot_product_facings,
    plot_demand_and_sales,
    plot_demand_sales_percentage,
    plot_allocation_amount,
    plot_allocation_percentage

end # module

ext: jl


text:
# This file illustrates the recovery of a real signal from its frequency domain.

using Plots
using FFTW

# Define Fourier transform
fs = 100
ts = 1 / 100
l = 2^10
fv = 0 : fs / (l - 1) : fs
xv = sinc.(fv)
ff = 0 : fs / (2l - 1) : fs
xf = [xv; reverse(xv)]

# Define inverse Fourier transform
x = ifft(xf) * fs
t = (0 : 2l - 1) * ts

# Plot the results
plt = plot(layout=2)
plot!(ff, abs.(xf), subplot=1)
xlabel!("f [Hz]", subplot=1)
ylabel!("|X(f)|", subplot=1)
plot!(t, abs.(x), subplot=2)
xlabel!("t [s]", subplot=2)
ylabel!("x(t)", subplot=2)
display(plt)


text:
@doc raw"""
Contains functions and types to work with the analytic solutions to the Dirac equation.

The bound state solutions to the Dirac equation are represented via the ``P_{n\kappa}(r)``
and ``Q_{n\kappa}(r)`` functions defined for each ``n`` and ``\kappa`` quantum number
combination and defined via the relation:

```math
\psi_{n\kappa m}(r,\theta,\varphi)
= \frac{1}{r} \begin{pmatrix}
  P_{n\kappa}(r) \chi_{\kappa m}(\theta,\varphi) \\
  i Q_{n\kappa}(r) \chi_{-\kappa m}(\theta, \varphi)
\end{pmatrix}
```

!!! note "Atomic units"

    All values are in **atomic units**, i.e. ``c = 1/α``, ``m = 1`` and ``\hbar = 1``.
"""
module DiracAnalytic
using SpecialFunctions: gamma
using GSL: sf_laguerre_n
using AtomicLevels: RelativisticOrbital

"""
The fine structure constants ``\\alpha``.

```@repl
α
1/α
```
"""
const α = 0.0072973525664

@doc raw"""
    energy(Z, n, κ) -> Real
    energy(Z, orbital::RelativisticOrbital) -> Real

Calculates the relativistic energy of a hydrogenic orbital in the ``V(r) = - Z / \alpha``
potential:

```math
E_{n\kappa}(Z) =
m c^2\left(1+\left[\frac{Z\alpha}{n-|k|+\sqrt{k^2-Z^2\alpha^2}}\right]^2\right)^{-1/2}
```

Also supports the following signatures

    energy(::Type{Complex}, ...) -> Complex

which allow the value to become complex. This happens after the critical nuclear charge
``Z > \abs{\kappa} / \alpha``.

```julia-repl
julia> energy(Complex, 200, ro"1s")
0.0 + 19962.685927945768im
```
"""
function energy end
energy(Z::Real, orb::RelativisticOrbital) = energy(Z, orb.n, orb.κ)
energy(T::Type{Complex}, Z, orb::RelativisticOrbital) = energy(T, Z, orb.n, orb.κ)
energy(Z::Real, n::Integer, κ::Integer) = _E(Z, n, κ, _Δ(Z, κ))
energy(::Type{Complex}, Z, n::Integer, κ::Integer) = _E(Z, n, κ, complex(_Δ(Z, κ)))
# Internal methods to handle the complex and non-complex versions of E
_E(Z, n, κ, Δ) = 1 / (α^2 * sqrt(1 + (Z*α / (n - abs(κ) + sqrt(Δ)))^2))
_Δ(Z, κ) = κ^2 - (Z*α)^2

# Radial solutions of the DiracEquation

abstract type DiracSolution end
function PQ end
Base.broadcastable(x::DiracSolution) = Ref(x)

"""
Implementation based on the expressions in Wikipedia:
<https://en.wikipedia.org/wiki/Hydrogen-like_atom#Solution_to_Dirac_equation>
"""
struct WikiSolution <: DiracSolution
    Z :: Float64
    n :: Int
    κ :: Int
end

function PQ(s::WikiSolution, r)
    E = energy(s.Z, s.n, s.κ)
    C, γ = _wiki_C(s.Z, s.n), _wiki_γ(s.Z, s.κ)
    A = _wiki_A(s.Z, s.n, s.κ)
    ρ = 2 * C * r

    if s.n == -s.κ
        A * (s.n + γ) * (ρ^γ) * exp(-ρ/2), A * s.Z * α * (ρ^γ) * exp(-ρ/2)
    else
        L1 = sf_laguerre_n(s.n - abs(s.κ) - 1, 2γ + 1, ρ)
        L2 = sf_laguerre_n(s.n - abs(s.κ), 2γ + 1, ρ)
        A * (ρ^γ) * exp(-ρ/2) * (
            s.Z * α * ρ * L1 +
            (γ - s.κ) * (γ/α^2 - s.κ*E) * L2 * α / C
        ),
        A * (ρ^γ) * exp(-ρ/2) * (
            (γ - s.κ) * ρ * L1 +
            s.Z * α * (γ/α^2 - s.κ*E) * L2 * α / C
        )
    end
end

function _wiki_A(Z, n, k)
    C, γ = _wiki_C(Z, n), _wiki_γ(Z, k)
    if n == -k
        sqrt(C / (2 * n * (n + γ) * γ * gamma(2γ)))
    else
        E = energy(Z, n, k)
        sqrt(
            0.5 *
            (C / (n - abs(k) + γ)) *
            (factorial(n - abs(k) - 1) / gamma(n - abs(k) + 2γ + 1)) *
            ((α^2 * E * k / γ)^2 + (α^2 * E * k / γ))
        ) / sqrt(2k * (k - γ))
    end
end

@doc raw"""
    _wiki_γ(Z, κ)

Calculates the ``\gamma = \sqrt{\kappa^2 - Z^2 \alpha^2}`` value.
"""
_wiki_γ(Z, κ) = sqrt(κ^2 - (Z*α)^2)

@doc raw"""
    _wiki_C(Z, n)

Calculates the radial decay constant ``C``:

```math
C = \frac{Z\alpha}{n}\frac{m c^2}{\hbar c} = \frac{Z}{n}
```
"""
_wiki_C(Z, n) = Z/n # μ = 1, ħ = 1 and α*c^2 / c = 1

end # module


text:
#unum-onezero.jl
#implements the one and zero functions for unums.

#SOME MATHEMATICAL CONSTANTS
Base.zero{ESS,FSS}(::Type{UnumSmall{ESS,FSS}}) = UnumSmall{ESS,FSS}(z64, z64, z16, z16, z16)
Base.zero{ESS,FSS}(::Type{UnumLarge{ESS,FSS}}) = UnumLarge{ESS,FSS}(z64, zero(ArrayNum{FSS}), z16, z16, z16)
@generated function Base.zero{ESS,FSS}(::Type{Unum{ESS,FSS}})
  if FSS < 7
    :(UnumSmall{ESS,FSS}(z64, z64, z16, z16, z16))
  else
    :(UnumLarge{ESS,FSS}(z64, zero(ArrayNum{FSS}), z16, z16, z16))
  end
end
@universal Base.zero(x::Unum) = zero(U)

doc"""
  the `zero!` function forcibly converts an existing unum to zero.  You can pass
  a flag that sets the sign or ubit, but it defaults to positive/not a ubit.
"""
@universal function zero!(x::Unum, flags::UInt16 = z16)
  x.fsize = z16
  x.esize = z16
  x.flags = flags
  x.exponent = z64
  frac_zero!(x)
end
export zero!

function Base.one{ESS,FSS}(::Type{UnumSmall{ESS,FSS}})
  if ESS == 0
    UnumSmall{ESS,FSS}(z64, t64, z16, z16, z16)
  else
    UnumSmall{ESS,FSS}(o64, z64, z16, o16, z16)
  end
end
function Base.one{ESS,FSS}(::Type{UnumLarge{ESS,FSS}})
  if ESS == 0
    UnumLarge{ESS,FSS}(z64, top(ArrayNum{FSS}), z16, z16, z16)
  else
    UnumLarge{ESS,FSS}(o64, zero(ArrayNum{FSS}), z16, o16, z16)
  end
end
Base.one{ESS,FSS}(::Type{Unum{ESS,FSS}}) = (FSS < 7) ? Base.one(UnumSmall{ESS,FSS}) : Base.one(UnumLarge{ESS,FSS})
@universal Base.one(x::Unum) = one(typeof(x))

pos_one{ESS,FSS}(::Type{Unum{ESS,FSS}}) = FSS < 7 ? one(UnumSmall{ESS,FSS}) : one(UnumLarge{ESS,FSS})
@universal pos_one(t::Type{Unum}) = one(t)
pos_one{ESS,FSS}(x::Unum{ESS,FSS}) = one(Unum{ESS,FSS})
@universal pos_one(x::Unum) = one(typeof(x))

neg_one{ESS,FSS}(::Type{Unum{ESS,FSS}}) = FSS < 7 ? uflag!(one(UnumSmall{ESS,FSS}), UNUM_SIGN_MASK) : uflag!(one(UnumLarge{ESS,FSS}), UNUM_SIGN_MASK)
@universal neg_one(t::Type{Unum}) = uflag!(one(t), UNUM_SIGN_MASK)
neg_one{ESS,FSS}(x::Unum{ESS,FSS}) = uflag!(one(Unum{ESS,FSS}), UNUM_SIGN_MASK)
@universal neg_one(x::Unum) = uflag!(one(typeof(x)))
export pos_one, neg_one

################################################################################
#infs and nans look quite similar, so we'll create a generated function that
#combines the code for both.
@universal function __infnanset!(x::Unum, flags::UInt16)
  x.fsize = max_fsize(FSS)
  x.esize = max_esize(ESS)
  x.flags = flags
  x.exponent = max_biased_exponent(ESS)
  frac_all!(x)
  (FSS < 7) && frac_trim!(x, x.fsize)
  return x
end

################################################################################

doc"""
  the `nan!` function forcibly turns a unum variable into nan.
"""
@universal nan!(x::Unum, signmask::UInt16 = z16) = __infnanset!(x, UNUM_UBIT_MASK | signmask)
doc"""
  Unums.nan(::Type{Unum})

  the internal nan function for generating typed nans.
"""
@universal nan(T::Type{Unum}, signmask::UInt16 = z16) = nan!(zero(T), signmask)
nan{ESS,FSS}(T::Type{Unum{ESS,FSS}}, signmask::UInt16 = z16) = nan!(zero(T), signmask)
################################################################################

inf{ESS,FSS}(::Type{Unum{ESS,FSS}}, signmask::UInt16 = z16) = (FSS < 7) ? __infnanset!(zero(UnumSmall{ESS,FSS}), signmask) : __infnanset!(zero(UnumLarge{ESS,FSS}), signmask)
@universal inf(T::Type{Unum}, signmask::UInt16 = z16) = __infnanset!(zero(U), signmask)
doc"""
  `pos_inf` generates an explicitly positive infinite value of the chosen type.
"""
pos_inf{ESS,FSS}(T::Type{Unum{ESS,FSS}}) = inf(T)
@universal pos_inf(T::Type{Unum}) = inf(T)

doc"""
  `neg_inf` generates an explicitly negative infinite value of the chosen type.
"""
neg_inf{ESS,FSS}(T::Type{Unum{ESS,FSS}}) = inf(T, UNUM_SIGN_MASK)
@universal neg_inf(T::Type{Unum}) = inf(T, UNUM_SIGN_MASK)

doc"""
  the `inf!` function forcibly turns a unum variable into inf of the chosen type...
"""
@universal inf!(x::Unum, signmask::UInt16 = z16) = __infnanset!(x, signmask)

doc"""
  the `pos_inf!` function forcibly turns a unum variable into positive infinity...
"""
@universal pos_inf!(x::Unum, signmask::UInt16) = __infnanset!(x)

doc"""
  the `neg_inf!` function forcibly turns a unum variable into negative infinity...
"""
@universal neg_inf!(x::Unum, signmask::UInt16) = __infnanset!(x, UNUM_SIGN_MASK)
export pos_inf, neg_inf, inf!, pos_inf!, neg_inf!

################################################################################
# cheapest zero ulp and cheapest inf ulp are the bit-cost cheapest of these
# two classes of number.

cheapest_zero_ulp{ESS,FSS}(T::Type{Unum{ESS,FSS}}, sign::UInt16 = z16) = (FSS < 7) ? cheapest_zero_ulp(UnumSmall{ESS,FSS}, sign) : cheapest_zero_ulp(UnumLarge{ESS,FSS}, sign)
cheapest_zero_ulp{ESS,FSS}(T::Type{UnumSmall{ESS,FSS}}, sign::UInt16 = z16) = T(z64, z64, sign | UNUM_UBIT_MASK, z16, z16)
cheapest_zero_ulp{ESS,FSS}(T::Type{UnumLarge{ESS,FSS}}, sign::UInt16 = z16) = T(z64, zero(ArrayNum{FSS}), sign | UNUM_UBIT_MASK, z16, z16)

cheapest_inf_ulp{ESS,FSS}(T::Type{Unum{ESS,FSS}}, sign::UInt16 = z16) = (FSS < 7) ? cheapest_inf_ulp(UnumSmall{ESS,FSS}, sign) : cheapest_inf_ulp(UnumLarge{ESS,FSS}, sign)
cheapest_inf_ulp{ESS,FSS}(T::Type{UnumSmall{ESS,FSS}}, sign::UInt16 = z16) = T(max_biased_exponent(ESS), t64, sign | UNUM_UBIT_MASK, max_esize(ESS), z16)
cheapest_inf_ulp{ESS,FSS}(T::Type{UnumLarge{ESS,FSS}}, sign::UInt16 = z16) = T(max_biased_exponent(ESS), top(ArrayNum{FSS}), sign | UNUM_UBIT_MASK, max_esize(ESS), z16)

cheapest_inf_ulp{ESS}(T::Type{UnumSmall{ESS, 0}}, sign::UInt16 = z16) = mmr(T, sign)
cheapest_inf_ulp{ESS}(T::Type{UnumLarge{ESS, 0}}, sign::UInt16 = z16) = mmr(T, sign)

################################################################################
# mmr and big_exact look very similar, so we'll combine the code to generate them
# here.
@universal function __mmr_bigexact_set!(x::Unum, flags::UInt16)
  x.fsize = max_fsize(FSS)
  x.esize = max_esize(ESS)
  x.flags = flags
  x.exponent = max_biased_exponent(ESS)

  if (FSS == 0)
    x.fraction = z64
  else
    frac_mask_top!(x, x.fsize - o16)
  end

  return x
end

#mmr and bigexact - "more than maxreal" and "biggest exact number".
mmr{ESS,FSS}(::Type{Unum{ESS,FSS}}, signmask::UInt16 = z16) = __mmr_bigexact_set!(zero(Unum{ESS,FSS}), signmask | UNUM_UBIT_MASK)
@universal mmr(T::Type{Unum}, signmask::UInt16 = z16) = __mmr_bigexact_set!(zero(T), signmask | UNUM_UBIT_MASK)
@universal mmr!(x::Unum, signmask::UInt16 = z16) = __mmr_bigexact_set!(x, signmask | UNUM_UBIT_MASK)

pos_mmr{ESS,FSS}(::Type{Unum{ESS,FSS}}) = mmr(Unum{ESS,FSS})
neg_mmr{ESS,FSS}(::Type{Unum{ESS,FSS}}) = mmr(Unum{ESS,FSS}, UNUM_SIGN_MASK)
@universal pos_mmr(T::Type{Unum}) = mmr(T)
@universal neg_mmr(T::Type{Unum}) = mmr(T, UNUM_SIGN_MASK)
@universal pos_mmr!(x::Unum) = __mmr_bigexact_set!(x, UNUM_UBIT_MASK)
@universal neg_mmr!(x::Unum) = __mmr_bigexact_set!(x, UNUM_SIGN_MASK | UNUM_UBIT_MASK)

big_exact{ESS,FSS}(::Type{Unum{ESS,FSS}}, signmask = z16) = __mmr_bigexact_set!(zero(Unum{ESS,FSS}), signmask & (~UNUM_UBIT_MASK))
@universal big_exact(T::Type{Unum}, signmask::UInt16 = z16) = __mmr_bigexact_set!(zero(T), signmask & (~UNUM_UBIT_MASK))
@universal big_exact!(x::Unum, signmask::UInt16 = z16) = __mmr_bigexact_set!(x, signmask & (~UNUM_UBIT_MASK))

pos_big_exact{ESS,FSS}(::Type{Unum{ESS,FSS}}) = big_exact(Unum{ESS,FSS})
neg_big_exact{ESS,FSS}(::Type{Unum{ESS,FSS}}) = big_exact(Unum{ESS,FSS}, UNUM_SIGN_MASK)
@universal pos_big_exact(T::Type{Unum}) = big_exact(T)
@universal neg_big_exact(T::Type{Unum}) = big_exact(T, UNUM_SIGN_MASK)
@universal pos_big_exact!(x::Unum) = __mmr_bigexact_set!(x)
@universal neg_big_exact!(x::Unum) = __mmr_bigexact_set!(x, UNUM_SIGN_MASK)
export mmr, mmr!, pos_mmr, neg_mmr, pos_mmr!, neg_mmr!, big_exact, big_exact!, pos_big_exact, neg_big_exact, pos_big_exact!, neg_big_exact!

################################################################################
# smaller than small subnormal cannot reuse code from zero because the esize and
# fsize parameters have to be maxed out.

@universal function sss!(x::Unum, flags::UInt16 = z16)
  x.fsize = max_fsize(FSS)
  x.esize = max_esize(ESS)
  x.flags = flags | UNUM_UBIT_MASK
  x.exponent = z64
  frac_zero!(x)
  return x
end

sss{ESS,FSS}(::Type{Unum{ESS,FSS}}, signmask::UInt16 = z16) = sss!(zero(Unum{ESS,FSS}), signmask)
@universal sss(T::Type{Unum}, signmask::UInt16 = z16) = sss!(zero(T), signmask)

pos_sss{ESS,FSS}(::Type{Unum{ESS,FSS}}) = sss(Unum{ESS,FSS})
neg_sss{ESS,FSS}(::Type{Unum{ESS,FSS}}) = sss(Unum{ESS,FSS}, UNUM_SIGN_MASK)
@universal pos_sss(T::Type{Unum}) = sss(T)
@universal neg_sss(T::Type{Unum}) = sss(T, UNUM_SIGN_MASK)
@universal pos_sss!(x::Unum) = sss!(x)
@universal neg_sss!(x::Unum) = sss!(x, UNUM_SIGN_MASK)
export sss, sss!, pos_sss, neg_sss, pos_sss!, neg_sss!

################################################################################
# small_exact is tricky because it generates a very unique signature.
@universal function __set_small_exact!(x::Unum, flags::UInt16 = z16)
  x.fsize = max_fsize(FSS)
  x.esize = max_esize(ESS)
  x.flags = flags & (~UNUM_UBIT_MASK)
  x.exponent = z64

  frac_bottom_bit!(x)

  return x
end

@universal small_exact!(x::Unum, flags::UInt16 = z16) = __set_small_exact!(x, flags)

small_exact{ESS,FSS}(T::Type{Unum{ESS,FSS}}, signmask = z16) = (x = zero(T); __set_small_exact!(x, signmask))
@universal small_exact(T::Type{Unum}, signmask = z16) = (x = zero(U); __set_small_exact!(x, signmask))

pos_small_exact{ESS,FSS}(T::Type{Unum{ESS,FSS}}) = small_exact(T)
neg_small_exact{ESS,FSS}(T::Type{Unum{ESS,FSS}}) = small_exact(T, UNUM_SIGN_MASK)
@universal pos_small_exact(T::Type{Unum}) = small_exact(T)
@universal neg_small_exact(T::Type{Unum}) = small_exact(T, UNUM_SIGN_MASK)

@universal pos_small_exact!(x::Unum) = small_exact!(x)
@universal neg_small_exact!(x::Unum) = small_exact!(x, UNUM_SIGN_MASK)
export small_exact, small_exact!, pos_small_exact, neg_small_exact, pos_small_exact!, neg_small_exact!

max_stars_repo_name: REX-Computing/unumjl

max_issues_repo_name: REX-Computing/unumjl

max_forks_repo_name: REX-Computing/unumjl


text:
include("bilibilivideos.jl")

const DATEFMT = dateformat"yyyy-mm-dd HH:MMp"
const TZ = "Asia/Shanghai"

function hfun_bar(vname)
  val = Meta.parse(vname[1])
  return round(sqrt(val), digits=2)
end

function hfun_m1fill(vname)
  var = vname[1]
  return pagevar("index", var)
end

function lx_baz(com, _)
  # keep this first line
  brace_content = Franklin.content(com.braces[1]) # input string
  # do whatever you want here
  return uppercase(brace_content)
end

function hfun_bilibili(params)
  id = params[1]
  trueid = get(videos, id, id)
  aid = getindex(trueid,1)
  bvid = getindex(trueid,2)
  cid = getindex(trueid,3)

  return """

  """
end


text:
using TypeTransform
using Test

include("fexpr.jl")
include("specific.jl")


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

using Markdown
using InteractiveUtils

# ╔═╡ 0758937c-478f-45b7-a1d4-31810eecfd60
begin
	using PlutoUI
	PlutoUI.TableOfContents(aside=true)
end

# ╔═╡ 7bf123d1-dc37-44d0-9da9-982dbca9ec02
using LinearAlgebra

# ╔═╡ e0d1f2ca-ea96-4ae8-a3bd-cfabe92978d5
using SparseArrays

# ╔═╡ ea479efe-0f65-4365-a136-14afdfb180e2
using Images

# ╔═╡ 56d22088-733f-4b76-8b56-592229cd6a25
md"""
# Sparse + Low-Rank Splitting

Suppose we are given a data matrix $A$, and know that it has a form $$A=L+S,$$ where $L$ is of low-rank and $S$ is sparse, but we know neither the rank of $L$ nor the non-zero entries of $S$.

_Can we recover $L$ and $S$?_

The answer is _YES, with high probability and with an efficient algorithm_.

_Sparse + Low-rank_ splitting can be successfully applied to video surveilance, face recognition, latent semantic indexing, and ranking and collaborative filtering.

__Prerequisites__

The reader should be familiar with linear algebra concepts, particularly SVD and its properties and algorithms.

__Competences__

The reader should be able to apply sparse + low-rank splitting to real problems.

__References__

For more details see [E. J. Candes, X. Li, Y. Ma, and J. Wright, Robust Principal Component Analysis?](http://arxiv.org/abs/0912.3599)

__Credits__: The author wishes to thank Dimitar Ninevski, a former IAESTE intern, for collecting and preparing some of the material.

"""

# ╔═╡ 33d0a1b9-f2f4-4f48-998f-e058c9a69e14
md"""
## Definitions

Let $A\in\mathbb{R}^{m\times n}$ have rank $r$, and let $A=U\Sigma V^T$ be its SVD.

The __nuclear norm__ of $A$ is $\|A\|_*=\sum\limits_{i=1}^r \sigma_i(A)$.

Let $\|A\|_1=\sum\limits_{i,j} |A_{ij}|$ denote the $1$-norm of $A$ seen as a long vector.

Let $\|A\|_{\infty}=\max\limits_{i,j} |A_{ij}|$ denote the $\infty$-norm of $A$ seen as a long vector.

Given $\tau>0$, the __shrinkage operator__ $\mathcal{S}_{\displaystyle\tau}:\mathbb{R}\to \mathbb{R}$ is defined by
$\mathcal{S}_{\displaystyle\tau}(x)=\mathop{\mathrm{sign}}(x)\max\{|x|-\tau,0\}$,
and is extended to matrices by applying it to each element.

Given $\tau>0$, the __singluar value thresholding operator__ is
$\mathcal{D}_{\displaystyle\tau}(A)=U \mathcal{S}_{\displaystyle\tau} (\Sigma) V^T$.

"""

# ╔═╡ 5c78225a-99b0-4587-87a7-d7ae505a9adc
md"""
### Example
"""

# ╔═╡ 7bb93306-9994-4302-9d03-43bb4404501e
# Shrinkage
function Shr(x::Array{T},τ::T) where T
    sign.(x).*max.(abs.(x).-τ,zero(T))
end

# ╔═╡ 19982690-3cf8-45f2-a19f-3a4004ec29f0
begin
	import Random
	Random.seed!(421)
	A₀=2*rand(3,5).-1
end

# ╔═╡ 35c93042-50a1-4d17-ba93-eb4abeb32bdc
Shr(A₀,0.5)

# ╔═╡ a5c7c4fb-4d28-4cdb-a825-81b422f5357c
# Singular value thresholding
function D(A::Array{T},τ::T) where T
    # U,σ,V=svd(A)
    # This can be replaced by a faster approach
    V=svd(A)
    S=Shr(V.S,τ)
    k=count(!iszero,S)
    return (V.U[:,1:k]*Diagonal(S[1:k]))*V.Vt[1:k,:]
end

# ╔═╡ 004407fe-d861-42b6-a061-4ef41176a289
svdvals(A₀)

# ╔═╡ 701fdeda-d5e3-4686-b57d-0c0dadba7c91
C₀=D(A₀,0.5)

# ╔═╡ 78fda2e8-1fbf-4aa1-bc4a-a05c262a410a
svdvals(C₀)

# ╔═╡ a29511fa-1deb-4bea-97aa-326bd366f6ab
md"""
## Facts

Let $A=L+S$ be the splitting that we are looking for.

1. The problem can be formulated as

$\mathop{\textrm{arg min}}\limits_{\displaystyle \mathop{\mathrm{rank}}(L)\leq k} \|A-L\|_2$.

2. The problem makes sense if the __incoherence conditions__

$$
\max_{\displaystyle i} \| U_{:,1:r}^T e_i\|_2^2\leq \frac{\mu r}{m}, \quad
\max_{\displaystyle i} \| V_{:,1:r}^T e_i\|_2^2\leq \frac{\mu r}{n}, \quad
\|UV^T\|_{\infty} \leq \sqrt{\frac{\mu r}{m\cdot n}},$$

hold for some parameter $\mu$.

3. If the incoherence conditions are satisfied, the __Principal Component Pursuit estimate__,

$$
\mathop{\textrm{arg min}}\limits_{\displaystyle L+S=A} \|L\|_*+\lambda \|S\|_2,$$

exactly recovers $L$ and $S$.

4. __Principal Component Pursuit by Alternating Directions__ algorithm finds the above estimate
    1. _Initialization_: $S=0$, $Y=0$, $L=0$, $\mu>0$, $\delta=10^{-7}$.
    2. _Iterations_: while $\|A-L-S\|_F>\delta\|A\|_F$ repeat
        1. _SV Thresholding_: $L=\mathcal{D}_{\displaystyle \mu^{-1}}(A-S+\mu^{-1}Y)$
        2. _Shrinkage_: $S=\mathcal{S}_{\displaystyle \lambda \mu^{-1}}(A-L+\mu^{-1}Y)$
        3. _Updating_: $Y=Y+\mu(A-L-S)$
"""

# ╔═╡ 8f347422-2782-48ca-b165-f97219ab8677
function PCPAD(A::Array{T}) where T
    # Initialize
    δ=1.0e-7
    tol=δ*norm(A)
    m,n=size(A)
    S=zero(A)
    Y=zero(A)
    L=zero(A)
    T₁=zero(A)
    μ=(m*n)/(4*(norm(A[:],1)))
    μ₁=one(T)/μ
    λ=one(T)/√(max(m,n))
    λμ₁=λ*μ₁
    ν=1e20
    maxiter=200
    iterations=0
    # Iterate
    while (ν>tol) && iterations<maxiter
        # println(iterations," ",ν)
        iterations+=1
        L=D(A-S+μ₁*Y,μ₁)
        S=Shr(A-L+μ₁.*Y,λμ₁)
        T₁=(A-L-S)
        Y+=(μ.*T₁)
        ν=norm(T₁)
    end
    L,S, iterations
end

# ╔═╡ db4778a0-7948-43cc-b63a-3b2d2a924228
@time L₀,S₀,iter₀=PCPAD(A₀)

# ╔═╡ 0b8f097f-2327-467f-a1d5-481711773ae2
rank(L₀),norm(A₀-L₀-S₀)

# ╔═╡ e33dbeb8-cae9-418b-9e89-1e6563bd58a7
md"
## Examples

### Larger random matrix
"

# ╔═╡ e52bd27c-6263-4b65-9a60-5ddb31626881
begin
	# Now the real test
	# Dimensions of the matrix
	m=100
	n=100
	# Rank of the low-rank part L
	k=10
	# Generate L
	L=rand(m,k)*rand(k,n)
	rank(L)
end

# ╔═╡ 7c23f010-5b76-44e0-ab8e-dd1eb8a01588
begin
	# Sparsity of the sparse part S
	sparsity=0.1
	# Generate S
	S=10*sprand(m,n,sparsity)
	nnz(S)
end

# ╔═╡ e7a50a63-2312-43f0-b771-64452e33d808
# Generate the matrix A, it is a full matrix with full rank
A=L+S;

# ╔═╡ 42904941-1859-4a05-a08c-a7a650f6b188
rank(A)

# ╔═╡ 0bc47362-3b76-44a8-8c52-2d0fa640a984
# Decompose A into L₁ and S₁
@time L₁,S₁,iters=PCPAD(A);

# ╔═╡ b04a85a6-0fab-4a37-9b54-28dfbe9382aa
iters, rank(L₁), norm(L), norm(L-L₁), norm(S), norm(S-S₁)

# ╔═╡ f58a21b2-a940-49f8-a179-e0c2dd032579
md"""
Although there might be no convergence, the splitting is still good.
"""

# ╔═╡ 1d16c2fa-d9b3-4e4c-bafc-9edbe408f516
S₁

# ╔═╡ 321cc936-0ed3-4fcd-bf95-504f8529ef1b
Matrix(S)

# ╔═╡ 8704e62c-278c-4cf2-9b14-063b6ab3abd3
md"""
### Face recognition

We will try to recover missing features. The images are chosen from the
[Yale Face Database](http://vision.ucsd.edu/content/yale-face-database).

"""

# ╔═╡ 612b0d4d-0a74-473d-89c9-f89333817b09
# First a single image
img=load("files/17.jpg")

# ╔═╡ b5f358cd-6475-4187-b248-68cc62cf55af
show(img[1,1])

# ╔═╡ 0ef3370b-edfe-46f6-9fb6-81ce8e3d86b3
A₂=map(Float64,img);

# ╔═╡ 24c36ac7-7ba6-4df1-9a90-2381b97362a2
begin
	# Compute the splitting and show number of iterations
	@time L₂,S₂,iters₂=PCPAD(A₂)
	iters₂, rank(L₂), norm(A₂), norm(A₂-L₂-S₂)
end

# ╔═╡ d0874885-447b-4aaa-8b2a-9c59ede4ac78
colorview(Gray,L₂)

# ╔═╡ a1413dd4-12c0-44e8-8981-79cb10d308dc
# Try S+0.5
colorview(Gray,S₂.+0.5)

# ╔═╡ e7714ae7-c473-44a6-9279-0374686495da
hcat(colorview(Gray,0.9*L₂+S₂.+0.2),img)

# ╔═╡ 481ab279-96bb-4a71-abb7-5df48b900e46
# Another image
img₃=load("files/19.jpg")

# ╔═╡ b8f4214c-2e11-4fba-a9a9-439a672516c8
begin
	A₃=map(Float64,img)
	L₃,S₃,iters₃=PCPAD(A₃)
	iters₃, rank(L₃), norm(A₃), norm(A₃-L₃-S₃)
end

# ╔═╡ c52d6a06-691f-49f1-9e5b-043429cba296
hcat(img₃,colorview(Gray,L₃),colorview(Gray,L₃+S₃.+0.3))

# ╔═╡ 0d8ddcb5-529e-4187-b257-9f8233abf656
md"""
### Multiple images

Each image of $168 \times 192$ pixels is converted to a vector of length 32256.
All vectors are stacked in the columns of matrix $A$, and the low-rank + sparse splitting
of $A$ is computed.
"""

# ╔═╡ 243bd190-6912-475f-870e-43f96656e9f6
begin
	# Load all images in the collection
	dir="./files/yaleB08/"
	files=readdir(dir)
end

# ╔═╡ 8b4577b3-8b23-4dbe-9d6f-9aec90849b60
begin
	n₄=length(files)-1
	images=Array{Any}(undef,n₄)
	B=Array{Any}(undef,n₄)
	for i=1:n₄
	    images[i]=Images.load(joinpath(dir,files[i+1]))
	    B[i]=map(Float64,images[i])
	end
end

# ╔═╡ db755a0a-0a04-4fc2-bdfe-641a0b933575
# Last 9 images are meaningless
images

# ╔═╡ c1fa7658-6c71-4891-b82e-dd676c2f1b37
begin
	# Form the big matrix - each image is converted to a column vector
	mi,ni=size(images[1])
	A₄=Array{Float64}(undef,mi*ni,n₄-9)
	for i=1:n₄-9
	    A₄[:,i]=vec(B[i])
	end
	size(A₄)
end

# ╔═╡ 8ca25ca4-3681-46d0-945a-2c99d20205b7
begin
	# Now the big SVDs - 1 minute (Tall and skinny)
	@time L₄,S₄,iters₄=PCPAD(A₄)
	iters₄, rank(L₄), norm(A₄), norm(A₄-L₄-S₄)
end

# ╔═╡ eaa6def3-06fc-4646-a228-1f9180050ffc
# For example
colorview(Gray,reshape(S₄[:,1],mi,ni).+0.3)

# ╔═╡ e32b8ed8-e50b-4b79-9f6d-119b6d2796dc
begin
	LowRank=similar(images)
	Sparse=similar(images)
	for i=1:n₄-9
	    LowRank[i]=colorview(Gray,reshape(L₄[:,i],mi,ni))
	    Sparse[i]=colorview(Gray,reshape(S₄[:,i],mi,ni).+0.3)
	end
	# hcat(images,LowRank,Sparse)
end

# ╔═╡ 66fd9e25-cb4a-410e-ae83-311fffb864c7
LowRank

# ╔═╡ adcb7667-cdff-4ba4-b59d-c2ece2f7ee31
Sparse

# ╔═╡ 80a6d992-0e72-4c9f-a593-18a0fed09e1c
begin
	i=29
	hcat(images[i],LowRank[i],Sparse[i],0.9*LowRank[i]+Sparse[i])
end

# ╔═╡ 85975780-6c17-4af9-a169-9fe906c1e369
md"""
### Mona Lisa's smile
"""

# ╔═╡ 0ad6a808-692d-47e6-9e8f-1f721a38524e
img₅=load("files/mona-lisa_1.jpg")

# ╔═╡ 8a7548de-6e1e-442c-b5a7-b65a6af0efa4
# As in the notebook S03
imgsep=map(Float64,channelview(img₅))

# ╔═╡ fbb0bf4c-2c91-47b2-8e61-c6c0a1085b27
size(imgsep)

# ╔═╡ 396542f6-737d-49ca-a3c9-41d319aa5cc7
begin
	# 1-2 minutes
	# Red
	@time RL,RS,Riter=PCPAD(imgsep[1,:,:])
	# Green
	GL,GS,Giter=PCPAD(imgsep[2,:,:])
	# Blue
	BL,BS,Biter=PCPAD(imgsep[3,:,:])
end

# ╔═╡ 1c13b5c0-26d5-4220-9fca-fecd7c945c57
Giter, rank(GL), norm(imgsep[2,:,:]), norm(imgsep[2,:,:]-GL-GS)

# ╔═╡ 062918a1-b84a-4c91-ba9e-7fe630582f63
# Mona Lisa's low-rank component
colorview(RGB,RL,GL,BL)

# ╔═╡ 6ccc341f-fae8-4f18-b3a5-3528a101a8c1
# Mona Lisa's sparse component
colorview(RGB,RS.+0.5,GS.+0.5,BS.+0.5)

# ╔═╡ 3bda0ed2-c721-4a8d-9beb-50fb0066b28e
md"""
### Mona Lisa's hands
"""

# ╔═╡ 94423d38-dc7b-4a26-b0f0-0ed532c80e72
img₆=load("files/Mona_Lisa_detail_hands.jpg")

# ╔═╡ a53efeb6-2676-4d13-b2b0-0da4089dbcc6
begin
	imgsep₁=map(Float64,channelview(img₆))
	@time RL₁,RS₁,Riter₁=PCPAD(imgsep₁[1,:,:])
	GL₁,GS₁,Giter₁=PCPAD(imgsep₁[2,:,:])
	BL₁,BS₁,Biter₁=PCPAD(imgsep₁[3,:,:])
	# Norm for Green
	Giter₁, rank(GL₁), norm(imgsep₁[2,:,:]),
	norm(imgsep₁[2,:,:]-GL₁-GS₁)
end

# ╔═╡ fe9da092-9dd9-4304-96a7-1016cbdc4a5e
colorview(RGB,RL₁,GL₁,BL₁)

# ╔═╡ 26e90bdb-dfb3-4259-bb75-a037e86344fe
colorview(RGB,RS₁.+0.5,GS₁.+0.5,BS₁.+0.5)

# ╔═╡ Cell order:
# ╟─0758937c-478f-45b7-a1d4-31810eecfd60
# ╟─56d22088-733f-4b76-8b56-592229cd6a25
# ╟─33d0a1b9-f2f4-4f48-998f-e058c9a69e14
# ╟─5c78225a-99b0-4587-87a7-d7ae505a9adc
# ╠═7bb93306-9994-4302-9d03-43bb4404501e
# ╠═19982690-3cf8-45f2-a19f-3a4004ec29f0
# ╠═35c93042-50a1-4d17-ba93-eb4abeb32bdc
# ╠═7bf123d1-dc37-44d0-9da9-982dbca9ec02
# ╠═a5c7c4fb-4d28-4cdb-a825-81b422f5357c
# ╠═004407fe-d861-42b6-a061-4ef41176a289
# ╠═701fdeda-d5e3-4686-b57d-0c0dadba7c91
# ╠═78fda2e8-1fbf-4aa1-bc4a-a05c262a410a
# ╟─a29511fa-1deb-4bea-97aa-326bd366f6ab
# ╠═8f347422-2782-48ca-b165-f97219ab8677
# ╠═db4778a0-7948-43cc-b63a-3b2d2a924228
# ╠═0b8f097f-2327-467f-a1d5-481711773ae2
# ╟─e33dbeb8-cae9-418b-9e89-1e6563bd58a7
# ╠═e52bd27c-6263-4b65-9a60-5ddb31626881
# ╠═e0d1f2ca-ea96-4ae8-a3bd-cfabe92978d5
# ╠═7c23f010-5b76-44e0-ab8e-dd1eb8a01588
# ╠═e7a50a63-2312-43f0-b771-64452e33d808
# ╠═42904941-1859-4a05-a08c-a7a650f6b188
# ╠═0bc47362-3b76-44a8-8c52-2d0fa640a984
# ╠═b04a85a6-0fab-4a37-9b54-28dfbe9382aa
# ╟─f58a21b2-a940-49f8-a179-e0c2dd032579
# ╠═1d16c2fa-d9b3-4e4c-bafc-9edbe408f516
# ╠═321cc936-0ed3-4fcd-bf95-504f8529ef1b
# ╟─8704e62c-278c-4cf2-9b14-063b6ab3abd3
# ╠═ea479efe-0f65-4365-a136-14afdfb180e2
# ╠═612b0d4d-0a74-473d-89c9-f89333817b09
# ╠═b5f358cd-6475-4187-b248-68cc62cf55af
# ╠═0ef3370b-edfe-46f6-9fb6-81ce8e3d86b3
# ╠═24c36ac7-7ba6-4df1-9a90-2381b97362a2
# ╠═d0874885-447b-4aaa-8b2a-9c59ede4ac78
# ╠═a1413dd4-12c0-44e8-8981-79cb10d308dc
# ╠═e7714ae7-c473-44a6-9279-0374686495da
# ╠═481ab279-96bb-4a71-abb7-5df48b900e46
# ╠═b8f4214c-2e11-4fba-a9a9-439a672516c8
# ╠═c52d6a06-691f-49f1-9e5b-043429cba296
# ╟─0d8ddcb5-529e-4187-b257-9f8233abf656
# ╠═243bd190-6912-475f-870e-43f96656e9f6
# ╠═8b4577b3-8b23-4dbe-9d6f-9aec90849b60
# ╠═db755a0a-0a04-4fc2-bdfe-641a0b933575
# ╠═c1fa7658-6c71-4891-b82e-dd676c2f1b37
# ╠═8ca25ca4-3681-46d0-945a-2c99d20205b7
# ╠═eaa6def3-06fc-4646-a228-1f9180050ffc
# ╠═e32b8ed8-e50b-4b79-9f6d-119b6d2796dc
# ╠═66fd9e25-cb4a-410e-ae83-311fffb864c7
# ╠═adcb7667-cdff-4ba4-b59d-c2ece2f7ee31
# ╠═80a6d992-0e72-4c9f-a593-18a0fed09e1c
# ╟─85975780-6c17-4af9-a169-9fe906c1e369
# ╠═0ad6a808-692d-47e6-9e8f-1f721a38524e
# ╠═8a7548de-6e1e-442c-b5a7-b65a6af0efa4
# ╠═fbb0bf4c-2c91-47b2-8e61-c6c0a1085b27
# ╠═396542f6-737d-49ca-a3c9-41d319aa5cc7
# ╠═1c13b5c0-26d5-4220-9fca-fecd7c945c57
# ╠═062918a1-b84a-4c91-ba9e-7fe630582f63
# ╠═6ccc341f-fae8-4f18-b3a5-3528a101a8c1
# ╟─3bda0ed2-c721-4a8d-9beb-50fb0066b28e
# ╠═94423d38-dc7b-4a26-b0f0-0ed532c80e72
# ╠═a53efeb6-2676-4d13-b2b0-0da4089dbcc6
# ╠═fe9da092-9dd9-4304-96a7-1016cbdc4a5e
# ╠═26e90bdb-dfb3-4259-bb75-a037e86344fe

max_stars_repo_path: src/Module C - Applications/L13 Sparse plus Low-Rank Splitting.jl

max_stars_repo_name: ivanslapnicar/GIAN-Applied-NLA-Course

max_issues_repo_name: ivanslapnicar/GIAN-Applied-NLA-Course

max_forks_repo_name: ivanslapnicar/GIAN-Applied-NLA-Course


text:
using Clp

include(joinpath(Pkg.dir("MathProgBase"),"test","linprog.jl"))
linprogtest(ClpSolver(LogLevel=1))

include(joinpath(Pkg.dir("MathProgBase"),"test","linproginterface.jl"))
linprogsolvertest(ClpSolver())

include(joinpath(Pkg.dir("MathProgBase"),"test","conicinterface.jl"))
coniclineartest(ClpSolver())


text:
using REPL

is_continous_bell = false
bell_single_threshold_seconds = 10
bell_continuous_threshold_seconds = 60

cmd_start_time = time() # to avoid buzzing on reloadStartup

function repl_pre()
    global is_continous_bell
    global cmd_start_time = time() # Get the system time in seconds since the epoch
    if is_continous_bell
        okj()
        is_continous_bell = false
    end
end

function repl_post()
    global cmd_start_time
    global is_continous_bell
    dur = time() - cmd_start_time
    if dur >= bell_continuous_threshold_seconds
        bellj()
        is_continous_bell = true
    elseif dur >= bell_single_threshold_seconds
        bello()
    end
end

function repl_transform_prepost(ex)
    res_sym = gensym("res_sym") # the string will be included in the name, helpful for debugging?
    Expr(:toplevel, :($repl_pre()), :($res_sym = $ex),:($repl_post()),:($res_sym))
    # * Wouldn't using =$(esc(ex))= be better?
    # ** No. See [[id:1f926185-b593-480c-b6a7-f2ec5ed4ab5d][macros/hygiene]]
end

if ! @isdefined BELL_LOADED
    if isdefined(Base, :active_repl_backend)
        if VERSION >= v"1.5.0-DEV.282"
            pushfirst!(Base.active_repl_backend.ast_transforms, repl_transform_prepost)
        else
            # Unsupported
        end
    elseif isdefined(Main, :IJulia)
        # @untested
        Main.IJulia.push_preexecute_hook(repl_pre)
        Main.IJulia.push_postexecute_hook(repl_post)
    elseif VERSION >= v"1.5.0-DEV.282"
        pushfirst!(REPL.repl_ast_transforms, repl_transform_prepost)
    end
end
const BELL_LOADED = true


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

using Markdown
using InteractiveUtils

# ╔═╡ fdf6853c-ddbf-4fd6-b4ca-c65b52f5b036
begin
	using CairoMakie
	using CSV
	using DataFrames
	using MixedModels
	using MixedModelsMakie
	CairoMakie.activate!(type="svg")
end

# ╔═╡ 7bb303da-e728-11eb-3cef-4f96ce335414
md"""
# MixedModels fits to data from Dorothea Pregla
"""

# ╔═╡ 9dfed156-b4f9-4b60-bfee-d0b4bdba2682
md"""
Dorothea provided the data in CSV format with missing data indicated by "NA".

First load the packages to be used.
"""

# ╔═╡ d0bf71cb-4f4e-4402-82b6-a85b1c84a090
md"""
Read the data from the .csv file and convert to a DataFrame.
"""

# ╔═╡ 112a2d45-642a-4156-abfc-ec7377ba637e
df = CSV.File("../../Dorothea_Pregla/SPL_decl.csv", missingstring="NA") |> DataFrame
# or CSV.read("../../Dorothea_Pregla/SPL_decl.csv", DataFrame; missingstring="NA")

# ╔═╡ 7f491d16-0dc4-4acf-86d8-c72ccd13836f
md"""
#### Description of the columns: (as given in the .rmd file)

- subj: subject number
- item: number of the item (number of items: n=20)
- condition: a (canonical) and b (non-canonical), we did not use a latin square design, i.e., all participants saw both conditions of all items
- region: region in the sentence (0, 1, 2, 3, question)
  - 0: sentence onset ("hier")
  - 1: verb ("tröstet")
  - 2: NP1 ("der Tiger")
  - 3: adverb ("gerade")
  - question: NP2 + picture selection ("den Esel" + picture selection)
- subj_status: healthy control (HC) or individual with aphasia (IWA)
- sentence: the respective auditory presented sentence
- word: the respective word of the sentence
- rt: listening time for the respective region
- acc: picture selection accuracy
- age, sex, years of education: demographic data of the participant
- aphasia_type: Aachen aphasia test syndrome, NA for control participants
- digit_symbol_substitution: WAIS subtest, number of correct items in two minutes
- digit span, block span: WMS-R subtests, forward and backward raw scores and longest span
- picture span: working memory test, forward and backward raw scores and longest span
- lexdec: lexical decision task, mean reaction times in the task

The `subj` column is read as an integer.
Convert these values to strings.
I usually prepend the string with a character like `S` for subject and zero-pad the numbers so that sorting lexicographically is the same as sorting by numeric value.
"""

# ╔═╡ dabb1b1b-20cc-4644-a43b-2cae5a8d3222
df.subj = string.('S', lpad.(df.subj, ndigits(maximum(df.subj)), '0'));

# ╔═╡ b7cbf196-3071-45d8-8b5d-af25f981a553
describe(df)

# ╔═╡ ad91ad4a-c03a-4109-a445-75986c7a2164
md"""
### Initial model fit

In the .rmd file the contrasts for some of the variables are set by hand.
Here we will use a contrast specification as `EffectsCoding()` which produces -1/+1 coding for a two-level factor like :condition or :subj_status.

The initial model fit was for the subset of the data with `region == 2`.
"""

# ╔═╡ 4f21a265-7b53-4afc-bb6f-2442ef8a0540
m1 = fit(
	MixedModel,
	@formula(
		log(rt) ~
		1 + condition * subj_status +
		zerocorr(1 + condition * subj_status | item) +
		(1 + condition | subj)
	),
	filter(:region => ==("2"), df);
	contrasts = Dict(
		:subj => Grouping(),
		:item => Grouping(),
		:condition => EffectsCoding(),
		:subj_status => EffectsCoding(),
	),
	REML=true,
)

# ╔═╡ babe051a-40d1-48d2-ae28-8e6ed8e41af5
md"""
The REML criterion was used here to allow comparison with the `lmer` results.
The ML estimates are similar.
"""

# ╔═╡ 7cc1000d-fb72-4692-baca-a7001424e216
refit!(m1, REML=false)

# ╔═╡ 7f75d0e8-1cf4-4f82-ba81-6ff96de41315
md"""
Check that `condition`, `subj_status` and their interaction use the -1/+1 encoding.
"""

# ╔═╡ a09af6fd-d204-411f-b2ee-6712ce2b754d
Int.(m1.X')   # transpose of fixed-effects model matrix as integers (to save space)

# ╔═╡ 02cb5651-e0c9-4dec-9962-1191e4238674
md"""
The contrasts on `subj_status` and `condition` produce a +1/-1 coding and, if the data were balanced, these would give an `X'X` matrix which is diagonal.  (Even more, it would be a multiple of the identity, if you know what that expression means.)

In this case, the `subj_status` factor is observational rather than a controlled experimental factor and the levels are unbalanced.
"""

# ╔═╡ 5b704af5-8cb2-4ce4-8efe-1c32beb3b137
combine(groupby(filter(:region => ==("2"), df), :subj_status), nrow)

# ╔═╡ 356893dd-b0b4-4ffe-a3f7-0d37b62c1cce
md"resulting in some off-diagonal non-zeros in `X'X`"

# ╔═╡ abbe119c-0746-4a3d-afd2-ff669892423a
m1.X'm1.X

# ╔═╡ 51e4a5c2-6a46-4de2-9763-00705fe508de
md"""
### Some diagnostic plots

Despite years of effort we do not have a definitive way of deciding on a suitable random-effects structure.
One way of examining the "estimates" of the random effects (technically these are the conditional means of the random effects given the observed data but informally we can think of them as estimates), is to compare these values, which have been "shrunk" toward the origin, to what we would get if we did not apply any shrinkage.
"""

# ╔═╡ e261b642-ed8e-4c00-9ec5-b037e82af0e2
shrinkageplot(m1)

# ╔═╡ f7f6d39b-3ca0-48fe-b85d-6feaab5edf54
md"""
This plot indicates that the random effect for subject is strong, because there is very little horizontal shrinkage, but the random effect for condition by subject is much less important.

For the random effects by item
"""

# ╔═╡ 4b036283-2529-4225-86fd-d88b2c9a45c0
shrinkageplot(m1, :item)

# ╔═╡ 141bf8da-1d3e-4ac0-aeb9-67cf0c298a0b
md"""
the "implosion" patterns in the panels on the right indicate again that the random effects for condition and for `subj_status` by item are not substantial.

We can also examine the precision of the distribution of the random effects with a "caterpillar" plot (so-called because it can look like a fuzzy caterpillar).
These are marginal 95% prediction intervals on individual random effects.

When the number of levels of the grouping factor is moderate we present this plot with one row for each of the levels.  For definiteness in the plot we order the rows by increasing mean of one of the random effects terms - the first one by default.
"""

# ╔═╡ 579ca400-dac1-4988-b662-6a74dfa74841
caterpillar(m1, :item)

# ╔═╡ 3c7a1106-1c4d-4c32-b22e-c44e532f3d8e
md"""
In this plot all the intervals, except for `8retest` and `7test` on `(Intercept)`, contain zero.
This is evidence that the random effects for `condition`, `subj_status`, and their interaction by item are not terribly important.

Because a likelihood-ratio test comparing this model to `m2` that has only simple, scalar random effects for `item` gives a p-value of 47%, we prefer the simpler model, `m2`.
"""

# ╔═╡ 96278a24-e281-4801-a1f8-7f2899913c0d
m2 = fit(
	MixedModel,
	@formula(
		log(rt) ~
		1 + condition * subj_status +
		(1 | item) +
		(1 + condition | subj)
	),
	filter(:region => ==("2"), df);
	contrasts = Dict(
		:subj => Grouping(),
		:item => Grouping(),
		:condition => EffectsCoding(),
		:subj_status => EffectsCoding(),
	),
)

# ╔═╡ 2fb51bbe-1d07-4535-8520-14c58c47478c
MixedModels.likelihoodratiotest(m2, m1)

# ╔═╡ e58f70f5-36b1-45f7-83fe-f861fa806ba3
md"""
When the number of levels of the grouping factor is larger, the rows and the axis annotations become messy and we revert to a quantile-quantile type of plot with the vertical axis defined by quantiles of the standard Gaussian (or "normal") distribution.
For these `qqcaterpillar` plots the ordering of the intervals is determined separately for each panel.
"""

# ╔═╡ 06a8bb39-e030-4f04-a4c7-6b0755137c19
qqcaterpillar(m2)

# ╔═╡ d3b25e36-c042-4510-b8da-01a13b610b40
md"""
This plot shows that the random effects for subject are substantial, reflecting what we saw in the shrinkage plot, and a few of the random effects for condition by subject  have prediction intervals that do not overlap zero.
"""

# ╔═╡ 0d531471-076f-4e07-a7a9-9f2005d583be
sum(leverage(m2))

# ╔═╡ 5e72ae53-c55c-4800-aa01-97d2ffde18b7
sum(leverage(m1))

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316"
MixedModelsMakie = "b12ae82c-6730-437f-aff9-d2c38332a376"

[compat]
CSV = "~0.8.5"
CairoMakie = "~0.6.2"
DataFrames = "~1.2.0"
MixedModels = "~4.0.0"
MixedModelsMakie = "~0.3.2"
"""

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

julia_version = "1.6.2"
manifest_format = "2.0"

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

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

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

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

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

[[deps.Arrow]]
deps = ["ArrowTypes", "BitIntegers", "CodecLz4", "CodecZstd", "DataAPI", "Dates", "Mmap", "PooledArrays", "SentinelArrays", "Tables", "TimeZones", "UUIDs"]
git-tree-sha1 = "ca0abf8290cf219aa96a5c89c8210bbf498fecf2"
uuid = "69666777-d1a9-59fb-9406-91d4454c9d45"
version = "1.6.0"

[[deps.ArrowTypes]]
deps = ["UUIDs"]
git-tree-sha1 = "88f8d727e612e3cd5b91c6906b10f25e7821d8d4"
uuid = "31f734f8-188a-4ce0-8406-c8a06bd891cd"
version = "1.1.0"

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

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

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

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

[[deps.BitIntegers]]
deps = ["Random"]
git-tree-sha1 = "f0853a9d2cf2cf4f9fbd98c6e19ff1627e65a9a7"
uuid = "c3b6d118-76ef-56ca-8cc7-ebb389d030a1"
version = "0.2.4"

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

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

[[deps.CSV]]
deps = ["Dates", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode"]
git-tree-sha1 = "b83aa3f513be680454437a0eee21001607e5d983"
uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
version = "0.8.5"

[[deps.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"

[[deps.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"

[[deps.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"

[[deps.ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "0b0aa9d61456940511416b59a0e902c57b154956"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "0.10.12"

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

[[deps.CodecLz4]]
deps = ["Lz4_jll", "TranscodingStreams"]
git-tree-sha1 = "59fe0cb37784288d6b9f1baebddbf75457395d40"
uuid = "5ba52731-8f18-5e0d-9241-30f10d1ec561"
version = "0.4.0"

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

[[deps.CodecZstd]]
deps = ["TranscodingStreams", "Zstd_jll"]
git-tree-sha1 = "d19cd9ae79ef31774151637492291d75194fc5fa"
uuid = "6b39b394-51ab-5f42-8807-6242bab2b4c2"
version = "0.7.0"

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

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

[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "32a2b8af383f11cbb65803883837a149d10dfe8a"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.10.12"

[[deps.ColorVectorSpace]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "StatsBase"]
git-tree-sha1 = "4d17724e99f357bfd32afa0a9e2dda2af31a9aea"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.8.7"

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

[[deps.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"

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

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

[[deps.Crayons]]
git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.0.4"

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

[[deps.DataFrames]]
deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Reexport", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
git-tree-sha1 = "1dadfca11c0e08e03ab15b63aaeda55266754bad"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.2.0"

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

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

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

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

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

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

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

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

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

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

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

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

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

[[deps.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"

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

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

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

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

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

[[deps.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"

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

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

[[deps.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"

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

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

[[deps.Future]]
deps = ["Random"]
uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"

[[deps.GLM]]
deps = ["Distributions", "LinearAlgebra", "Printf", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "StatsModels"]
git-tree-sha1 = "f564ce4af5e79bb88ff1f4488e64363487674278"
uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
version = "1.5.1"

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

[[deps.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"

[[deps.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"

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

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

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

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

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

[[deps.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"

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

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

[[deps.ImageIO]]
deps = ["FileIO", "Netpbm", "PNGFiles"]
git-tree-sha1 = "0d6d09c28d67611c68e25af0c2df7269c82b73c7"
uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
version = "0.4.1"

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

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

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

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

[[deps.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"

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

[[deps.InvertedIndices]]
deps = ["Test"]
git-tree-sha1 = "15732c475062348b0165684ffe28e85ea8396afc"
uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f"
version = "1.0.0"

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

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

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

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

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

[[deps.JSON3]]
deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"]
git-tree-sha1 = "e13a411f59a3f9ad25378b25a40ea08c2ded02e7"
uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
version = "1.9.0"

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

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

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

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

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

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

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

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

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

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

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

[[deps.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"

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

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

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

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

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

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

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

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

[[deps.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"

[[deps.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"

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

[[deps.MappedArrays]]
git-tree-sha1 = "18d3584eebc861e311a552cbb67723af8edff5de"
uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
version = "0.4.0"

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

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

[[deps.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"

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

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

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

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

[[deps.MixedModels]]
deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"]
git-tree-sha1 = "c17a2cdb285cf936920855e48e198e4f25fcef5c"
uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316"
version = "4.0.0"

[[deps.MixedModelsMakie]]
deps = ["DataFrames", "LinearAlgebra", "Makie", "MixedModels", "SpecialFunctions"]
git-tree-sha1 = "126f059a16e8ae01f3199982a5062e1e98856c38"
uuid = "b12ae82c-6730-437f-aff9-d2c38332a376"
version = "0.3.2"

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

[[deps.Mocking]]
deps = ["ExprTools"]
git-tree-sha1 = "916b850daad0d46b8c71f65f719c49957e9513ed"
uuid = "78c3b35d-d492-501b-9361-3d52fe80e533"
version = "0.7.1"

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

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

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

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

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

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

[[deps.Netpbm]]
deps = ["ColorVectorSpace", "FileIO", "ImageCore"]
git-tree-sha1 = "09589171688f0039f13ebe0fdcc7288f50228b52"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.1"

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

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

[[deps.OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "4f825c6da64aebaa22cc058ecfceed1ab9af1c7e"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.3"

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

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

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

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

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

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

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

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

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

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

[[deps.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"

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

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

[[deps.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"

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

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

[[deps.PooledArrays]]
deps = ["DataAPI", "Future"]
git-tree-sha1 = "cde4ce9d6f33219465b55162811d8de8139c0414"
uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720"
version = "1.2.1"

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

[[deps.PrettyTables]]
deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"]
git-tree-sha1 = "0d1245a357cc61c8cd61934c07447aa569ff22e6"
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
version = "1.1.0"

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

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

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

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

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

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

[[deps.RecipesBase]]
git-tree-sha1 = "b3fb709f3c97bfc6e948be68beeecb55a0b340ae"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.1"

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

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

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

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

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

[[deps.SentinelArrays]]
deps = ["Dates", "Random"]
git-tree-sha1 = "ffae887d0f0222a19c406a11c3831776d1383e3d"
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
version = "1.3.3"

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

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

[[deps.ShiftedArrays]]
git-tree-sha1 = "22395afdcf37d6709a5a0766cc4a5ca52cb85ea0"
uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a"
version = "1.0.0"

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

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

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

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

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

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

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

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

[[deps.StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "1b9a0f17ee0adde9e538227de093467348992397"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.7"

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

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

[[deps.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"

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

[[deps.StatsModels]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Printf", "ShiftedArrays", "SparseArrays", "StatsBase", "StatsFuns", "Tables"]
git-tree-sha1 = "dfdf16cc1e531e154c7e62cd42d531e00f8d100e"
uuid = "3eaba693-59b7-5ba5-a881-562e759f1c8d"
version = "0.6.23"

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

[[deps.StructTypes]]
deps = ["Dates", "UUIDs"]
git-tree-sha1 = "e36adc471280e8b346ea24c5c87ba0571204be7a"
uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"
version = "1.7.2"

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

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

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

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

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

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

[[deps.TimeZones]]
deps = ["Dates", "Future", "LazyArtifacts", "Mocking", "Pkg", "Printf", "RecipesBase", "Serialization", "Unicode"]
git-tree-sha1 = "81753f400872e5074768c9a77d4c44e70d409ef0"
uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53"
version = "1.5.6"

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

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

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

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

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

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

[[deps.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"

[[deps.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"

[[deps.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"

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

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

[[deps.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"

[[deps.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"

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

[[deps.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"

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

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

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

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

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

[[deps.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"

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

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

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

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

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

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

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

# ╔═╡ Cell order:
# ╟─7bb303da-e728-11eb-3cef-4f96ce335414
# ╟─9dfed156-b4f9-4b60-bfee-d0b4bdba2682
# ╠═fdf6853c-ddbf-4fd6-b4ca-c65b52f5b036
# ╟─d0bf71cb-4f4e-4402-82b6-a85b1c84a090
# ╠═112a2d45-642a-4156-abfc-ec7377ba637e
# ╟─7f491d16-0dc4-4acf-86d8-c72ccd13836f
# ╠═dabb1b1b-20cc-4644-a43b-2cae5a8d3222
# ╠═b7cbf196-3071-45d8-8b5d-af25f981a553
# ╟─ad91ad4a-c03a-4109-a445-75986c7a2164
# ╠═4f21a265-7b53-4afc-bb6f-2442ef8a0540
# ╟─babe051a-40d1-48d2-ae28-8e6ed8e41af5
# ╠═7cc1000d-fb72-4692-baca-a7001424e216
# ╟─7f75d0e8-1cf4-4f82-ba81-6ff96de41315
# ╠═a09af6fd-d204-411f-b2ee-6712ce2b754d
# ╟─02cb5651-e0c9-4dec-9962-1191e4238674
# ╠═5b704af5-8cb2-4ce4-8efe-1c32beb3b137
# ╟─356893dd-b0b4-4ffe-a3f7-0d37b62c1cce
# ╠═abbe119c-0746-4a3d-afd2-ff669892423a
# ╟─51e4a5c2-6a46-4de2-9763-00705fe508de
# ╠═e261b642-ed8e-4c00-9ec5-b037e82af0e2
# ╟─f7f6d39b-3ca0-48fe-b85d-6feaab5edf54
# ╠═4b036283-2529-4225-86fd-d88b2c9a45c0
# ╟─141bf8da-1d3e-4ac0-aeb9-67cf0c298a0b
# ╠═579ca400-dac1-4988-b662-6a74dfa74841
# ╟─3c7a1106-1c4d-4c32-b22e-c44e532f3d8e
# ╠═96278a24-e281-4801-a1f8-7f2899913c0d
# ╠═2fb51bbe-1d07-4535-8520-14c58c47478c
# ╟─e58f70f5-36b1-45f7-83fe-f861fa806ba3
# ╠═06a8bb39-e030-4f04-a4c7-6b0755137c19
# ╟─d3b25e36-c042-4510-b8da-01a13b610b40
# ╠═0d531471-076f-4e07-a7a9-9f2005d583be
# ╠═5e72ae53-c55c-4800-aa01-97d2ffde18b7
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
using DelimitedFiles
using WriteVTK
using MeshCore: AbsShapeDesc, P1, L2, T3, Q4, T4, H8
using MeshCore: VecAttrib
using MeshCore: shapedesc, nshapes, IncRel
using MeshCore: ShapeColl
using LinearAlgebra: norm

"""
    T4blockx(xs::Vector{T}, ys::Vector{T}, zs::Vector{T}, orientation::Symbol) where {T}

Generate a graded tetrahedral mesh  of a 3D block.

Four-node tetrahedra in a regular arrangement, with non-uniform given spacing
between the nodes, with a given orientation of the diagonals.
The mesh is produced by splitting each logical  rectangular cell into a certain number of
tetrahedra. Orientation may be chosen as `:a`, `:b` (six tetrahedra per rectangular cell),
or `:ca` or `:cb` (five tetrahedra per rectangular cell). Keyword argument

# Return
By convention the function returns an incidence relation (`connectivity`)
between the elements (`connectivity.left`) and the vertices
(`connectivity.right`). The geometry is stored as the attribute "geom" of the
vertices.
"""
function T4blockx(xs::Vector{T}, ys::Vector{T}, zs::Vector{T}, orientation::Symbol; intbytes = 8) where {T}
    inttype = Int64
    if intbytes == 4
        inttype = Int32
    end
    nL = length(xs)-1;
    nW = length(ys)-1;
    nH = length(zs)-1;
    nnodes = (nL+1)*(nW+1)*(nH+1);
    ncells = 6*(nL)*(nW)*(nH);
    xyzs = zeros(T, nnodes, 3);
    conns = zeros(inttype, ncells, 4);
    if (orientation==:a)
        t4ia = inttype[1  8  5  6; 3  4  2  7; 7  2  6  8; 4  7  8  2; 2  1  6  8; 4  8  1  2];
        t4ib =  inttype[1  8  5  6; 3  4  2  7; 7  2  6  8; 4  7  8  2; 2  1  6  8; 4  8  1  2];
    elseif (orientation==:b)
        t4ia = inttype[2 7 5 6; 1 8 5 7; 1 3 4 8; 2 1 5 7; 1 2 3 7; 3 7 8 1];
        t4ib =  [2 7 5 6; 1 8 5 7; 1 3 4 8; 2 1 5 7; 1 2 3 7; 3 7 8 1];
    elseif (orientation==:ca)
        t4ia = inttype[8  4  7  5; 6  7  2  5; 3  4  2  7; 1  2  4  5; 7  4  2  5];
        t4ib = inttype[7  3  6  8; 5  8  6  1; 2  3  1  6; 4  1  3  8; 6  3  1  8];
    elseif (orientation==:cb)
        t4ia = inttype[7  3  6  8; 5  8  6  1; 2  3  1  6; 4  1  3  8; 6  3  1  8];
        t4ib = inttype[8  4  7  5; 6  7  2  5; 3  4  2  7; 1  2  4  5; 7  4  2  5];
    else
        error("Unknown orientation")
    end

    f=1;
    for k=1:(nH+1)
        for j=1:(nW+1)
            for i=1:(nL+1)
                xyzs[f, 1] = xs[i]
                xyzs[f, 2] = ys[j]
                xyzs[f, 3] = zs[k];
                f=f+1;
            end
        end
    end

    function node_numbers(i, j, k, nL, nW, nH)
        f=(k-1)*((nL+1)*(nW+1))+(j-1)*(nL+1)+i;
        nn=[f (f+1)  f+(nL+1)+1 f+(nL+1)];
        return inttype[nn broadcast(+, nn, (nL+1)*(nW+1))];
    end

    gc=1;
    for i=1:nL
        for j=1:nW
            for k=1:nH
                nn=node_numbers(i, j, k, nL, nW, nH);
                if (mod(sum( [i, j, k] ), 2)==0)
                    t4i =t4ib;
                else
                    t4i =t4ia;
                end
                for r=1:size(t4i, 1)
                    for c1=1:size(t4i, 2)
                        conns[gc, c1] = nn[t4i[r, c1]];
                    end
                    gc=gc+1;
                end
            end
        end
    end

    C = inttype.(conns[1:gc-1, :]);
    N, TC = size(xyzs, 2), eltype(xyzs)
    locs =  VecAttrib([SVector{N, TC}(xyzs[i, :]) for i in 1:size(xyzs, 1)])
    vertices = ShapeColl(P1, length(locs), "vertices")
    vertices.attributes["geom"] = locs
    elements = ShapeColl(T4, size(C, 1), "elements")
    return IncRel(elements, vertices, C)
end

"""
    T4block(Length, Width, Height, nL, nW, nH, orientation = :a)

Generate a tetrahedral mesh  of the 3D block.

Four-node tetrahedra in a regular arrangement, with uniform spacing between
the nodes, with a given orientation of the diagonals.
The mesh is produced by splitting each logical  rectangular cell into six
tetrahedra. Range =<0, Length> x <0, Width> x <0, Height>.
Divided into elements: nL,  nW,  nH in the first,  second,  and
third direction (x, y, z).

See also: T4blockx
"""
function T4block(Length, Width, Height, nL, nW, nH, orientation = :a; kwargs...)
    return T4blockx(collect(linearspace(0.0, Length, nL+1)),
                    collect(linearspace(0.0, Width, nW+1)),
                    collect(linearspace(0.0, Height, nH+1)), orientation; kwargs...);
end