text:
# reweighting functions

"""
    w_exp(shift, h, dτ; E_r = mean(shift), skip = 0)
Compute the weights for reweighting over `h` time steps with reference energy `E_r` from
the exponential formula
```math
w_h^{(n)} = \\prod_{j=1}^h \\exp[-dτ(S^{(q+n-j)}-E_r)] ,
```
where `q = skip`.

See also [`w_lin()`](@ref), [`growth_estimator()`](@ref),
[`mixed_estimator()`](@ref).
"""
@inline function w_exp(shift, h, dτ; E_r = mean(shift), skip = 0)
    T = promote_type(eltype(shift),typeof(E_r))
    len = length(shift)-skip
    accu = Vector{T}(undef, len)
    @inbounds for n in 1:len
        a = zero(T)
        look_back = min(h,skip+n-1)
        @simd ivdep for j in 1:look_back # makes it very fast
            a += shift[skip+n-j] - E_r
        end
        accu[n] = exp(-dτ*a)
    end
    return accu
end

"""
    w_lin(shift, h, dτ; E_r = mean(shift), skip = 0)
Compute the weights for reweighting over `h` time steps with reference energy `E_r` from
the linearised formula
```math
w_h^{(n)} = \\prod_{j=1}^h [1-dτ(S^{(q+n-j)}-E_r)] ,
```
where `q = skip`.

See also [`w_exp()`](@ref), [`growth_estimator()`](@ref),
[`mixed_estimator()`](@ref).
"""
@inline function w_lin(shift, h, dτ; E_r = mean(shift), skip = 0)
    T = promote_type(eltype(shift),typeof(E_r))
    len = length(shift)-skip
    accu = ones(T, len)
    @inbounds for n in 1:len
        a = one(T)
        look_back = min(h,skip+n-1)
        @simd ivdep for j in 1:look_back
            a *= 1 - dτ*(shift[skip+n-j] - E_r)
        end
        accu[n] = a
    end
    return accu
end

"""
    growth_estimator(
        shift, wn, h, dτ;
        skip = 0,
        E_r = mean(shift[skip+1:end]),
        weights = w_exp,
        change_type = identity,
        kwargs...,
    ) -> r::RatioBlockingResult
Compute the growth estimator with reference energy `E_r` by the reweighting
technique described in [Umirgar *et al.* (1993)](http://dx.doi.org/10.1063/1.465195),
see Eq. (20).
`shift` and `wn` are equal length
vectors containing the shift and walker number time series, respectively.
Reweighting is done over `h`
time steps and `length(shift) - skip` time steps are used for the blocking analysis done
with [`ratio_of_means()`](@ref). `dτ` is the time step and `weights` a function that
calulates the weights. See [`w_exp()`](@ref) and [`w_lin()`](@ref).
```math
E_{gr} = E_r - \\frac{1}{dτ}\\ln
    \\frac{\\sum_n w_{h+1}^{(n+1)} N_\\mathrm{w}^{(n+1)}}
        {\\sum_m w_{h}^{(m)} N_\\mathrm{w}^{(m)}}
```
When `h` is greater than the autocorrelation time scale of the `shift`,
then `E_gr` (returned as `r.ratio`) is an unbiased but approximate estimator for the ground
state energy ``E_0`` with an error ``\\mathcal{O}(dτ^2)`` and potentially increased
confidence intervals compared to the (biased) shift estimator.
Error propagation is done with [`MonteCarloMeasurements`](@ref). Progagation through the
logarithm can be modified by setting `change_type` to [`to_measurement`](@ref) in order
to avoid `NaN` results from negative outliers.

If `success==true` the
blocking analysis was successful in `k-1` steps, using `blocks` uncorrelated data points.

See also [`mixed_estimator()`](@ref) and [`RatioBlockingResult`](@ref).
"""
function growth_estimator(
    shift, wn, h, dτ;
    skip = 0,
    E_r = mean(view(shift, skip+1:length(shift))),
    weights = w_exp,
    change_type = identity,
    mc_samples = nothing,
    kwargs...,
)
    T = promote_type(eltype(shift), eltype(wn))
    # W_{t+1}^{(n+1)} .* wn^{(n+1)}
    @views numerator = weights(shift[2:end], h+1, dτ; E_r, skip) .* wn[skip+2:end]
    # W_{t}^{(n)} .* wn^{(n)}
    @views denominator = weights(shift[1:end-1], h, dτ; E_r, skip) .* wn[skip+1:end-1]
    rbr = ratio_of_means(numerator, denominator; mc_samples, kwargs...)
    r = rbr.ratio::MonteCarloMeasurements.Particles{T,<:Any}
    r = change_type(r)
    E_gr = E_r - log(r)/dτ # MonteCarloMeasurements propagates the uncertainty
    E_gr_f = E_r - log(Measurements.measurement(rbr.f, rbr.σ_f))/dτ # linear error prop
    return RatioBlockingResult(
        particles(mc_samples, E_gr),
        Measurements.value(E_gr_f),
        Measurements.uncertainty(E_gr_f),
        rbr.δ_y,
        rbr.k,
        rbr.blocks,
        rbr.success
    )
    # return (; E_gr, k=rbr.k, blocks = rbr.blocks, success = rbr.success)
end
"""
    growth_estimator(df::DataFrame, h; shift=:shift, norm=:norm, dτ=df.dτ[end], kwargs...)
Calculate the growth estimator directly from a `DataFrame` returned by
[`lomc!`](@ref). The keyword arguments `shift` and `norm`
can be used to change the names of the relevant columns.
"""
function growth_estimator(
        df::DataFrame, h;
        shift=:shift, norm=:norm, dτ=df.dτ[end], kwargs...
)
    shift_vec = getproperty(df, Symbol(shift))
    norm_vec = getproperty(df, Symbol(norm))
    return growth_estimator(shift_vec, norm_vec, h, dτ; kwargs...)
end

"""
    mixed_estimator(
        hproj, vproj, shift, h, dτ;
        skip = 0,
        E_r = mean(shift[skip+1:end]),
        weights = w_exp,
        kwargs...,
    ) -> r::RatioBlockingResult
Compute the mixed estimator by the reweighting
technique described in [Umirgar *et al.* (1993)](http://dx.doi.org/10.1063/1.465195),
Eq. (19)
```math
E_\\mathrm{mix} = \\frac{\\sum_n w_{h}^{(n)}  (Ĥ'\\mathrm{v})⋅\\mathrm{c}^{(n)}}
        {\\sum_m w_{h}^{(m)}  \\mathrm{v}⋅\\mathrm{c}^{(m)}} ,
```
where the time series `hproj ==` ``(Ĥ'\\mathrm{v})⋅\\mathrm{c}^{(n)}`` and
`vproj ==` ``\\mathrm{v}⋅\\mathrm{c}^{(m)}`` have the same length as `shift`
(See [`ProjectedEnergy`](@ref) on how to set these up).
Reweighting is done over `h`
time steps and `length(shift) - skip` time steps are used for the blocking analysis done
with [`ratio_of_means()`](@ref). `dτ` is the time step and `weights` a function that
calulates the weights. See [`w_exp()`](@ref) and [`w_lin()`](@ref).
Additional keyword arguments are passed on to [`ratio_of_means()`](@ref).

When `h` is greater than the autocorrelation time scale of the `shift`,
then `r.ratio` is an unbiased but approximate estimator for the ground state energy
``E_0`` with an error ``\\mathcal{O}(dτ^2)`` and potentially increased confidence intervals
compared to the unweighted ratio.
Error propagation is done with [`MonteCarloMeasurements`](@ref).
Results are returned as [`RatioBlockingResult`](@ref).

See also [`growth_estimator()`](@ref).
"""
function mixed_estimator(
    hproj, vproj, shift, h, dτ;
    skip = 0,
    E_r = mean(view(shift, skip+1:length(shift))),
    weights = w_exp,
    kwargs...,
)
    @views num = weights(shift, h, dτ; E_r, skip) .* hproj[skip+1:end]
    @views denom = weights(shift, h, dτ; E_r, skip) .* vproj[skip+1:end]
    return ratio_of_means(num, denom; kwargs...)
end
"""
    mixed_estimator(
        df::DataFrame, h;
        hproj=:hproj, vproj=:vproj, shift=:shift, dτ=df.dτ[end], kwargs...
    )
Calculate the mixed energy estimator directly from a `DataFrame` returned by
[`lomc!`](@ref). The keyword arguments `hproj`, `vproj`, and `shift`
can be used to change the names of the relevant columns.
"""
function mixed_estimator(
    df::DataFrame, h;
    hproj = :hproj, vproj = :vproj, shift = :shift, dτ=df.dτ[end], kwargs...
)
    hproj_vec = getproperty(df, Symbol(hproj))
    vproj_vec = getproperty(df, Symbol(vproj))
    shift_vec = getproperty(df, Symbol(shift))
    return mixed_estimator(hproj_vec, vproj_vec, shift_vec, h, dτ; kwargs...)
end

"""
    projected_energy(
        df::DataFrame;
        skip=0, hproj=:hproj, vproj=:vproj, kwargs...
    ) -> r::RatioBlockingResult
Compute the projected energy estimator
```math
E_\\mathrm{p} = \\frac{\\sum_n  \\mathrm{v}⋅Ĥ\\mathrm{c}^{(n)}}
        {\\sum_m \\mathrm{v}⋅\\mathrm{c}^{(m)}} ,
```
where the time series `df.hproj ==` ``\\mathrm{v}⋅Ĥ\\mathrm{c}^{(n)}`` and
`df.vproj ==` ``\\mathrm{v}⋅\\mathrm{c}^{(m)}`` are taken from `df`, skipping the first
`skip` entries (use `post_step = `[`ProjectedEnergy()`](@ref) to set these up in
[`lomc!()`](@ref)).
`projected_energy` is equivalent to [`mixed_estimator`](@ref) with `h=0`.

The keyword arguments `hproj` and `vproj`
can be used to change the names of the relevant columns. Other `kwargs` are
passed on to [`ratio_of_means`](@ref).
Returns a [`RatioBlockingResult`](@ref).

See [`NamedTuple`](@ref), [`val_and_errs`](@ref), [`val`](@ref), [`errs`](@ref) for
processing results.
"""
function projected_energy(df::DataFrame; skip=0, hproj=:hproj, vproj=:vproj, kwargs...)
    hproj_vec = getproperty(df, Symbol(hproj))
    vproj_vec = getproperty(df, Symbol(vproj))
    return @views ratio_of_means(hproj_vec[skip+1:end], vproj_vec[skip+1:end]; kwargs...)
end

"""
    shift_estimator(df::DataFrame; shift=:shift, kwargs...) -> r::BlockingResult
Return the shift estimator from the data in `df.shift`. The keyword argument `shift`
can be used to change the name of the relevant column. Other keyword arguments are passed
on to [`blocking_analysis`](@ref). Returns a [`BlockingResult`](@ref).

See also [`growth_estimator`](@ref), [`projected_energy`](@ref).
"""
function shift_estimator(df::DataFrame; shift=:shift, kwargs...)
    shift_vec = getproperty(df, Symbol(shift))
    return blocking_analysis(shift_vec; kwargs...)
end


text:
"""
Module UniformQuadMesh

Includes mesh related utility functions
"""

module UniformQuadMesh

using SparseArrays
using CommonUtils # for meshgrid

export uniform_quad_mesh
export quad_face_vertices

"""
uniform_quad_mesh(Kx::Int,Ky::Int)

Matlab uniform triangular mesh.

# Examples
```jldoctest
```
"""

function uniform_quad_mesh(Nx,Ny)

        Nxp = Nx+1;
        Nyp = Ny+1;
        Nv = convert(Int,Nxp*Nyp);
        K = convert(Int,Nx*Ny);

        x1D = LinRange(-1,1,Nxp);
        y1D = LinRange(-1,1,Nyp);
        x, y = meshgrid(x1D,y1D);
        I, J = meshgrid(collect(1:Nxp),collect(1:Nyp));
        inds = @. (I-1)*Ny + (J+I-1);
        EToV = zeros(Int,K,4);
        k = 1;
        for i = 1:Ny
                for j = 1:Nx
                        EToV[k,:] = [inds[i,j] inds[i,j+1] inds[i+1,j] inds[i+1,j+1]];
                        k += 1;
                end
        end

        VX = x[:];
        VY = y[:];

        return VX[:],VY[:],EToV
end

function uniform_quad_mesh(Kx)
        return uniform_quad_mesh(Kx,Ky)
end

"""
connect_2D(EToV)

Initialize quad elements connectivity matrices, element to element and
element to face connectivity.

# Examples
```jldoctest
"""

# ordering matters...
function quad_face_vertices()
        return [1,2],[2,4],[3,4],[1,3]
end

end

ext: jl

max_stars_repo_name: jlchan/ESDG-CNS

max_issues_repo_name: jlchan/ESDG-CNS

max_forks_repo_name: jlchan/ESDG-CNS


text:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Description
# ==============================================================================
#
#   Tests related to orbit representations.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# References
# ==============================================================================
#
#   [1] Vallado, D. A (2013). Fundamentals of Astrodynamics and Applications.
#       Microcosm Press, Hawthorn, CA, USA.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# File: ./src/orbit/representations/rv.jl
# =======================================

# Functions: kepler_to_rv and rv_to_kepler
# ----------------------------------------

################################################################################
#                                 TEST RESULTS
################################################################################
#
# Scenario 01
# ===========
#
# Example 2-5: Finding position and velocity vectors (COE2RV Test Case) [1, p.
# 119-120].
#
# Cartesian representation:
#
#     r = 6525.344    I + 6861.535    J + 6449.125    K km
#     v =    4.902276 I +    5.533124 J -    1.975709 K km
#
# Orbit elements
#
#     ╔═════════════════╦══════════════╗
#     ║    Parameter    ║    Values    ║
#     ╠═════════════════╬══════════════╣
#     ║ p               ║ 11067.790 km ║
#     ║ Eccentricity    ║ 0.83285      ║
#     ║ Inclination     ║ 87.87°       ║
#     ║ RAAN            ║ 227.89°      ║
#     ║ Arg. of Perigee ║ 53.38°       ║
#     ║ True Anomaly    ║ 92.335°      ║
#     ╚═════════════════╩══════════════╝
#
################################################################################

@testset "Function kepler_to_rv and rv_to_kepler" begin

    # Float64
    # ==========================================================================

    let
        ## kepler_to_rv
        ## ============

        p    = 11067.790 * 1000
        e    = 0.83285
        i    = 87.87  * π / 180
        RAAN = 227.89 * π / 180
        w    = 53.38  * π / 180
        f    = 92.335 * π / 180
        a    = p / (1 - e^2)

        r_i, v_i = kepler_to_rv(a, e, i, RAAN, w, f)

        @test r_i[1] / 1000 ≈ +6525.344 atol=5e-2
        @test r_i[2] / 1000 ≈ +6861.535 atol=5e-2
        @test r_i[3] / 1000 ≈ +6449.125 atol=5e-2
        @test eltype(r_i) == Float64

        @test v_i[1] / 1000 ≈ +4.902276 atol=1e-4
        @test v_i[2] / 1000 ≈ +5.533124 atol=1e-4
        @test v_i[3] / 1000 ≈ -1.975709 atol=1e-4
        @test eltype(v_i) == Float64

        ## rv_to_kepler
        ## ============

        r_i = [6525.344; 6861.535; 6449.125] * 1000
        v_i = [4.902276; 5.533124; -1.975709] * 1000

        oe = rv_to_kepler(r_i..., v_i...)

        a, e, i, RAAN, w, f = oe.a, oe.e, oe.i, oe.Ω, oe.ω, oe.f
        p = a * (1 - e^2)

        @test p / 1000       ≈ 11067.790 atol=5e-2
        @test e              ≈ 0.83285   atol=1e-5
        @test i    * 180 / π ≈ 87.87     atol=1e-2
        @test RAAN * 180 / π ≈ 227.89    atol=1e-2
        @test w    * 180 / π ≈ 53.38     atol=1e-2
        @test f    * 180 / π ≈ 92.335    atol=1e-3
        @test oe.a isa Float64
    end

    # Float32
    # ==========================================================================

    let
        ## kepler_to_rv
        ## ============

        p    = 11067.790f0 * 1000
        e    = 0.83285f0
        i    = 87.87f0  * Float32(π / 180)
        RAAN = 227.89f0 * Float32(π / 180)
        w    = 53.38f0  * Float32(π / 180)
        f    = 92.335f0 * Float32(π / 180)
        a    = p / (1 - e^2)

        r_i, v_i = kepler_to_rv(a, e, i, RAAN, w, f)

        @test r_i[1] / 1000 ≈ +6525.344 atol=5e-2
        @test r_i[2] / 1000 ≈ +6861.535 atol=5e-2
        @test r_i[3] / 1000 ≈ +6449.125 atol=5e-2
        @test eltype(r_i) == Float32

        @test v_i[1] / 1000 ≈ +4.902276 atol=1e-4
        @test v_i[2] / 1000 ≈ +5.533124 atol=1e-4
        @test v_i[3] / 1000 ≈ -1.975709 atol=1e-4
        @test eltype(v_i) == Float32

        ## rv_to_kepler
        ## ============

        r_i = [6525.344f0; 6861.535f0; 6449.125f0]  * 1000
        v_i = [4.902276f0; 5.533124f0; -1.975709f0] * 1000

        oe = rv_to_kepler(r_i..., v_i...)

        a, e, i, RAAN, w, f = oe.a, oe.e, oe.i, oe.Ω, oe.ω, oe.f
        p = a * (1 - e^2)

        @test p / 1000       ≈ 11067.790 atol=5e-2
        @test e              ≈ 0.83285   atol=1e-5
        @test i * 180 / π    ≈ 87.87     atol=1e-2
        @test RAAN * 180 / π ≈ 227.89    atol=1e-2
        @test w * 180 / π    ≈ 53.38     atol=1e-2
        @test f * 180 / π    ≈ 92.335    atol=1e-3
        @test oe.a isa Float32
    end
end

@testset "Issue #25 - Special cases in kepler_to_rv" begin
    # Circular and equatorial
    # =======================

	orb_i = KeplerianElements(0.0, 42164e3, 0, 0, 0, 0, 0 )
    orb_o = sv_to_kepler( kepler_to_sv( orb_i ) )
	orb_e = KeplerianElements(0.0, 42164e3, 0, 0, 0, 0, 0 )

    @test orb_o.a ≈ orb_e.a   atol = 1e-7
    @test orb_o.e ≈ orb_e.e   atol = 1e-7
    @test orb_o.i ≈ orb_e.i   atol = 1e-7
    @test orb_o.Ω ≈ orb_e.Ω   atol = 1e-7
    @test orb_o.ω ≈ orb_e.ω   atol = 1e-7
    @test orb_o.f ≈ orb_e.f   atol = 1e-7

	orb_i = KeplerianElements(0.0, 42164e3, 0, 0, 10*π/180, 11*π/180, 12*π/180 )
    orb_o = sv_to_kepler( kepler_to_sv( orb_i ) )
    orb_e = KeplerianElements(0.0, 42164e3, 0, 0, 0, 0, (10+11+12)*π/180 )

    @test orb_o.a ≈ orb_e.a   atol = 1e-7
    @test orb_o.e ≈ orb_e.e   atol = 1e-7
    @test orb_o.i ≈ orb_e.i   atol = 1e-7
    @test orb_o.Ω ≈ orb_e.Ω   atol = 1e-7
    @test orb_o.ω ≈ orb_e.ω   atol = 1e-7
    @test orb_o.f ≈ orb_e.f   atol = 1e-7

    # Elliptical equatorial
    # =====================

    orb_i = KeplerianElements(0.0, 42164e3, 0.05, 0, 10*π/180, 11*π/180, 12*π/180 )
    orb_o = sv_to_kepler( kepler_to_sv( orb_i ) )
    orb_e = KeplerianElements(0.0, 42164e3, 0.05, 0, 0, (10+11)*π/180, 12*π/180 )

    @test orb_o.a ≈ orb_e.a   atol = 1e-7
    @test orb_o.e ≈ orb_e.e   atol = 1e-7
    @test orb_o.i ≈ orb_e.i   atol = 1e-7
    @test orb_o.Ω ≈ orb_e.Ω   atol = 1e-7
    @test orb_o.ω ≈ orb_e.ω   atol = 1e-7
    @test orb_o.f ≈ orb_e.f   atol = 1e-7

    # Circular inclined
    # =================

    orb_i = KeplerianElements(0.0, 42164e3, 0, π/4, 10*π/180, 11*π/180, 12*π/180 )
    orb_o = sv_to_kepler( kepler_to_sv( orb_i ) )
    orb_e = KeplerianElements(0.0, 42164e3, 0, π/4, 10*π/180, 0, (11+12)*π/180 )

    @test orb_o.a ≈ orb_e.a   atol = 1e-7
    @test orb_o.e ≈ orb_e.e   atol = 1e-7
    @test orb_o.i ≈ orb_e.i   atol = 1e-7
    @test orb_o.Ω ≈ orb_e.Ω   atol = 1e-7
    @test orb_o.ω ≈ orb_e.ω   atol = 1e-7
    @test orb_o.f ≈ orb_e.f   atol = 1e-7
end

@testset "Issue #72 - Bug with elliptical and equatorial orbit" begin
    a = 6674.790266053491 * 1000
    e = 0.0055622826070485095
    i = 0.0 |> deg2rad
    Ω = 0.0 |> deg2rad
    ω = 330.27258118831503 |> deg2rad
    f = 42.80749332919855 |> deg2rad

    rr, vv = kepler_to_rv(a, e, i, Ω, ω, f)

    oe = rv_to_kepler(rr, vv, 0)

    @test oe.a ≈ a atol = 1e-7
    @test oe.e ≈ e atol = 1e-7
    @test oe.i ≈ i atol = 1e-7
    @test oe.Ω ≈ Ω atol = 1e-7
    @test oe.ω ≈ ω atol = 1e-7
    @test oe.f ≈ f atol = 1e-7
end


text:
using Nettle
using Base.Test
using Compat

include("hash_tests.jl")
include("hmac_tests.jl")
include("cipher_tests.jl")


text:
# GLOBALS that should be set
println("Running comment script")

# Set plot globals
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"

println("Defining functions")

# Stolen from https://discourse.julialang.org/t/collecting-all-output-from-shell-commands/15592/6
""" Read output from terminal command """
function communicate(cmd::Cmd, input)
    inp = Pipe()
    out = Pipe()
    err = Pipe()

    process = run(pipeline(cmd, stdin=inp, stdout=out, stderr=err), wait=false)
    close(out.in)
    close(err.in)

    stdout = @async String(read(out))
    stderr = @async String(read(err))
    write(process, input)
    close(inp)
    wait(process)
    return (
        stdout = fetch(stdout),
        stderr = fetch(stderr),
        code = process.exitcode
    )
end

""" Checkout ControlSystems PR"""
function checkout_ControlSystems_PR(org, origin, ID)
    Pkg.develop(Pkg.PackageSpec(url="https://github.com/$org/ControlSystems.jl.git"))
    dir = joinpath(Pkg.devdir(), "ControlSystems")
    cd(dir)
    run(`git fetch $origin pull/$ID/head:tests-$ID`)
    run(`git checkout tests-$ID`)
    return
end

""" Generate figures for plot tests"""
function gen_figures()
    #### Test Plots

    ControlExamplePlots.Plots.gr()
    ControlExamplePlots.Plots.default(show=false)

    funcs, refs, eps = getexamples()
    # Make it easier to pass tests on different systems
    # Set to a factor 2*2 of common errors
    eps = 2*[0.15, 0.015, 0.1, 0.01, 0.01, 0.02, 0.01, 0.15, 0.15, 0.01, 0.01]
    res = genplots(funcs, refs, eps=eps, popup=false)

    ndiff = count(r -> r.status != ControlExamplePlots.EXACT_MATCH, res)

    return res, ndiff
end

function create_ControlExamplePlots_branch(ID)
    dir = joinpath(Pkg.devdir(), "ControlExamplePlots")
    cd(dir)
    master_sha1 = communicate(`git rev-parse HEAD`, "useless string")[1][1:end-1] # strip newline
    tmp_name = UUIDs.uuid1()
    # Create new branch
    new_branch_name = "tests-$ID-$tmp_name"
    run(`git checkout -b $new_branch_name`)
    return master_sha1, new_branch_name
end

""" Replace old files with new and push to new branch"""
function replace_and_push_files(res, new_org, origin, new_branch_name)
    # Create dir for temporary figures
    dir = joinpath(Pkg.devdir(), "ControlExamplePlots")
    cd(dir)
    for r in res
        # Copy results into repo
        mv(r.testFilename, r.refFilename, force=true)
    end
    # Add figures
    run(`git config --global user.email "name@example.com"`)
    run(`git config --global user.name "JuliaControl Bot"`)
    run(`git add src/figures/"*"`) # Escaping special char *
    run(`git commit -m "automated plots test"`)
    run(`git remote add bot https://JuliaControlBot:$(ENV["ACCESS_TOKEN_BOT"])@github.com/$(new_org)/ControlExamplePlots.jl.git`)
    run(`git push -u bot $new_branch_name`)
    return
end

# Builds a message to post to github
function get_message(res, org, new_org, old_commit, new_branch_name)
    good = ":heavy_check_mark:"
    warning = ":warning:"
    error = ":x:"

    images_str = ""
    ndiff = 0
    for r in res
        if r.status != ControlExamplePlots.EXACT_MATCH
            ndiff += 1
            diff = (isdefined(r, :diff) && isa(r.diff, Number)) ? r.diff : 1.0
            # Symbol in front of number
            symbol = ( diff < 0.015 ? good : (diff < 0.03 ? warning : error))
            # Number/message we print
            status = (isdefined(r, :diff) && isa(r.diff, Number)) ? round(r.diff, digits=3) : string(r.status)
            # Name of file
            fig_name = basename(r.refFilename)
            # Append figure to message
            images_str *= "$symbol $status | ![Reference](https://raw.githubusercontent.com/$org/ControlExamplePlots.jl/$old_commit/src/figures/$(fig_name)) | ![New](https://raw.githubusercontent.com/$(new_org)/ControlExamplePlots.jl/$(new_branch_name)/src/figures/$(fig_name))\n"
        end
    end

    str = if ndiff > 0
        """This is an automated message.
        Plots were compared to references. $(ndiff)/$(length(res)) images have changed, see differences below.
        After pulling this PR, please update the reference images by creating a PR to ControlExamplePlots.jl [here](https://github.com/JuliaControlBot/ControlExamplePlots.jl/pull/new/$(new_branch_name)).
        Difference | Reference Image | New Image
        -----------| ----------------| ---------
        """*images_str
    else
        """This is an automated message.
        Plots were compared to references. No changes were detected.
        """
    end
    return str
end

""" Post comment with result to original PR """
function post_comment(org, ID, message)
    token = ENV["ACCESS_TOKEN_BOT"]
    auth = GitHub.authenticate(token)
    #Push the comment
    GitHub.create_comment("$org/ControlSystems.jl", ID, :issue; auth = auth, params = Dict("body" => message))
end

println("Loading constants")
# Values
origin = "origin"
org = "JuliaControl"
new_org = "JuliaControlBot"
ID = ENV["PR_ID"]
RUN_ID = ENV["RUN_ID"]

try
    println("Running main script.")
    println("PR_ID is $(ENV["PR_ID"])")

    using Pkg

    # Makes sure we can push to this later
    println("deving ControlExamplePlots")
    Pkg.develop(Pkg.PackageSpec(url="https://github.com/$org/ControlExamplePlots.jl.git"))

    println("adding packages")
    Pkg.add("UUIDs")
    Pkg.add("GitHub")
    Pkg.add("ImageMagick") # Has no UUID

    println("running checkout_ControlSystems_PR")
    checkout_ControlSystems_PR(org, origin, ENV["PR_ID"])

    println("using ControlExamplePlots")
    using ControlExamplePlots

    println("running gen_figures")
    res, ndiff = gen_figures()

    println("$ndiff images have changes")
    import UUIDs

    println("running create_ControlExamplePlots_branch")
    old_commit, new_branch_name = create_ControlExamplePlots_branch(ID)

    if ndiff > 0
        println("running replace_and_push_files")
        replace_and_push_files(res, new_org, origin, new_branch_name)
    else
        println("No changes will be pushed")
    end

    println("running get_message")
    message = get_message(res, org, new_org, old_commit, new_branch_name)

    #### Post Comment
    import GitHub
    println("running post_comment")
    post_comment(org, ID, message)
    println("Done!")
catch
    println("BUILD FAILED!")

    message = "Something failed when generating plots. See the log at https://github.com/JuliaControl/ControlExamplePlots.jl/actions/runs/$(RUN_ID)?check_suite_focus=true for more details."

    import GitHub
    println("running post_comment")
    post_comment(org, ID, message)
    println("Build failed, comment added to PR.")
    # Throw error to log
    rethrow()
end


text:
"""
    Line(p1, p2)

Construct a `Line` geometric object (representing a segment) with given beginning and end
points, which are generally 2-vectors or 3-vectors.
"""
struct Line{N, T <: Real}
    p1::SVector{N, T}
    p2::SVector{N, T}
end

function Line(p1::StaticVector{N, T}, p2::StaticVector{N, T}) where {N, T <: Real}
    Line{N, T}(p1, p2)
end

function Line{N}(p1::AbstractVector{T}, p2::AbstractVector{T}) where {N, T <: Real}
    Line{N, T}(p1, p2)
end

# Note: This doesn't compare the ordering of points
function Base.:(==)(l1::Line{N}, l2::Line{N}) where N
    return l1.p1 == l2.p1 && l1.p2 == l2.p2
end

function Base.isequal(l1::Line{N}, l2::Line{N}) where N
    isequal(l1.p1, l2.p1) && isequal(l1.p2, l2.p2)
end

function Base.hash(l::Line, h::UInt)
    hash(l.p1, hash(l.p2, hash(UInt === UInt64 ? 0x627c5acc5b1e3d3d : 0x94c690be, h)))
end

# Use getindex to get points along the line
length(l::Line) = norm(l.p1 - l.p2)
function getindex(l::Line, t)
    t = t/length(l)
    (1-t)*l.p1 + t*l.p2
end
if VERSION < v"0.7"
    endof(l::Line) = length(l) # e.g. l[end - 1.0] is the point 1 metre from end of line
else
    lastindex(l::Line) = length(l) # e.g. l[end - 1.0] is the point 1 metre from end of line
end

eltype(::Line{N, T}) where {N, T} = SVector{N,T}
eltype(::Type{Line{N, T}}) where {N, T} = SVector{N,T}

getindex(l::Line, v::AbstractVector) = map(x -> l[x], v)

# Transformations (Affine only, for the moment)
(trans::Translation{V})(l::Line) where {V} = Line(trans(l.p1), trans(l.p2))
(trans::LinearMap{M})(l::Line) where {M} = Line(trans(l.p1), trans(l.p2))
(trans::AffineMap{M,V})(l::Line) where {M,V} = Line(trans(l.p1), trans(l.p2))

# Geometric operations
convert2d(l::Line{2}) = l
convert2d(l::Line{3}) = Line(convert2d(l.p1), convert2d(l.p2))
convert3d(l::Line{2}) = Line(convert3d(l.p1), convert3d(l.p2))
convert3d(l::Line{2}, z::Real) = Line(convert3d(l.p1, z), convert3d(l.p2, z))
convert3d(l::Line{3}) = l
convert3d(l::Line{3}, z::Real) = Line(convert3d(l.p1, z), convert3d(l.p2, z))

function intersects(l1::Line, l2::Line)
    return distance(l1, l2) == 0
end

function show(io::IO, l::Line{N}) where N
    print(io, "Line{$N}(")
    print(io, l.p1)
    print(io, ", ")
    print(io, l.p2)
    print(io, ")")
end

lines(l::Line) = [l]


text:
apply_process(C::Operator,ψ::Ket) = apply_process(C,Operator(ψ))
# assumes Choi matrix
apply_process(C::Operator,ρ::Operator{T,D}) where {T,D} =
    ptrace((transpose(ρ)⊗qeye(dims(ρ)))*C,ntuple(identity,D))
# assumes Kraus operators
apply_process(As::Vector{<:Operator},ρ::Operator) = sum(A->A*ρ*A',As)

function gate_fidelity_choi(C::Operator,U::Operator)
    # calculate the average gate fidelity given a Choi matrix and a unitary gate
    if dims(C) != (dims(U)...,dims(U)...)
        throw(DimensionMismatch())
    end
    V = qeye(dims(U)) ⊗ U
    return gate_fidelity_choi(V'*C*V)
end

function gate_fidelity_choi(C::Operator{T,D}) where {T,D}
    # calculate the average gate fidelity given a Choi matrix
    # Johnston, N. & Kribs, D. W. Quantum gate fidelity in terms of Choi
    # matrices. J. Phys. A Math. Theor. 44, 495303 (2011).
    dm = dims(C)
    if D%2 != 0 || prod(i->dm[i],1:D÷2) != prod(i->dm[i],D÷2+1:D)
        throw(ArgumentError("not a valid Choi matrix!"))
    end
    d = prod(i->dm[i],1:D÷2)
    TrA² = let CC = Operator(data(C),(d,d)) # rewrap operator to use tensored indexing
        real(sum(CC[(i,i),(j,j)] for i=0:d-1, j=0:d-1))
    end
    return (d + TrA²)/(d^2 + d)
end

function gate_fidelity_kraus(As::Vector{Operator{T,D}}) where {T,D}
    # calculate the average gate fidelity given a list of Kraus operators
    d = prod(i->dims(first(As))[i],1:D)
    return (d + sum(abs2∘trace,As))/(d^2 + d)
end

function gate_fidelity_kraus(As::Vector{<:Operator{T1,D}},U::Operator{T2,D}) where {T1,T2,D}
    # calculate the average gate fidelity given a list of Kraus operators and
    # a unitary gate
    dimsmatch(As,U)
    d = prod(i->dims(U)[i],1:D)
    return (d + sum(abs2∘inner,product(As,(U,))))/(d^2 + d)
end

# conversion functions

function operator_to_choi(O::Operator)
    newdims = (dims(O)...,dims(O)...)
    return Operator(vec(data(O))*vec(data(O))',newdims)
end

function kraus_to_natural(As::Vector{<:Operator})
    return sum(A->conj(A)⊗A,As)
end

function natural_to_kraus(K::Operator)
    # we go through the Choi representation since the extra conversion step is
    # basically free compared to the eigendecomposition
    return choi_to_kraus(natural_to_choi(K))
end

function natural_to_choi(K::Operator)
    # the conversion between the natural and Choi is a self-inverse
    return choi_to_natural(K)
end

function choi_to_natural(C::Operator)
    # the "natural" representation is the same as Choi with shuffled dimensions
    length(dims(C)) == 2 || throw(ArgumentError("multi-space operators not supported yet!"))
    d = dims(C)[1]
    K = reshape(permutedims(reshape(data(C),(d,d,d,d)),[1,3,2,4]),(d^2,d^2))
    return Operator(K,dims(C))
end

function choi_to_kraus(C::Operator)
    length(dims(C)) == 2 || throw(ArgumentError("multi-space operators not supported yet!"))
    @static if VERSION < v"0.7.0-"
        @inbounds for i = 1:size(C,1); C[i,i] = real(C[i,i]); end
    end
    D,V = eigen(Hermitian(data(C)),1E-10,Inf)
    return [Operator(unvec(√(D[i])*V[:,i]),(dims(C)[1],)) for i = length(D):-1:1]
end

function kraus_to_choi(As::Vector{<:Operator})
    length(dims(As[1])) == 1 || throw(ArgumentError("multi-space operators not supported yet!"))
    d = dims(As[1])[1]
    return Operator(sum(A->vec(data(A))*vec(data(A))',As),(d,d))
end

function choi_to_chi(C::Operator)
    length(dims(C)) == 2 || throw(ArgumentError("multi-space operators not supported yet!"))
    B = Operator(_choi_to_pauli_basis((dims(C)[1],)),dims(C))
    return (B*C*B')/2^1 # TODO: fix for multi-qubit
end

function chi_to_choi(χ::Operator)
    length(dims(χ)) == 2 || throw(ArgumentError("multi-space operators not supported yet!"))
    B = Operator(_choi_to_pauli_basis((dims(χ)[1],)),dims(χ))
    return (B'*χ*B)/2^1 # TODO: fix for multi-qubit
end

function _choi_to_pauli_basis(D::NTuple{N,Int}) where N
    all(d->d==2,D) || throw(ArgumentError("only valid with qubits!"))
    B = Matrix{Float64}(undef,4^N,4^N)
    # change to I,X,Y,Z basis (Y = -i*σy)
    Ps = ([1 0; 0 1], [0 1; 1 0], [0 -1; 1 0], [1 0; 0 -1])
    for (i,ops) in enumerate(product(ntuple(_->Ps,N)...))
        B[:,i] = vec(reduce(⊗,ops))
    end
    return B
end

Base.vec(O::Operator) = Ket(copy(vec(data(O))),dims(O).^2)

unvec(v::Ket) = Operator(copy(unvec(data(O))),isqrt.(dims(v)))

super(A::Operator) = conj(A) ⊗ A # represents A*ρ*A†
super(A::Operator,B::Operator) = transpose(B) ⊗ A

function unvec(vecA::AbstractVector)
    # unvectorize a vector into a square matrix
    d = isqrt(length(vecA))
    return reshape(vecA,(d,d))
end

function super(A::AbstractMatrix,B::AbstractMatrix=data(qeye(size(A,1))))
    # represents the action AρB, on a vectorized version of ρ
    return transpose(B) ⊗ A
end


text:
using CloudSeis, Documenter, TeaSeis

makedocs(sitename="CloudSeis", modules=[CloudSeis])

deploydocs(
    repo = "git@github.com:ChevronETC/CloudSeis.jl.git"
)


text:
abstract type Maybe end

struct Just{T} <: Maybe
    value::T
end

struct None <: Maybe end

const NONE = None()

"""
    MaybeTypeTrait

An abstract type that for implementing your own `Just` or `None` types.
For examples:
```julia
MaybeTypeTrait(::Type{MyOwnJust}) = IsJust()
MaybeTypeTrait(::Type{MyOwnNone}) = IsNone()
```
"""
abstract type MaybeTypeTrait end

struct IsNone <: MaybeTypeTrait end
struct IsJust <: MaybeTypeTrait end
struct IsVal  <: MaybeTypeTrait end

MaybeTypeTrait(::Type{<:Any}) = IsVal()
MaybeTypeTrait(::Type{<:Just}) = IsJust()
MaybeTypeTrait(::Type{None}) = IsNone()
MaybeTypeTrait(::Type{Nothing}) = IsNone()

# constructors
just(x::T) where {T} = just(MaybeTypeTrait(T), x)
just(::IsNone, x) = x
just(::IsJust, x) = x
just(::IsVal, x) = Just(x)

"""
    fmap(f, [x])
    fmap(f...)

Map function `f` over value `x`.  If `x` is wrapped then the result
will be wrapped as well.  If `x` is not provided then a curried
function is returned.
"""
fmap
fmap(f::Function, x::T) where {T} = fmap(MaybeTypeTrait(T), f, x)
fmap(::IsJust, f::Function, x) = Just(f(x.value))
fmap(::IsNone, f::Function, x) = x
fmap(::IsVal,  f::Function, x) = f(x)

# curry
fmap(f::Function) = x -> fmap(f, x)

# curry over multiple functions
# fmap(f, g, h) = x -> (h ∘ g ∘ f)(x)
fmap(f::Function...) = x -> foldr(fmap, reverse(f), init = x)

"""
    or_else([x], y)

If `x` is none then return `y`.  Otherwise, return `x`.
If `x` is not provided, then a curried function is returned.
"""
or_else
or_else(x::T, y) where {T} = or_else(MaybeTypeTrait(T), x, y)
or_else(::IsJust, x, y) = x
or_else(::IsNone, x, y) = y
or_else(::IsVal,  x, y) = x

# curry
or_else(y) = x -> or_else(x, y)

"""
    cata(lf, rf, [x])

Catamorphism - Return `lf()` when x is none. Otherwsie,
return `rf(x)`.  If `x` is wrapped then the result will be
wrapped.  If `x` is not provided then a curried function is
returned.
"""
cata
cata(lf::Function, rf::Function, x::T) where {T} = cata(MaybeTypeTrait(T), lf, rf, x)
cata(::IsJust, lf::Function, rf::Function, x) = just(rf(x.value))
cata(::IsNone, lf::Function, rf::Function, x) = lf()
cata(::IsVal,  lf::Function, rf::Function, x) = rf(x)

# curry
cata(lf::Function, rf::Function) = x -> cata(lf, rf, x)


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

_variate_form(::Distribution{VF}) where VF = VF

function _direct_valueshape_sum(vs_a::Union{ScalarShape{T},ArrayShape{T,1}}, vs_b::Union{ScalarShape{<:T},ArrayShape{<:T,1}}) where T
    n = totalndof(vs_a) + totalndof(vs_b)
    ArrayShape{T}(n)
end

_ntshape_names(::NamedTupleShape{names}) where names = names

function _direct_valueshape_sum(vs_a::NamedTupleShape{names_a}, vs_b::NamedTupleShape{names_b}) where {names_a,names_b}
    r = NamedTupleShape(; vs_a..., vs_b...)
    _ntshape_names(r) == (names_a..., names_b...) || throw(ArgumentError("Can't generate direct sum of NamedTupleShapes that share field names"))
    r
end

_direct_variateform_sum(::Type{<:Union{Univariate,Multivariate}}, ::Type{<:Union{Univariate,Multivariate}}) = Multivariate

function _direct_variateform_sum(::Type{ValueShapes.NamedTupleVariate{names_a}}, ::Type{ValueShapes.NamedTupleVariate{names_b}}) where {names_a,names_b}
    ValueShapes.NamedTupleVariate{(names_a...,names_b...)}
end

"""
    struct HierarchicalDistribution <: ContinuousDistribution

*Experimental feature, not part of stable public API.*

A hierarchical distribution, useful for hierarchical models/priors.

Constructors:

* ```HierarchicalDistribution(f::Function, primary_dist::NamedTupleDist)```

with a functon `f` that returns a `ContinuousDistribution` for any
variate `v` drawn from `primary_dist`.

Example:

```julia
hd = HierarchicalDistribution(
    v -> NamedTupleDist(
        baz = fill(Normal(v.bar, v.foo), 3)
    ),
    NamedTupleDist(
        foo = Exponential(3.5),
        bar = Normal(2.0, 1.0)
    )
)

varshape(hd) == NamedTupleShape(
    foo = ScalarShape{Real}(),
    bar = ScalarShape{Real}(),
    baz = ArrayShape{Real}(3)
)

v = rand(hd)
```

!!! note

    All fields of `HierarchicalDistribution` are considered internal and
    subject to change without deprecation.
"""
struct HierarchicalDistribution{
    VF <: VariateForm,
    T <: Real,
    F <: Function,
    PD <: ContinuousDistribution,
    VS <: AbstractValueShape,
    SVS <: AbstractValueShape
} <: Distribution{VF,Continuous}
    f::F
    pdist::PD
    vs::VS
    secondary_vs::SVS
    effndof::Int
end

export HierarchicalDistribution

function HierarchicalDistribution(f::Function, primary_dist::ContinuousDistribution)
    vs_primary = varshape(primary_dist)
    vf_primary = _variate_form(primary_dist)
    x_primary_us = rand(bat_determ_rng(), unshaped(primary_dist))
    x_primary = stripscalar(vs_primary(x_primary_us))

    secondary_dist = f(x_primary)
    vs_secondary = varshape(secondary_dist)
    vf_secondary = _variate_form(secondary_dist)
    if any(x -> x isa ConstValueShape, values((;vs_secondary...)))
        throw(ArgumentError("Value shape of secondary distributions of HierarchicalDistribution must not contain a ConstValueShape"))
    end

    vs = _direct_valueshape_sum(vs_primary, vs_secondary)
    VF = _direct_variateform_sum(vf_primary, vf_secondary)

    @assert totalndof(vs) == length(unshaped(primary_dist)) + length(unshaped(secondary_dist))

    T = promote_type(eltype(unshaped(primary_dist)), eltype(unshaped(secondary_dist)))
    F = typeof(f)
    PD = typeof(primary_dist)
    VS = typeof(vs)
    SVS = typeof(vs_secondary)

    effndof = eff_totalndof(primary_dist) + eff_totalndof(secondary_dist)

    HierarchicalDistribution{VF,T,F,PD,VS,SVS}(f, primary_dist, vs, vs_secondary, effndof)
end

ValueShapes.varshape(d::HierarchicalDistribution) = d.vs

Base.length(d::HierarchicalDistribution) = totalndof(varshape(d))

eff_totalndof(d::HierarchicalDistribution) = d.effndof

function Base.show(io::IO, d::HierarchicalDistribution)
    print(io, "HierarchicalDistribution(")
    Base.show(io, d.f)
    print(io, ", ")
    Base.show(io, d.pdist)
    print(io, ")")
end

struct UnshapedHDist{
    VF <: VariateForm,
    T <: Real,
    F <: Function,
    PD <: ContinuousDistribution,
    VS <: AbstractValueShape,
    SVS <: AbstractValueShape
} <: Distribution{Multivariate,Continuous}
    shaped::HierarchicalDistribution{VF,T,F,PD,VS,SVS}
end

ValueShapes.unshaped(d::HierarchicalDistribution) = UnshapedHDist(d)

Base.length(ud::UnshapedHDist) = length(ud.shaped)

Base.eltype(ud::UnshapedHDist{VF,T}) where {VF,T} = T

_hd_pridist(d::HierarchicalDistribution) = d.pdist

function _hd_secdist(d::HierarchicalDistribution, x::Any)
    secondary_dist = d.f(stripscalar(x))
    @assert eff_totalndof(d.pdist) + eff_totalndof(secondary_dist) == d.effndof
    secondary_dist
end

_hd_pridist(ud::UnshapedHDist) = unshaped(_hd_pridist(ud.shaped))
_hd_secdist(ud::UnshapedHDist, x::AbstractVector{<:Real}) = unshaped(_hd_secdist(ud.shaped, varshape(ud.shaped.pdist)(x)))

#=
@inline @generated function _split_nt(nt::NamedTuple, ::Val{names}) where {names}
    all_names = _nt_type_names(nt)
    rest_names = filter(n -> !(n in names), [all_names...])
    expr1 = Expr(:tuple, map(key -> :($key = nt.$key), names)...)
    expr2 = Expr(:tuple, map(key -> :($key = nt.$key), rest_names)...)
    Expr(:tuple, expr1, expr2)
end

@inline _split_nt(nt::NamedTuple, ::NamedTupleShape{names}) where {names} = _split_nt(nt, Val(names))

@inline function _hd_split(d::HierarchicalDistribution{ValueShapes.NamedTupleVariate{names}}, x::NamedTuple{names}) where names
    vsp = varshape(d.pd)
    _split_nt(x, vsp)
end

@inline function _hd_split(d::HierarchicalDistribution{ValueShapes.NamedTupleVariate{names}}, x::ShapedAsNT{<:NamedTuple{names}}) where names
    x_primary_us, x_secondary_us = _hd_split(unshaped(d), x)
    varshape(d.pdist)(x_primary_us), d.secondary_vs(x_secondary_us)
end
=#

function _hd_split(ud::UnshapedHDist, x::AbstractVector{<:Real})
    @argcheck length(ud) == length(eachindex(x))
    np = length(_hd_pridist(ud))
    idxs = eachindex(x)
    idxs_primary = first(idxs):(first(idxs) + np - 1)
    idxs_secondary = (first(idxs) + np):last(idxs)
    (view(x, idxs_primary), view(x, idxs_secondary))
end

function Distributions.logpdf(ud::UnshapedHDist, x::AbstractVector{<:Real})
    x_primary, x_secondary = _hd_split(ud, x)
    logval1 = logpdf(_hd_pridist(ud), x_primary)
    T = typeof(logval1)
    R = promote_type(T, eltype(x))
    # ToDo: Use insupport(_hd_pridist(ud), x_primary) in the future? insupport not yet available for NamedTupleDist.
    if logval1 > convert(T, -Inf)
        logval2 = logpdf(_hd_secdist(ud, x_primary), x_secondary)
        convert(R, logval1 + logval2)
    else
        convert(R, logval1)
    end
end

Distributions.pdf(d::HierarchicalDistribution, x::Any) where names = exp(logpdf(d, x))

Distributions.pdf(ud::UnshapedHDist, x::AbstractVector{<:Real}) = exp(logpdf(ud, x))

Random.rand(rng::AbstractRNG, d::HierarchicalDistribution, dims::Tuple{}) = varshape(d)(rand(rng, unshaped(d)))

# ToDo/Decision: Use stripscalar on result or not?
Random.rand(rng::AbstractRNG, d::HierarchicalDistribution) = stripscalar(rand(rng, d, ()))

function Random.rand(rng::AbstractRNG, d::HierarchicalDistribution, dims::Dims)
    ud = unshaped(d)
    X_flat = Array{eltype(ud)}(undef, length(ud), dims...)
    X = ArrayOfSimilarVectors(X_flat)
    rand!.(Ref(rng), Ref(ud), X)
    varshape(d).(X)
end

function Distributions._rand!(rng::AbstractRNG, ud::UnshapedHDist, x::AbstractVector{<:Real})
    x_primary, x_secondary = _hd_split(ud, x)
    rand!(rng, _hd_pridist(ud), x_primary)
    rand!(rng, _hd_secdist(ud, x_primary), x_secondary)
    x
end

function Distributions.insupport(ud::UnshapedHDist, x::AbstractVector)
    x_primary, x_secondary = _hd_split(ud, x)
    primary_dist = _hd_pridist(ud)
    insupport(primary_dist, x_primary) && insupport(secondary_dist, _hd_secdist(ud, x_primary))
end

function Statistics.mean(ud::UnshapedHDist)
    mean(nestedview(rand(bat_determ_rng(), ud, 10^5)))
end

function Statistics.cov(ud::UnshapedHDist)
    cov(nestedview(rand(bat_determ_rng(), ud, 10^5)))
end


text:
module RegionCovarianceDescriptor

using StaticArrays

include("descriptor.jl")

export RegionCovariance,
       covariance_matrix,
       covariance_matrix!

end # module


text:
using MAT
using Random
using Statistics
using StatsBase
include("../src/HyperLocal.jl")

@time M = matread("../data/stackoverflow_answer_H.mat")
LabelMatrix = M["LabelMatrix"]
LabelNames = M["LabelNames"]
H = M["H"]
order = round.(Int64,vec(sum(H,dims=2)))
m,n = size(H)
@show size(H)

esmall = findall(x->x<50,order)
@time Az = WeightedCliqueExpansion(H[esmall,:], order)

matwrite("ZCE_Stack.mat", Dict("Az"=>Az))

@time As = SimpleCliqueExp(H[esmall,:])

matwrite("SCE_Stack.mat", Dict("As"=>As))

max_stars_repo_name: nveldt/HypergraphFlowClustering

max_issues_repo_name: nveldt/HypergraphFlowClustering

max_forks_repo_name: nveldt/HypergraphFlowClustering


text:
## Get county info
# In retrospect, the MUCH easier thing to do would have been to use the
# county-info.csv file to get the FIPS code to lookup in the wikipedia
# data. But this is how I did it initially...
using JSON
## load county-info.csv from the website
using DelimitedFiles
cinfo,header = readdlm("county-info.csv",',',header=true)
cid2index = Dict(((cinfo[i,1]), Int(cinfo[i,2]+1)) for i in 1:size(cinfo,1))

##
mapdata = JSON.parsefile("final-map.json")
counties = mapdata["objects"]["counties"]["geometries"]
## Get the county names
names = [String(counties[i]["properties"]["NAME"]) for i in eachindex(counties)]
stateid = [String(counties[i]["properties"]["STATEFP"]) for i in eachindex(counties)]
geoids = [String(counties[i]["properties"]["GEOID"]) for i in eachindex(counties)]

## Get county info from wikipedia
## https://en.wikipedia.org/wiki/User:Michael_J/County_table
data = String(read("wikipedia-county-info.txt"))
info = split(data,"|-\n")[3:end]

##
info_geoids = []
for line in info
  parts = split(chomp(line), "||")
  @assert(length(parts) == 14)
  geoid = split(parts[3], "|")[2]
  push!(info_geoids, geoid)
  name = split(parts[4], "|")[2]
  if !(geoid in geoids)
    println("Missing $(geoid) $(name)")
  end

  population = parse(Int,replace(split(parts[6], "|")[2], ","=>""))
  area = parse(Float64,replace(split(parts[12], "|")[2], ","=>""))
  long = parse(Float64, split(parts[13], "|")[2][1:end-1])
  # this must use an emdash – vs. - (yes, there is a difference there!)
  lat = parse(Float64, replace(split(parts[14], "|")[2][1:end-1], "–" => "-"))
end
## Check which we don't have info on
for geoid in geoids
  if !(geoid in info_geoids)
    println("Missing info on $(geoid)")
  end
end

## We are missing data on one county, let's just add it.
# Missing info on 02158
names[findfirst(geoids .== "02158")]
# Oh! This was just renamed...
# https://github.com/walkerke/tidycensus/blob/master/R/estimates.R
# Account for change from Shannon County, SD to Oglala Lakota County
# and the new Kusilvak Census Area in AK
# geom$GEOID[geom$GEOID == "46113"] <- "46102"
# geom$GEOID[geom$GEOID == "02270"] <- "02158"

## So we have everything!
##
info_geoids = []
info_population = zeros(Int,0)
info_area = zeros(0)
info_lat = zeros(0)
info_long = zeros(0)
info_state = Vector{String}()
info_name = Vector{String}()
for line in info
  parts = split(chomp(line), "||")
  @assert(length(parts) == 14)
  geoid = split(parts[3], "|")[2]
  name = split(parts[4], "|")[2]
  stateid = split(parts[2], "|")[3][1:2]
  if geoid == "02270" # see notes above
    geoid = "02158"
  end

  population = parse(Int,replace(split(parts[6], "|")[2], ","=>""))
  area = parse(Float64,replace(split(parts[12], "|")[2], ","=>""))
  long = parse(Float64, split(parts[13], "|")[2][1:end-1])
  # this must use an emdash – vs. - (yes, there is a difference there!)
  lat = parse(Float64, replace(split(parts[14], "|")[2][1:end-1], "–" => "-"))

  push!(info_name, name)
  push!(info_state, stateid)
  push!(info_lat, lat)
  push!(info_long, long)
  push!(info_area, area)
  push!(info_population, population)
  push!(info_geoids, geoid)
end

## Spit out metadata
# we want two files: xy coords with the lat/long
# -metadata.csv with the population and area
# build the permutation, here, we have to lookup the geoid to get the id in the
# matrix
rows = zeros(Int,length(geoids))
perm = zeros(Int,length(geoids))
for (i,g) in enumerate(geoids)
  gnum = parse(Int,g)
  row = cid2index[gnum]
  perm[row] = i
  rows[row]= findfirst(info_geoids .== g)
end

## join state and name
names_states = names[perm] .* ", ".*info_state[rows]
## Quick verifyication of data
[info_name[rows][1:10] names_states[1:10]]
## Adjust the lat-long of the stuff on the other hemisphere
xy = [info_lat[rows] info_long[rows]]
xy[69,1] = -180-(180-xy[69,1])

##
using DelimitedFiles
writedlm("facebook-county-friendship.xy", xy)
writedlm("facebook-county-friendship.labels", names_states)
writedlm("facebook-county-friendship-metadata.csv",
  zip(info_population[rows], info_area[rows], info_state[rows]))

max_stars_repo_name: empet/more-graphs

max_issues_repo_name: empet/more-graphs

max_forks_repo_name: empet/more-graphs


text:
module Endpoints

using ..Pages

export Endpoint, endpoints, method, servefile, servefolder
export GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH

struct Method{M} end

struct Endpoint
    handlers::Dict{Symbol,HTTP.RequestHandlerFunction}
    route::String

    function Endpoint(handle,route,method::Method{M}=GET) where M
        route = lowercase(route)
        if haskey(endpoints,route)
            e = endpoints[route]
            e.handlers[M] = HTTP.RequestHandlerFunction(handle)
            return e
        else
            handlers = Dict(M=>HTTP.RequestHandlerFunction(handle))
            e = new(handlers,route)
            endpoints[route] = e
            return e
        end
    end
end
const endpoints = Dict{String,Endpoint}()

symbol(m::Type{Method{M}}) where M = M

Base.show(io::IO,m::Method{M}) where M = print(io,M)
Base.show(io::IO,::MIME"text/plain",m::Method{M}) where M = print(io,M)

methods = ["GET","HEAD","POST","PUT","DELETE","CONNECT","OPTIONS","TRACE","PATCH"]
for method in methods
    @eval Endpoints $(Symbol(method)) = Method{Symbol($(method))}()
end
method(m::Method{S}) where {S} = S

function servefile(filepath,root="/")
    if isfile(filepath)
        file = basename(filepath)
        if isequal(lowercase(file),"index.html") || isequal(lowercase(file),"index.htm")
            Endpoint(root) do request::HTTP.Request
                read(filepath,String)
            end
        end
        Endpoint("$(root)/$(file)") do request::HTTP.Request
            read(filepath,String)
        end
    else
        @warn "$(filepath) not found."
    end
end

function servefolder(folder,root="/")
    for file in readdir(folder)
        filepath = joinpath(folder,file)
        servefile(filepath,root)
    end
end

end


text:
Dict{Symbol, Any}(
    :album_id => SpId("2O9mD7oKwBnhQZQUAJM6GM"),
    :album_ids => [SpId("2O9mD7oKwBnhQZQUAJM6GM"), SpId("3eLvDNfWAMpytqIp073FEc")],
    :artist_id => SpId("7HGFXtBhRq3g1Ma3nH4Rgv"),
    :category_id => SpCategoryId("party"),
    :country => "NO",
    :episode_id => SpId("7Hyyvc9QaojDudrjXsS06P"),
    :ids => [SpId("74ASZWbe4lXaubB36ztrGX"), SpId("08td7MxkoHQkXnWAYD8d6Q")],
    :include_groups => "album,single,appears_on,compilation",
    :limit => 10,
    :locale => "en",
    :market => "NO",
    :noffset => 0,
    :offset => 0,
    :playlist_id => SpId("5o5IGyk4tKO7A0DkVpstN0"),
    :seeds => [SpId("4NHQUGzhtTLFvgF5SZesLK"), SpId("79O1dBolRj3Epn1pIZRCsZ")],
    :show_id => SpId("72qiPaoDRf8HkGKEChvG5q"),
    :shows_ids => [SpId("5AvwZVawapvyhJUIx71pdJ"),SpId("6ups0LMt1G8n81XLlkbsPo"), SpId("5AvwZVawapvyhJUIx71pdJ")],
    :show_ids => [SpId("5AvwZVawapvyhJUIx71pdJ"),SpId("6ups0LMt1G8n81XLlkbsPo"), SpId("5AvwZVawapvyhJUIx71pdJ")],
    :time_range => "medium",
    :timestamp => string(now()),
    :track_attributes => "TEMP", # Dict(),
    :track_id => SpId("0WdUHon5tYn2aKve13psfy"),
    :track_ids => [SpId("0WdUHon5tYn2aKve13psfy"), SpId("619OpJGKpAOrp5rM4Gcs65")],
    :type => "artist"
    )


text:
using LinearAlgebra
using SparseArrays
include("../src/ExactDiagonalization.jl")
include("deprecate/ExactDiagonalization.jl")
using .ExactDiagonalization
import .OldED as OED
using Test
#-------------------------------------------------------------------------------------------------------------------------
# Pauli matrices
#-------------------------------------------------------------------------------------------------------------------------
const X = [0 1; 1 0]
const Y = [0 -1; 1 0] * 1im
const Z = [1 0; 0 -1]
@testset "PauliKron" begin
    XII = operator([X], [[1]], 3)
    @test Array(XII) ≈ kron(X, I(4))
    IYI = operator([Y], [[2]], 3)
    @test Array(IYI) ≈ kron(I(2), Y, I(2))
    IIZ = operator([Z], [[3]], 3)
    @test Array(IIZ) ≈ kron(I(4), Z)
    # Multiplication
    V = rand(8)
    M = rand(ComplexF64, 8, 2)
    @test (XII * V) ≈ (kron(X, I(4)) * V)
    @test (IYI * M) ≈ (kron(I(2), Y, I(2)) * M)
end

#-------------------------------------------------------------------------------------------------------------------------
# Randon Matrices
#-------------------------------------------------------------------------------------------------------------------------
@testset "Real Random Matrices" begin
    L = 12
    println("\nL = $L System:")
    mats = [rand(4, 4) |> Hermitian |> Array for i=1:L]
    inds = [mod.([i-1, i], L) .+ 1 for i=1:L]
    print("New :")
    @time op1 = operator(mats, inds, L) |> Array
    print("Old :")
    @time op2 = OED.operation(mats, inds, L) |> Array
    @test op1 ≈ op2
end

@testset "ComplexF64 Random Matrices" begin
    L = 13
    println("\nL = $L System:")
    mats = [rand(ComplexF64, 4, 4) |> Hermitian |> Array for i=1:L]
    inds = [mod.([i-1, i], L) .+ 1 for i=1:L]
    print("New :")
    @time op1 = operator(mats, inds, L) |> Array
    print("Old :")
    @time op2 = OED.operation(mats, inds, L) |> Array
    @test op1 ≈ op2
end

@testset "Benchmark Sparse Matrix" begin
    L = 14
    println("\nBenchmark Sparse Matrix for L = $L System:")
    mat = kron(I(2), X, Y, Z)
    print("New :")
    @time op1 = trans_inv_operator(mat, 4, L) |> Array
    print("Old :")
    @time op2 = OED.trans_inv_operation(mat, 1:4, L) |> Array
end

@testset "Benchmark Matrix Multiplication" begin
    L = 14
    println("\nBenchmark Matrix Multiplication for L = $L System:")
    mat = kron(I(2), X, Y, Z)
    v = rand(2^L)
    opt = trans_inv_operator(mat, 4, L)
    print("Operator : ")
    @time v2 = opt * v
    print("Dense    : ")
    optm = Array(opt)
    @time v3 = optm * v
    @test v2 ≈ v3
end


text:
module DGmethods

using MPI
using ..MPIStateArrays
using ..Mesh.Grids
using ..Mesh.Topologies
using StaticArrays
using ..SpaceMethods
using ..VariableTemplates
using DocStringExtensions
using KernelAbstractions
using KernelAbstractions.Extras: @unroll

export BalanceLaw, DGModel, init_ode_state

include("balancelaw.jl")
include("NumericalFluxes.jl")
include("DGmodel.jl")
include("DGmodel_kernels.jl")

end

max_stars_repo_name: trontrytel/CLIMA

max_issues_repo_name: trontrytel/CLIMA

max_forks_repo_name: trontrytel/CLIMA


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

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 iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
end

# ╔═╡ 071d9ca5-9b42-4583-ad96-a48f93453a0e
using PlutoUI

# ╔═╡ bc532cd2-c75b-11ea-313f-8b5e771c9227
md"""# PlutoUI.jl

The [Interactivity sample notebook](./sample/Interactivity.jl) explains how Pluto notebooks can use **`@bind`** to add _interactivity_ to your notebook. It's a simple concept - it uses the same reactivity that you have when editing code, except now you use sliders and buttons, instead of editing code.

However, code like

```julia
@bind x html"<input type=range min=5 max=15>"
```
is hard to memorize, so `PlutoUI` makes it more _Julian_:
```julia
@bind x Slider(5:15)
```
"""

# ╔═╡ 3eff9592-cc63-11ea-2b61-4170d1a7656a

# ╔═╡ 051f31fc-cc63-11ea-1e2c-0704285ea6a9
md"""
#### To use it in other notebooks
Simply import the `PlutoUI` package, and Pluto's built-in package manager takes care of the rest!
"""

# ╔═╡ fddb794c-c75c-11ea-1f55-eb9c178424cd
md"""
# Basics
"""

# ╔═╡ b819e9a8-c760-11ea-11ee-dd01da663b5c
md"## Slider"

# ╔═╡ 34ebf81e-c760-11ea-05bb-376173e7ed10
@bind x Slider(5:15)

# ╔═╡ a4488984-c760-11ea-2930-871f6b400ef5
x

# ╔═╡ 1048d1e0-cc50-11ea-1bf3-d76cae42740a

# ╔═╡ a709fd2e-c760-11ea-05c5-7bf673990de1
md"The first argument is a `Vector` or range. You can set the _default value_ using a keyword argument:"

# ╔═╡ d3811ac2-c760-11ea-0811-131d9f1d3910
@bind y Slider(20:0.1:30, default=25)

# ╔═╡ dfe10b6c-c760-11ea-2f77-79cc4cfa8dc4
y

# ╔═╡ 06962cde-cc4f-11ea-0d96-69a8cb7eeda2

# ╔═╡ 6605d010-d0d1-4cc8-a34d-3158b8572b5d
md"""
## Scrubbable

`Scrubbable` makes a number interactive, you can **click and drag** its value left or right.

Try it in the text below:
"""

# ╔═╡ 756e2c82-6e2f-4d7b-a1ed-5de97be04269
md"""
_If Alice has $(@bind a Scrubbable(20)) apples,
and she gives $(@bind b Scrubbable(3)) apples to Bob..._
"""

# ╔═╡ c07c5a9e-61f9-4247-86e7-7c3f9956d0ff
md"""
_...then Alice has **$(a - b)** apples left._
"""

# ╔═╡ c3fea1b2-fc11-4c19-9c01-a8e03fda2817
md"""
Use the Live Docs to learn more about `Scrubbable`!
"""

# ╔═╡ 221c308e-3cbe-4689-aa67-8970957f8cb0

# ╔═╡ e49623ac-c760-11ea-3689-c15f2e2f6081
md"## NumberField

A `NumberField` can be used just like a `Slider`, it just looks different:"

# ╔═╡ 314cb85a-c761-11ea-1cba-b73f84a52be8
@bind x_different NumberField(0:100, default=20)

# ╔═╡ 104b55ce-cc4f-11ea-1273-092a1717e399

# ╔═╡ 4513b730-c761-11ea-1460-2dca56081fcf
md"## CheckBox"

# ╔═╡ 4f8e4e1e-c761-11ea-1787-419cab59bb12
@bind z CheckBox()

# ╔═╡ b787ead6-c761-11ea-3b17-41c0a5434f9b
z

# ╔═╡ 177e6bf0-cc50-11ea-0de2-e77544f5c615

# ╔═╡ b08c347e-c761-11ea-1b61-7b69631d078b
md"Default value:"

# ╔═╡ b53c8ffa-c761-11ea-38d1-2d4ad96a7bee
@bind having_fun CheckBox(default=true)

# ╔═╡ adcf4e68-c761-11ea-00bb-c3b15c6dedc0
having_fun

# ╔═╡ 1a562ad4-cc50-11ea-2485-cdec6e1a78dc

# ╔═╡ 5d420570-c764-11ea-396b-cf0db01d34aa
having_fun ? md"🎈🎈" : md"☕"

# ╔═╡ 09393bf2-cc4f-11ea-1e48-cfbedab8e6b4

# ╔═╡ cd1b5872-c761-11ea-2179-57a3cb34d235
md"## TextField"

# ╔═╡ d9e85ed0-c761-11ea-30bf-83ce272526e0
@bind s TextField()

# ╔═╡ e4c262d6-c761-11ea-36b2-055419bfc981
s

# ╔═╡ 0934bc0c-cc50-11ea-0da8-0d6b2f275399

# ╔═╡ e690337c-c761-11ea-08be-ade40a464eb4
md"With a default value:"

# ╔═╡ f1f83980-c761-11ea-1e34-97c0ffca3f67
@bind sentence TextField(default="te dansen omdat men leeft")

# ╔═╡ f985c8de-c761-11ea-126c-1fd79d547b79
sentence

# ╔═╡ 1cbfd28e-cc50-11ea-2c90-a7807e4979ef

# ╔═╡ 0136af80-c762-11ea-2f1a-9dccff334a11
md"You can also create a **multi-line** text box!"

# ╔═╡ 0e6f0508-c762-11ea-0352-09bd694a9b35
@bind poem TextField((30, 3), "Je opent en sluit je armen,\nMaar houdt niets vast.\nHet is net zwemmen")

# (poem by: Sanne de Kroon)

# ╔═╡ 3dcd7002-c765-11ea-323d-a1fb49409011
split(poem, "\n")

# ╔═╡ 0aa3c85e-cc4f-11ea-2fba-4bdd513d9217

# ╔═╡ 5833f7f4-c763-11ea-0b95-9b21a40192a9
md"## Select"

# ╔═╡ 690cf3ac-c763-11ea-10f0-b3e28c380be9
@bind vegetable Select(["potato", "carrot"])

# ╔═╡ 705662e2-c763-11ea-2f6d-cdaffc1fc73a
vegetable

# ╔═╡ 1feebd8f-667a-42fd-965d-5e3167ff7c7a
@bind favourite_function Select([sin, cos, tan, sqrt])

# ╔═╡ 9128d2c1-364c-4446-baaa-6d0593edda47
favourite_function(2)

# ╔═╡ 3930f0d8-cc50-11ea-3de6-d91ac5c6cd9f

# ╔═╡ 787a2c88-c763-11ea-0a32-bb91ca60113d
md"Instead of an array of values, you can also give an array of **pairs**, where the first item is the bound value, and the second item is displayed. "

# ╔═╡ ac8c4dee-c763-11ea-1b2d-c590a2d50d7e
@bind fruit Select(["apple" => "🍎", "melon" => "🍉"])

# ╔═╡ dcda9ad2-c763-11ea-3ec6-093b823ba66d
fruit

# ╔═╡ 0c3ab1f8-cc4f-11ea-0cfb-8f076d2c9836

# ╔═╡ 62c6f866-f0fe-11ea-0961-319f28d040d4
md"""
## MultiSelect

This widget allows the user to select multiple element by holding `Ctrl` / `Cmd` while clicking a more items.
"""

# ╔═╡ a01c8096-f0fe-11ea-3e78-ad8551e84fa1
@bind vegetable_basket MultiSelect(["potato", "carrot", "boerenkool"])

# ╔═╡ a20e30f2-f0fe-11ea-0ca7-c5195c9eb24a
vegetable_basket

# ╔═╡ c819ef3e-f0fe-11ea-1213-9df7597e4e89
md"Just like `Select`, you can also give an array of pairs."

# ╔═╡ b104ba6d-0293-4378-9652-f628f1d08d97
md"""
## MultiCheckBox

This widget allows the user to select multiple elements using checkboxes.
"""

# ╔═╡ 16f2218d-f1bc-4b34-a355-53acfa77fbf5
@bind fruit_basket MultiCheckBox(["apple", "blueberry", "mango"])

# ╔═╡ 2c7811cb-d9ea-470c-8cb7-2b3803489f3f
fruit_basket

# ╔═╡ 78be41d1-7dda-4bec-b75f-fbcf8b7594a7
md"""
You can use `MultiSelect` and `MultiCheckBox` with any vector of objects, not just strings:
"""

# ╔═╡ 90d84f1b-042c-444e-8bac-fe358b6d68a1
@bind my_functions MultiCheckBox([sin, cos, tan])

# ╔═╡ b97cfb04-0c39-4709-9419-9294e677a872
[f(π) for f in my_functions]

# ╔═╡ 283d1177-c605-4652-905b-9a70354cf878
md"Just like `Select`, you can also give an array of pairs. See the Live Docs for `MultiCheckBox` for all the customization options!"

# ╔═╡ 0b1ce22e-c764-11ea-3d60-e799d58aee30
md"## Button"

# ╔═╡ 6d9108a8-c765-11ea-0a38-09a1364998b1
@bind clicked Button("Hello world")

# ╔═╡ 7a14e496-c765-11ea-20a1-6fb960009251
clicked

# ╔═╡ 3eff932a-cc50-11ea-366e-812d3854dd4c

# ╔═╡ 7e10fb52-c765-11ea-2a71-0fc347d09885
md"""
### Button as reactive trigger

In the example above, _any cell that references `clicked` will re-evaluate_ when you click the button. This means that you can a button as a **reactive trigger**, by referencing its value in another cell.
"""

# ╔═╡ b91764e8-c765-11ea-27a2-4ba5777fbd89
@bind go Button("Recompute")

# ╔═╡ bb356b12-c765-11ea-2c36-697f4314bb93
let
	go

	md"I am $(rand(1:15)) years old!"
end

# ╔═╡ 9276da28-cc4f-11ea-17b3-65eec41a181e

# ╔═╡ 92def54a-cc4f-11ea-12c5-652f2bb46413
md"## FilePicker"

# ╔═╡ 9920e56c-cc4f-11ea-2d5e-f5371c79f048
@bind important_document FilePicker()

# ╔═╡ 44591b34-cc50-11ea-2005-2f7075e6f2db
important_document

# ╔═╡ 4fda3072-cc50-11ea-2804-197b6391b269
md"The file picker is useful if you want to show off your notebook on a dataset or image **uploaded by the reader**. It will work anywhere - you don't access files using their path.

The caveat is that large files might take a long time to get processed: everything needs to pass through the browser. If you are using large datasets, a better option is to use `Select` to let the reader pick a filename. You can then read the file using `Base.read(filename, type)`"

# ╔═╡ 3e5dd7d2-c760-11ea-1dca-6d8720b3558d
md"# Extras"

# ╔═╡ f31668c6-c768-11ea-1501-5f41afa7c83b
md"## Clock"

# ╔═╡ 417390ba-c760-11ea-27df-5908858ae88c
@bind t Clock()

# ╔═╡ 49e7cd06-c760-11ea-3f5d-2741d94278a6
t

# ╔═╡ 31a2f3c4-cc51-11ea-3652-bd814517a4b5

# ╔═╡ 67709812-c760-11ea-2bda-9756ead35749
md"You can set the interval (`5.0` seconds), and disable the UI (`true`):"

# ╔═╡ 4c2b45a0-c760-11ea-2b64-3fefc820cd5b
@bind t_slow Clock(5.0, true)

# ╔═╡ 5be148cc-c760-11ea-0819-a7bb403d27ff
t_slow

# ╔═╡ 347e3d06-cc51-11ea-012c-43e824eaffa2

# ╔═╡ 343d7118-cc51-11ea-387a-fb22d8c73506
md"You can use a `Clock` to drive an animation! Or use it to repeat the same command at an interval: just like with `Button`, you can reference a bound (reactive) variable without actually using it!"

# ╔═╡ 32e41ac2-cc51-11ea-3358-bbead9c68123

# ╔═╡ f74f434a-c768-11ea-079c-fb707e6ba17b
md"## DownloadButton"

# ╔═╡ ea00721c-cc4b-11ea-1e82-0b3dbe6a7f1e
md"""
The download button is not an **input** element that you can `@bind` to, it's an **output** that you can use to get processed data from your notebook easily. The second argument is the _output filename_.
"""

# ╔═╡ fc12280c-c768-11ea-3ebc-ebcd6b3459c1
DownloadButton(poem, "poem.txt")

# ╔═╡ 067cbcde-cc4c-11ea-3eed-972dc6d7bb3b
DownloadButton([0x01, 0x02, 0x03], "secret_data.bin")

# ╔═╡ 7da30d97-b28a-4eb9-a2ef-fad599b549d1
md"""
# High-level inputs
"""

# ╔═╡ 170089cd-f366-4c0a-b58d-fe6e36049db7
md"""
## Confirm

Normally, when you move a [`Slider`](@ref) or type in a [`TextField`](@ref), all intermediate values are sent back to `@bind`. By wrapping an input element in `confirm`, you get a button to manually **control when the value is sent**, intermediate updates are hidden from Pluto.

"""

# ╔═╡ b29215cb-8e7e-4382-822c-cdaa4c473ba1
@bind distance confirm(Slider(1:100))

# ╔═╡ 00f9f608-85bd-4932-b585-39f74dcf53b4
distance

# ╔═╡ 48a9ffbd-cac7-4c4e-85e5-c3d0693e5550
md"""
`confirm` can be wrapper around any input element to create a new one, including inputs from other packages, or inputs that you have made yourself!
"""

# ╔═╡ 5c85ee41-da68-4f5f-b45e-e1de7996747d

# ╔═╡ 8c51343f-cb35-4ff9-9fd8-642ffab57e22
md"""
## Combine

This next high-level component is a bit tricky, but very powerful!

Using `combine`, you can create a single input out of multiple existing ones! In the example below, we create a new input, `wind_speed_input`. Notice that the list of wind directions is *dynamic*: if you add a new direction, a 5th slider will appear!

"""

# ╔═╡ 621f2e82-5ab4-4ab9-a0ff-fb1cc1b41295
import PlutoUI: combine

# ╔═╡ a4837897-caae-447a-8db9-7775e7a4d0c8

# ╔═╡ d278189e-6a5b-428a-8c81-ce3d206b042c
function wind_speed_input(directions::Vector)

	return combine() do Child

		inputs = [
			md""" $(name): $(
				Child(name, Slider(1:100))
			)"""

			for name in directions
		]

		md"""
		#### Wind speeds
		$(inputs)
		"""
	end
end

# ╔═╡ f5c421cc-dbdb-459a-9bb4-d648507a87d2
@bind speeds wind_speed_input(["North", "East", "South", "West"])

# ╔═╡ a4eac824-ba87-473a-b39a-783c4de3f933
speeds

# ╔═╡ f9052ed8-84cc-4cca-abb2-9363aafc6040
speeds.North

# ╔═╡ 4ca9c749-08ee-467f-af2c-9b2f13199d72
md"""
Use the Live Docs to learn more about `combine` and to see additional examples.

> 🙋 `combine` is very useful in combination with [HypertextLiteral.jl](https://github.com/MechanicalRabbit/HypertextLiteral.jl), which you can learn using our JavaScript sample notebook.
"""

# ╔═╡ ad8e9b30-c75d-11ea-1fd0-0b53592135bf
md"""# Loading resources

Notebooks use data from different places. For example, you use [`Base.read`](https://docs.julialang.org/en/v1/base/io-network/#:~:text=read(filename%3A%3AAbstractString%2C%20String)) to access local data (files) inside your Julia code, and [`Downloads.jl`](https://github.com/JuliaLang/Downloads.jl) for remote data (interwebs).

`PlutoUI` helps you communicate with the person reading the notebook!
- To get **remote media** (URL) inside your **Markdown text**, use `PlutoUI.Resource`.
- To get **local media** (file) inside your **Markdown text**, use `PlutoUI.LocalResource`.

(With _media_, we mean **images**, video and audio.)

> We **strongly recommend** that you use _remote_ media inside Pluto notebooks!
>
> If your notebook uses local images, then those images **will not show** when someone else opens your notebook, unless they have the same images on their computer, at the exact same location. _More on this later._

"""

# ╔═╡ 87d088d0-cc54-11ea-02c6-bd673b95b9d3
md"""## Resource

If you just want to show **images inside Markdown**, you can use the built-in syntax (without `PlutoUI`):

```
md"Here is a _dog_: ![](https://fonsp.com/img/doggoSmall.jpg)"
```

`PlutoUI.Resource` has some extra features:
- specify **image dimensions** and spacing
- support for videos
- support for audio"""

# ╔═╡ 6a7e7e54-c75e-11ea-2ea7-ed3da37e9e96
dog_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Welsh_Springer_Spaniel.jpg/640px-Welsh_Springer_Spaniel.jpg"

# ╔═╡ 3c68b25c-c761-11ea-226a-4f46579a6732
Resource(dog_url, :width => x * x_different)

# ╔═╡ 9ac7921c-c75e-11ea-30f5-c35e6ee370cb
t_rex_url = "https://upload.wikimedia.org/wikipedia/commons/transcoded/6/62/Meow.ogg/Meow.ogg.mp3"

# ╔═╡ a8c57442-c75e-11ea-1913-7d82cbd2c69c
flower_url = "https://upload.wikimedia.org/wikipedia/commons/4/41/Sunflower_Flower_Opening_Time_Lapse.ogv"

# ╔═╡ cb37b916-c75b-11ea-0c83-6ba759536075
md"""Hello I am a dog $(Resource(dog_url))"""

# ╔═╡ 16ea31fc-c75e-11ea-0f2d-dd790a56b2dc
md"""And I sound like this: $(Resource(t_rex_url))"""

# ╔═╡ 1dfd8cc6-c75e-11ea-3c04-a96734779c97
md"""This is my flower friend

$(Resource(flower_url, :width => 200))"""

# ╔═╡ 2fda30ea-c75e-11ea-2ff5-7f2dcf4f9b66
md"### Attributes

You can pass additional _HTML attributes_ to `Resource`, these will be added to the element. For example:"

# ╔═╡ 525ceea0-c75e-11ea-2766-f72418fd784e
md"""
$(Resource(dog_url, :width => 20))
$(Resource(dog_url, :width => 50))
$(Resource(dog_url, :width => 100))
$(Resource(dog_url,
	:width => 100,
	:style => "filter: grayscale(100%); border: 3px solid black;"))
"""

# ╔═╡ 382d41d8-c75e-11ea-2ae3-2ffe96e04b5a
Resource(flower_url, :width => 200, :autoplay => "", :loop => "")

# ╔═╡ 958ab19c-cc56-11ea-162e-d3664e66ff66
md"### YouTube, Vimeo, etc.

If you use `Resource` for video, the URL has to point to a _video file_ (like `.mp4` or `.mov`).

Popular video sites don't give you that link, instead, you can use their **embed codes**. You can find these inside the video player, by right clicking or using the menu buttons. You then use that inside an HTML block:
```
html\"\"\"
~ paste embed code here ~
\"\"\"
```

You might need to change the `width` to `100%` to make it fit."

# ╔═╡ 8477619c-cc57-11ea-0618-1778c502d28f
html"""

"""

# ╔═╡ f743076c-cc57-11ea-1a8e-8799d9db985a

# ╔═╡ c65d28a2-c75d-11ea-2e13-7332f93d9c5e
md"## LocalResource _(not recommended)_

The examples above use `Resource` to make media from a URL available inside Markdown. To use **local files**, simply **replace `Resource` with `LocalResource`**, and use a _file path_ instead of a URL."

# ╔═╡ c16dff74-cc5d-11ea-380c-aff1639b5551

# ╔═╡ dada2154-c75d-11ea-2312-b9156a9a531e
html"I really hope that this works"

# ╔═╡ f809110c-cc55-11ea-1551-e138c28d5d82
md"""Hello I am a dog $(LocalResource("C:\\Users\\fons\\Pictures\\hannes.jpg"))"""

# ╔═╡ 1c930364-cc58-11ea-36c8-0ddf7c4700cd
md""" $(html"OOPS"), it didn't!

$(html"
")

Here are **two tips** for getting local images to work correctly:

1. Go to [imgur.com](https://imgur.com) and drag&drop the image to the page. Right click on the image, and select "Copy image location". You can now use the image like so:

   ```PlutoUI.Resource("https://i.imgur.com/SAzsMMA.jpg")```

2. If your notebook is part of a git repository, place the image in the repository and use a relative path:

    ```PlutoUI.LocalResource("../images/cat.jpg")```

"""

# ╔═╡ c48b48f6-cc5d-11ea-0f3b-d3481238625d

# ╔═╡ ea6ade22-cc5a-11ea-1782-97f2464fd148
md"#### Why does it have to be so difficult?

Pluto only stores _code_ in the notebook file, not images. This minimal file format is very valuable, but it means that images need to be _addressed_, not stored.

Addressing _local files_ is fragile: if someone else opens the notebook, or if you move the notebook to a different folder, that image file needs to be available at exactly the same path. This is difficult to do correctly, and if it works for you, it is hard to tell if it will work for someone else.

Putting images online might be a hassle, but once it works, it will work everywhere! The stateless nature of URLs means that the images will work regardless of how the notebook file is accessed, while keeping a minimal file format."

# ╔═╡ a245dddc-cc59-11ea-3e1d-1763673ff706
md"# PlutoUI without Pluto

Huh?

Did you know that you can run Pluto notebooks _without Pluto_? If your notebook is called `wow.jl`, then
```sh
$ julia wow.jl
```
will run the notebook just fine.

When you use `@bind`, your notebook can still run without Pluto! Sort of. Normally, all bound variables are assigned the value `missing` when you run it elsewhere. However, the `PlutoUI` types have all been configured to assign a more sensible default value.

For example, if your notebook contains
```julia
@bind x Slider(10:20)
```
and you run it without Pluto, then this statement simply assigns `x = 10`.
"

# ╔═╡ 0cda8986-cc64-11ea-2acc-b5c38fdf17e5

# ╔═╡ 0da7bc30-cc64-11ea-1dde-2b7f2dd76036
md"`Pluto` and `PlutoUI` work independently of each other! In fact, _you_ could write a package with fun input elements, or add `@bind`able values to existing packages."

# ╔═╡ 512fe760-cc4c-11ea-1c5b-2b32da035aad
md"# Appendix"

# ╔═╡ 55bcdbf8-cc4c-11ea-1549-87c076a59ff4
space = html"

"

# ╔═╡ fb6142f6-c765-11ea-29fd-7ff4e823c02b
space

# ╔═╡ ebfc61b0-c765-11ea-1d66-cbf1dcdb8bdb
space

# ╔═╡ f69a5d5e-c765-11ea-3fa0-230c6c619730
space

# ╔═╡ 0b66c781-ecf2-445e-b2aa-82cb13371e46
space

# ╔═╡ 35523932-cc4f-11ea-0908-2d51c57176b7
space

# ╔═╡ d163f434-cc5a-11ea-19e9-9319ba994efa
space

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
PlutoUI = "~0.7.24"
"""

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

[[AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "abb72771fd8895a7ebd83d5632dc4b989b022b5b"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.2"

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

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

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

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

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

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

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

[[Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

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

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

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

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

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

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

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

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

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

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

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

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

[[PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "6c9fa3e4880242c666dafa4901a34d8e1cd1b243"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.24"

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

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

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

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

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

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

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

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

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

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

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

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

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

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

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

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

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

# ╔═╡ Cell order:
# ╟─bc532cd2-c75b-11ea-313f-8b5e771c9227
# ╟─3eff9592-cc63-11ea-2b61-4170d1a7656a
# ╟─051f31fc-cc63-11ea-1e2c-0704285ea6a9
# ╠═071d9ca5-9b42-4583-ad96-a48f93453a0e
# ╟─fb6142f6-c765-11ea-29fd-7ff4e823c02b
# ╟─fddb794c-c75c-11ea-1f55-eb9c178424cd
# ╟─b819e9a8-c760-11ea-11ee-dd01da663b5c
# ╠═34ebf81e-c760-11ea-05bb-376173e7ed10
# ╠═a4488984-c760-11ea-2930-871f6b400ef5
# ╟─1048d1e0-cc50-11ea-1bf3-d76cae42740a
# ╟─a709fd2e-c760-11ea-05c5-7bf673990de1
# ╠═d3811ac2-c760-11ea-0811-131d9f1d3910
# ╠═dfe10b6c-c760-11ea-2f77-79cc4cfa8dc4
# ╟─06962cde-cc4f-11ea-0d96-69a8cb7eeda2
# ╟─6605d010-d0d1-4cc8-a34d-3158b8572b5d
# ╠═756e2c82-6e2f-4d7b-a1ed-5de97be04269
# ╠═c07c5a9e-61f9-4247-86e7-7c3f9956d0ff
# ╟─c3fea1b2-fc11-4c19-9c01-a8e03fda2817
# ╟─221c308e-3cbe-4689-aa67-8970957f8cb0
# ╟─e49623ac-c760-11ea-3689-c15f2e2f6081
# ╠═314cb85a-c761-11ea-1cba-b73f84a52be8
# ╟─3c68b25c-c761-11ea-226a-4f46579a6732
# ╟─104b55ce-cc4f-11ea-1273-092a1717e399
# ╟─4513b730-c761-11ea-1460-2dca56081fcf
# ╠═4f8e4e1e-c761-11ea-1787-419cab59bb12
# ╟─b787ead6-c761-11ea-3b17-41c0a5434f9b
# ╟─177e6bf0-cc50-11ea-0de2-e77544f5c615
# ╟─b08c347e-c761-11ea-1b61-7b69631d078b
# ╠═b53c8ffa-c761-11ea-38d1-2d4ad96a7bee
# ╟─adcf4e68-c761-11ea-00bb-c3b15c6dedc0
# ╟─1a562ad4-cc50-11ea-2485-cdec6e1a78dc
# ╟─5d420570-c764-11ea-396b-cf0db01d34aa
# ╟─09393bf2-cc4f-11ea-1e48-cfbedab8e6b4
# ╟─cd1b5872-c761-11ea-2179-57a3cb34d235
# ╠═d9e85ed0-c761-11ea-30bf-83ce272526e0
# ╟─e4c262d6-c761-11ea-36b2-055419bfc981
# ╟─0934bc0c-cc50-11ea-0da8-0d6b2f275399
# ╟─e690337c-c761-11ea-08be-ade40a464eb4
# ╠═f1f83980-c761-11ea-1e34-97c0ffca3f67
# ╟─f985c8de-c761-11ea-126c-1fd79d547b79
# ╟─1cbfd28e-cc50-11ea-2c90-a7807e4979ef
# ╟─0136af80-c762-11ea-2f1a-9dccff334a11
# ╠═0e6f0508-c762-11ea-0352-09bd694a9b35
# ╠═3dcd7002-c765-11ea-323d-a1fb49409011
# ╟─0aa3c85e-cc4f-11ea-2fba-4bdd513d9217
# ╟─5833f7f4-c763-11ea-0b95-9b21a40192a9
# ╠═690cf3ac-c763-11ea-10f0-b3e28c380be9
# ╠═705662e2-c763-11ea-2f6d-cdaffc1fc73a
# ╠═1feebd8f-667a-42fd-965d-5e3167ff7c7a
# ╠═9128d2c1-364c-4446-baaa-6d0593edda47
# ╟─3930f0d8-cc50-11ea-3de6-d91ac5c6cd9f
# ╟─787a2c88-c763-11ea-0a32-bb91ca60113d
# ╠═ac8c4dee-c763-11ea-1b2d-c590a2d50d7e
# ╠═dcda9ad2-c763-11ea-3ec6-093b823ba66d
# ╟─0c3ab1f8-cc4f-11ea-0cfb-8f076d2c9836
# ╟─62c6f866-f0fe-11ea-0961-319f28d040d4
# ╠═a01c8096-f0fe-11ea-3e78-ad8551e84fa1
# ╠═a20e30f2-f0fe-11ea-0ca7-c5195c9eb24a
# ╟─c819ef3e-f0fe-11ea-1213-9df7597e4e89
# ╟─b104ba6d-0293-4378-9652-f628f1d08d97
# ╠═16f2218d-f1bc-4b34-a355-53acfa77fbf5
# ╠═2c7811cb-d9ea-470c-8cb7-2b3803489f3f
# ╟─78be41d1-7dda-4bec-b75f-fbcf8b7594a7
# ╠═90d84f1b-042c-444e-8bac-fe358b6d68a1
# ╠═b97cfb04-0c39-4709-9419-9294e677a872
# ╟─283d1177-c605-4652-905b-9a70354cf878
# ╟─0b1ce22e-c764-11ea-3d60-e799d58aee30
# ╠═6d9108a8-c765-11ea-0a38-09a1364998b1
# ╠═7a14e496-c765-11ea-20a1-6fb960009251
# ╟─3eff932a-cc50-11ea-366e-812d3854dd4c
# ╟─7e10fb52-c765-11ea-2a71-0fc347d09885
# ╠═b91764e8-c765-11ea-27a2-4ba5777fbd89
# ╠═bb356b12-c765-11ea-2c36-697f4314bb93
# ╟─9276da28-cc4f-11ea-17b3-65eec41a181e
# ╟─92def54a-cc4f-11ea-12c5-652f2bb46413
# ╠═9920e56c-cc4f-11ea-2d5e-f5371c79f048
# ╠═44591b34-cc50-11ea-2005-2f7075e6f2db
# ╟─4fda3072-cc50-11ea-2804-197b6391b269
# ╟─ebfc61b0-c765-11ea-1d66-cbf1dcdb8bdb
# ╟─3e5dd7d2-c760-11ea-1dca-6d8720b3558d
# ╟─f31668c6-c768-11ea-1501-5f41afa7c83b
# ╠═417390ba-c760-11ea-27df-5908858ae88c
# ╠═49e7cd06-c760-11ea-3f5d-2741d94278a6
# ╟─31a2f3c4-cc51-11ea-3652-bd814517a4b5
# ╟─67709812-c760-11ea-2bda-9756ead35749
# ╠═4c2b45a0-c760-11ea-2b64-3fefc820cd5b
# ╠═5be148cc-c760-11ea-0819-a7bb403d27ff
# ╟─347e3d06-cc51-11ea-012c-43e824eaffa2
# ╟─343d7118-cc51-11ea-387a-fb22d8c73506
# ╟─32e41ac2-cc51-11ea-3358-bbead9c68123
# ╟─f74f434a-c768-11ea-079c-fb707e6ba17b
# ╟─ea00721c-cc4b-11ea-1e82-0b3dbe6a7f1e
# ╠═fc12280c-c768-11ea-3ebc-ebcd6b3459c1
# ╠═067cbcde-cc4c-11ea-3eed-972dc6d7bb3b
# ╟─f69a5d5e-c765-11ea-3fa0-230c6c619730
# ╟─7da30d97-b28a-4eb9-a2ef-fad599b549d1
# ╟─170089cd-f366-4c0a-b58d-fe6e36049db7
# ╠═b29215cb-8e7e-4382-822c-cdaa4c473ba1
# ╠═00f9f608-85bd-4932-b585-39f74dcf53b4
# ╟─48a9ffbd-cac7-4c4e-85e5-c3d0693e5550
# ╟─5c85ee41-da68-4f5f-b45e-e1de7996747d
# ╟─8c51343f-cb35-4ff9-9fd8-642ffab57e22
# ╠═621f2e82-5ab4-4ab9-a0ff-fb1cc1b41295
# ╟─a4837897-caae-447a-8db9-7775e7a4d0c8
# ╠═f5c421cc-dbdb-459a-9bb4-d648507a87d2
# ╠═a4eac824-ba87-473a-b39a-783c4de3f933
# ╠═f9052ed8-84cc-4cca-abb2-9363aafc6040
# ╠═d278189e-6a5b-428a-8c81-ce3d206b042c
# ╟─4ca9c749-08ee-467f-af2c-9b2f13199d72
# ╟─0b66c781-ecf2-445e-b2aa-82cb13371e46
# ╟─ad8e9b30-c75d-11ea-1fd0-0b53592135bf
# ╟─87d088d0-cc54-11ea-02c6-bd673b95b9d3
# ╟─6a7e7e54-c75e-11ea-2ea7-ed3da37e9e96
# ╟─9ac7921c-c75e-11ea-30f5-c35e6ee370cb
# ╟─a8c57442-c75e-11ea-1913-7d82cbd2c69c
# ╠═cb37b916-c75b-11ea-0c83-6ba759536075
# ╠═16ea31fc-c75e-11ea-0f2d-dd790a56b2dc
# ╠═1dfd8cc6-c75e-11ea-3c04-a96734779c97
# ╟─2fda30ea-c75e-11ea-2ff5-7f2dcf4f9b66
# ╠═525ceea0-c75e-11ea-2766-f72418fd784e
# ╠═382d41d8-c75e-11ea-2ae3-2ffe96e04b5a
# ╟─958ab19c-cc56-11ea-162e-d3664e66ff66
# ╠═8477619c-cc57-11ea-0618-1778c502d28f
# ╟─f743076c-cc57-11ea-1a8e-8799d9db985a
# ╟─c65d28a2-c75d-11ea-2e13-7332f93d9c5e
# ╟─c16dff74-cc5d-11ea-380c-aff1639b5551
# ╟─dada2154-c75d-11ea-2312-b9156a9a531e
# ╠═f809110c-cc55-11ea-1551-e138c28d5d82
# ╟─1c930364-cc58-11ea-36c8-0ddf7c4700cd
# ╟─c48b48f6-cc5d-11ea-0f3b-d3481238625d
# ╟─ea6ade22-cc5a-11ea-1782-97f2464fd148
# ╟─35523932-cc4f-11ea-0908-2d51c57176b7
# ╟─a245dddc-cc59-11ea-3e1d-1763673ff706
# ╟─0cda8986-cc64-11ea-2acc-b5c38fdf17e5
# ╟─0da7bc30-cc64-11ea-1dde-2b7f2dd76036
# ╟─d163f434-cc5a-11ea-19e9-9319ba994efa
# ╟─512fe760-cc4c-11ea-1c5b-2b32da035aad
# ╠═55bcdbf8-cc4c-11ea-1549-87c076a59ff4
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
"""
    dimnames(x)

Returns a tuple of names for each dimension of `x`. If `x` is an `AbstractUnitRange`
then a `Symbol` will be returned if it has a name and `nothing` will be returned
if it doesn't.

## Examples
```jldoctest
julia> dimnames(Index{:a}(1:10))
:a

julia> dimnames(1:10)

julia> dimnames((Index{:a}(1:10), 1:10)
(:a, nothing)
```
"""
dimnames(::AbstractIndex{name}) where {name} = name
dimnames(::AbstractUnitRange) = nothing
dimnames(x::AbstractArray) = dimnames(axes(x))
dimnames(x::AbstractArray, i::Int) = dimnames(axes(x, i))
dimnames(x::Tuple{Any,Vararg}) = (dimnames(first(x)), dimnames(tail(x))...)
dimnames(x::Tuple{}) = ()

"""
    to_dims(a, dims::Tuple) -> NTuple{N,Int}
    to_dims(a, dims) -> Int

Given an array or tuple of indices `a` returns the dimensions corresponding to
`dims` as `Int`. If `dims` is an integer this simply ensures that it is an `Int`
or converted to one. If `dims` is a `Symbol` this returns the dimension corresponding
to the provided name. If the named dimension is not present an error is returned.

## Examples
```jldoctest
julia> axs = (Index{:a}(1:10), Index{:b}(1:10), Index(1:10));

julia> to_dims(axs, :a)
1

julia> to_dims(axs, :b)
2

julia> to_dims(axs, (:a, :b))
(1, 2)
```
"""
@inline to_dims(x::AbstractArray, d) = to_dims(axes(x), d)
@inline to_dims(x::Tuple, d) = _to_dims(x, d)

_to_dims(x::Tuple, d::Tuple) = (_to_dims(x, first(d)), _to_dims(x, tail(d))...)
_to_dims(x::Tuple, d::Tuple{}) = ()
_to_dims(x::Tuple, d::Union{Int,Colon}) = d
_to_dims(a::AbstractArray, d::Integer) = Int(d)

function _to_dims(x::Tuple, n::Symbol)::Int
    dimnum = __to_dim(x, n)
    if dimnum === 0
        throw(ArgumentError(
            "Specified name ($(repr(n))) does not match any dimension name ($x)"
        ))
    end
    return dimnum
end

function __to_dim(axs::NTuple{N,Any}, name::Symbol) where N
    for ii in 1:N
        dimnames(getfield(axs, ii)) === name && return ii
    end
    return 0
end

"""
    unname(x)

Remove the name from a `x`. If `x` doesn't have a name the same instance of `x`
is returned.

## Examples
```jldoctest
julia> aidx, nidx, uidx, = Index{:a}(1:10), Index(1:10), 1:10

julia> unname(aidx)
Index(1:10)

julia> unname(nidx)
Index(1:10)

julia> unname(uidx)
1:10
```
"""
unname(x) = copy(x)
unname(nt::NamedTuple{names}) where {names} = Tuple(nt)
unname(x::Tuple) = unname.(x)
unname(idx::Index) = Index(keys(idx), values(idx), AllUnique, LengthChecked)
unname(si::SimpleIndex) = SimpleIndex(keys(si))


text:
# In this file, methods for the abstract type `AbstractConfig` are defined.
# An implementation of a subtype can overwrite these.
# Else, they work as a default.
# `AbstractConfig` has a type parameter `F<:AbstractFloat` indicating
# the data precision. It usually does not matter for thresholds, but some
# methods return parameters that influence either `x` or `Δ`.
# If not clear, possible return types are indicated for the implementation of subtypes.

Broadcast.broadcastable( ac :: AbstractConfig ) = Ref( ac )

# Criticality Test parameters
# # ω threshold
_eps_crit( :: AbstractConfig ) :: Float64 = 1e-3
# # shrinking in critical loop
_gamma_crit( ::AbstractConfig ) :: Float64 = .501;

# # maximum number of loops before exiting
max_critical_loops( :: AbstractConfig ) :: Int = 5

# is a database used? if yes, what is the type?
use_db( :: AbstractConfig ) :: Bool = true

# should iterations, where the models are not fully linear, be counted for stopping?
count_nonlinear_iterations( :: AbstractConfig ) :: Bool = true

# initial box radius (for fully constrained problems this is relative to ``[0,1]^n```)
get_delta_0(::AbstractConfig) :: NumOrVec64 = 0.1

# radius upper bound(s)
get_delta_max(::AbstractConfig) :: NumOrVec64 = 0.5

# STOPPING
# restrict number of evaluations and iterations
max_evals( :: AbstractConfig ) :: Int = typemax(Int)
max_iter( :: AbstractConfig ) :: Int = 50

# relative stopping
# stop if ||Δf|| ≤ ε ||f|| (or |Δf_ℓ| .≤ ε |f_ℓ| )
f_tol_rel( :: AbstractConfig ) :: NumOrVec64 = 1e-8
# stop if ||Δx|| ≤ ε ||x||
x_tol_rel( :: AbstractConfig ) :: NumOrVec64 = 1e-8

# absolute stopping
f_tol_abs( :: AbstractConfig ) :: NumOrVec64 = -1.0
x_tol_abs( :: AbstractConfig ) :: NumOrVec64 = -1.0

# stop if ω ≤ omega_tol_rel && Δ .≤ Δ_tol_rel
omega_tol_rel( :: AbstractConfig ) :: Float64 = 1e-3
delta_tol_rel( :: AbstractConfig ) :: NumOrVec64 = 1e-2

# stop if ω <= omega_tol_abs
omega_tol_abs(ac :: AbstractConfig ) :: Float64 = -1.0

# stop if Δ .<= Δ_tol_abs
delta_tol_abs(ac :: AbstractConfig ) :: NumOrVec64 = 1e-6

# what method to use for the subproblems
descent_method( :: AbstractConfig ) :: Union{AbstractDescentConfig,Symbol} = :steepest_descent

# acceptance test parameters
strict_acceptance_test( :: AbstractConfig ) :: Bool = true
_nu_success( :: AbstractConfig ) :: Float64 = 0.2
_nu_accept(::AbstractConfig) :: Float64 = 1e-3

_mu(::AbstractConfig) :: Float64 = 2e3
_beta(::AbstractConfig) :: Float64 = 1e3

# Parameters for the radius update
radius_update_method(::AbstractConfig)::Symbol = :standard
_gamma_grow(::AbstractConfig) :: Float64 = 2.0
_gamma_shrink(::AbstractConfig) :: Float64 = .75
_gamma_shrink_much(::AbstractConfig) :: Float64 = .501


text:
using HelloWorld
using Test

@testset "HelloWorld.jl" begin
    # Write your tests here.
end


text:
module Lithium

using DataFrames
using LaTeXStrings
using Missings
using MLJ
using Distributions
using Plots

include("analysis.jl")  # Experimental designs
include("cb.jl")        # Causal bootstrapping
include("criticism.jl") # Performance evaluation functions
include("dataio.jl")    # Data cleaning/preprocessing
include("heterogeneity.jl") # Heterogeneity analysis functions
include("models.jl")    # Model specifications
include("qc.jl")        # Quality control functions

# Analyses functions
export classification_analysis
export pca_plot
export shuffle_split
export split_prune_bootstrap

# Causal bootstrapping functions
export cb_backdoor_discrete
export discrete_causal_bootstrapping

# Criticism functions
export classification_report
export classification_predictions
export store_classification_results
export summarize_classification_results
export store_classification_predictions
export compute_reliability_curve
export plot_reliability_curves
export plot_roc_curves

# DataIO functions
export remove_columns
export remove_ltg_targets, remove_vpa_targets
export remove_ids, remove_opcrit, remove_excluded_variables
export remove_n_episode_outliers

export probands_only
export limit_to_bd_diagnosis
export merge_mania_hypomania_ageofonset
export normalize_family_history
export narrow_comorbidity_definition
export replace_centre_names
export remove_incomplete_targets
export remove_incomplete_li_target_binary
export remove_incomplete_li_target_numerical
export remove_lowvar
export compute_alda_b_score, compute_alda_total_score
export unpack_features_targets_covariates
export prune_missingness
export coerce_scitypes

# Heterogeneity
export renyi, renyi_pooled, renyi_within, renyi_between

# Model functions
export linear_classifier
export rf_classifier

# QC
export filter_qc_exclusions
export qc_age_consistency

end