text:
####################################################################################################################
#### Load packages ####
using Pkg
Pkg.activate(".")
Pkg.add("JuMP")
Pkg.add("Combinatorics")
Pkg.add("DataFrames")
Pkg.add("CSV")
Pkg.add("ExcelFiles")
Pkg.add("CSVFiles")
Pkg.add("DelimitedFiles")
Pkg.add("XLSX")
Pkg.add("BenchmarkTools")
Pkg.add("GLPK")
Pkg.add("Plots")
Pkg.add("StatsPlots")
Pkg.add(Pkg.PackageSpec(name = "Gurobi", version = v"0.9.4"))

## Precompile project
Pkg.precompile()

using JuMP
using Combinatorics
using DataFrames
using CSV
using ExcelFiles
using DelimitedFiles
using XLSX
using BenchmarkTools
using GLPK
using Gurobi

####################################################################################################################
# #### Data Prep ####
model_first = 0;
model_last = 4;

for i in (model_first:model_last)

    println("Scenario $i initiated")

    ##### Sets #####
    # read sets
    sets_df = load("Scenario$i.xlsx", "sets") |> DataFrame;
    sets_df;
    set_K = sets_df[!,:K];
    set_S = sets_df[!,:S];
    set_L = sets_df[!,:L];
    set_N = sets_df[!,:N];

    set_K = findall(!ismissing, set_K);
    set_S = findall(!ismissing, set_S);
    set_L = findall(!ismissing, set_L);
    set_N = findall(!ismissing, set_N);

    set_A = [(i,j) for (i,j) in permutations(set_N,2) if i != j];
    set_IL = [(i,l) for i in set_N for l in set_L];
    set_KN = [(k,i) for k in set_K for i in set_N];
    set_KSA = [(k,s,i,j) for k in set_K for s in set_S for (i,j) in set_A];
    set_KSN = [(k,s,i) for k in set_K for s in set_S for i in set_N];

    ##### Parameters with multiple indices #####
    # Read from input data file
    param_c_df = load("Scenario$i.xlsx", "param_cc") |> DataFrame;
    # Convert and create parameters
    param_c_df[!,[:k, :s, :i, :j]] = convert.(Int,param_c_df[!,[:k, :s, :i, :j]]) #convert to int
    param_c_df[!,:index] = zip(param_c_df[!,:k], param_c_df[!,:s],param_c_df[!,:i],param_c_df[!,:j]) |> collect #create index col
    param_c_df = DataFrames.select!(param_c_df,[:index,:value]);
    param_c = eachrow(param_c_df) |> Dict # convert to dict type

    param_U_df = load("Scenario$i.xlsx", "param_U") |> DataFrame;
    param_U_df[!,[:s, :i, :j]] = convert.(Int,param_U_df[!,[:s, :i, :j]]);
    param_U_df[!,:index] = zip(param_U_df[!,:s],param_U_df[!,:i],param_U_df[!,:j]) |> collect;
    param_U_df = DataFrames.select!(param_U_df,[:index,:value]);
    param_U = eachrow(param_U_df) |> Dict;

    param_v_df = load("Scenario$i.xlsx", "param_vv") |> DataFrame;
    param_v_df[!,[:k,:s,:i]] = convert.(Int,param_v_df[!,[:k,:s,:i]]);
    param_v_df[!,:index] = zip(param_v_df[!,:k], param_v_df[!,:s],param_v_df[!,:i]) |> collect;
    param_v_df = DataFrames.select!(param_v_df,[:index,:value]);
    param_v = eachrow(param_v_df) |> Dict;

    param_prop_df = load("Scenario$i.xlsx", "param_prop") |> DataFrame;
    param_prop_df[!,[:k,:s,:i]] = convert.(Int,param_prop_df[!,[:k,:s,:i]]);
    param_prop_df[!,:index] = zip(param_prop_df[!,:k], param_prop_df[!,:s],param_prop_df[!,:i]) |> collect;
    param_prop_df = DataFrames.select!(param_prop_df,[:index,:value]);
    param_prop = eachrow(param_prop_df) |> Dict;

    param_F_df = load("Scenario$i.xlsx", "param_F") |> DataFrame;
    param_F_df[!,[:i,:l]] = convert.(Int,param_F_df[!,[:i,:l]]);
    param_F_df[!,:index] = zip(param_F_df[!,:i], param_F_df[!,:l]) |> collect;
    param_F_df = DataFrames.select!(param_F_df,[:index,:value]);
    param_F = eachrow(param_F_df) |> Dict;

    param_d_df = load("Scenario$i.xlsx", "param_dd") |> DataFrame;
    param_d_df[!,[:i,:j]] = convert.(Int,param_d_df[!,[:i,:j]]);
    param_d_df[!,:index] = zip(param_d_df[!,:i], param_d_df[!,:j]) |> collect;
    param_d_df = DataFrames.select!(param_d_df,[:index,:value]);
    param_d = eachrow(param_d_df) |> Dict;

    ##### Parameters with single index #####
    param_M_df = load("Scenario$i.xlsx", "param_M") |> DataFrame;
    param_M_df[!,[:index]] = convert.(Int,param_M_df[!,[:index]]);
    param_M = eachrow(param_M_df) |> Dict;

    param_b_df = load("Scenario$i.xlsx", "param_bb") |> DataFrame;
    param_b_df[!,[:index]] = convert.(Int,param_b_df[!,[:index]]);
    param_b = eachrow(param_b_df) |> Dict;

    param_q_df = load("Scenario$i.xlsx", "param_qq") |> DataFrame;
    param_q_df[!,[:index]] = convert.(Int,param_q_df[!,[:index]]);
    param_q = eachrow(param_q_df) |> Dict;

    param_h_df = load("Scenario$i.xlsx", "param_hh") |> DataFrame;
    param_h_df[!,[:index]] = convert.(Int,param_h_df[!,[:index]]);
    param_h = eachrow(param_h_df) |> Dict;

    param_p_df = load("Scenario$i.xlsx", "param_pp") |> DataFrame;
    param_p_df[!,[:index]] = convert.(Int,param_p_df[!,[:index]]);
    param_p = eachrow(param_p_df) |> Dict;

    param_P_df = load("Scenario$i.xlsx", "param_P") |> DataFrame;
    param_P_df[!,[:index]] = convert.(Int,param_P_df[!,[:index]]);
    param_P = eachrow(param_P_df) |> Dict;

    param_u_df = load("Scenario$i.xlsx", "param_uu") |> DataFrame;
    param_u_df[!,[:index]] = convert.(Int,param_u_df[!,[:index]]);
    param_u = eachrow(param_u_df) |> Dict;

    param_bigM_df = load("Scenario$i.xlsx", "param_bigM") |> DataFrame;
    param_bigM_df[!,[:index]] = convert.(Int,param_bigM_df[!,[:index]]);
    param_bigM = eachrow(param_bigM_df) |> Dict;

    # Adjusting parameters
    param_D_df = load("Scenario$i.xlsx", "param_D") |> DataFrame;
    param_D_df[!,[:index]] = convert.(Int,param_D_df[!,[:index]]);
    param_D = eachrow(param_D_df) |> Dict;

    param_alpha_df = load("Scenario$i.xlsx", "param_alpha") |> DataFrame;
    param_alpha_df[!,[:index]] = convert.(Int,param_alpha_df[!,[:index]]);
    param_alpha = eachrow(param_alpha_df) |> Dict;

    println("Parameters set up successfully for scenario $i")
    ####################################################################################################################
    #### Model Prep ####
    # Time the model
    TimeTrack_start = time();

    # Preparing an optimization model
    m = Model(Gurobi.Optimizer);
    # m = Model(GLPK.Optimizer);

    ##Declaring variables

    # variables
    @variable(m, y[index in set_IL], Bin);
    @variable(m, r[index in set_KN] >= 0,Int);
    @variable(m, x[index in set_KSA] >= 0,Int);
    @variable(m, z[index in set_KSN] >= 0,Int);
    @variable(m, w[index in set_KSN] >= 0,Int);
    @variable(m, gamma[s in set_S], Bin);

    ##Objective function
    @objective(m, Min, sum(param_F[(i,l)] * y[(i,l)] for (i,l) in set_IL) # Fix Cost
                        + sum(param_q[k] * r[(k,n)] for (k,n) in set_KN)  # Preposition Cost
                        + sum(param_P[s] * param_c[(k,s,i,j)] * x[(k,s,i,j)] for (k,s,i,j) in set_KSA) # Scenario Specific Cost 1
                        + sum(param_P[s] * param_h[k] * z[(k,s,i)] + param_P[s] * param_p[k] * w[(k,s,i)] for (k,s,i) in set_KSN) # Scenario Specific Cost 2
                );

    ##Constraints
    # Flow Conservation
    fc = @constraint(m, fc[k in set_K, s in set_S, i in set_N],
                            sum(x[(k,s,j,i)] for j in set_N if j != i) + param_prop[(k,s,i)]* r[(k,i)] - z[(k,s,i)]
                            ==
                            sum(x[(k,s,i,j)] for j in set_N if j != i) + param_v[(k,s,i)] - w[(k,s,i)]
                );

    # Open Facility Capacity
    ofc = @constraint(m, ofc[i in set_N],
                        sum(param_b[k] * r[(k,i)] for k in set_K)
                        <=
                        sum(param_M[l] * y[(i,l)] for l in set_L)
                );
    # Facility Number per Node
    fpn = @constraint(m, fpn[i in set_N],
                    sum(y[(i,l)] for l in set_L)
                    <=
                    1
                );
    # Arc Capacity
    ac = @constraint(m, ac[s in set_S, (i,j) in set_A],
                    sum(param_u[k] * x[(k,s,i,j)] for k in set_K)
                    <=
                    param_U[(s,i,j)]
                );

    # Average Distance Limit
    adl = @constraint(m, adl[k in set_K, s in set_S],
                        sum(param_d[(i,j)] * x[(k,s,i,j)] for (i,j) in set_A)
                        <=
                        param_D[k] * sum(param_v[(k,s,i)] for i in set_N) + param_bigM[1] * (1 - gamma[s])
                );

    # Reliability Set Definition
    rsd = @constraint(m, rsd,
                    sum(param_P[s] * gamma[s] for s in set_S)
                    >=
                    param_alpha[1]
                );

    # Demand requirements for scenarios in reliable set
    dmrs = @constraint(m, dmrs[k in set_K, s in set_S, i in set_N],
                        w[(k,s,i)]
                        <=
                        param_v[(k,s,i)] * (1 - gamma[s])
                );

    println("Model successfully set up for scenario $i")
    ####################################################################################################################
    #### Model solving ####

    # Printing the prepared optimization model
    # print(m);

    # Solving the optimization problem
    JuMP.optimize!(m);
    TimeTrack_elapsed = time() - TimeTrack_start;

    ####################################################################################################################
    #### Post-processing ####

    # Print result
    println("Model running time is: ", round(TimeTrack_elapsed,digits = 5),"s")
    println("Model solving time:",round(JuMP.solve_time(m),digits = 5), "s")

    # save the optimized variables to *_star
    y_star = JuMP.value.(y);
    r_star = JuMP.value.(r);
    x_star = JuMP.value.(x);
    z_star = JuMP.value.(z);
    w_star = JuMP.value.(w);
    gamma_star = JuMP.value.(gamma);

    # Print objective value
    println("Objective value: ", JuMP.objective_value(m))

    # Print the non-zero variables
    println("If a variable is not printed, the value is 0!")
    for (i,l) in set_IL
        if y_star[(i,l)] == 1
            println("facility $l located in node $i")
        else end
    end;

    for (k,i) in set_KN
        if r_star[(k,i)] > 0
            println("Amount of commodity $k pre-position at node $i: ", r_star[(k,i)])
        else end
    end;

    for (k,s,i,j) in set_KSA
        if x_star[(k,s,i,j)] > 0
        println("Amount of commodity $k shipped across link ($i,$j) in scenario $s: ", x_star[(k,s,i,j)])
        else end
    end;

    for (k,s,i) in set_KSN
        if z_star[(k,s,i)] > 0
            println("Commodity $k not used in scenario $s at node $i: ", z_star[(k,s,i)] )
        else end
    end;

    for (k,s,i) in set_KSN
        if w_star[(k,s,i)] > 0
            println("Shortage of commodity $k at node $i in scenario $s: ", w_star[(k,s,i)])
        else end
    end;

    for s in set_S
        if gamma_star[s] > 0
            println("Scenario $s belong to the reliable set")
        else end
    end;

    ####################################################################################################################
    #### Export Results ####

    # Write result to data frames
    y_df = DataFrame(variable_type =[], index=[],value=[]);
    for (i,l) in set_IL
        val = y_star[(i,l)]
        push!(y_df, vcat("y",(i,l),val))
    end;

    r_df = DataFrame(variable_type =[],index=[],value=[]);
    for (k,i) in set_KN
        val = r_star[(k,i)]
        push!(r_df, vcat("r",(k,i),val))
    end;

    x_df = DataFrame(variable_type =[],index=[],value=[]);
    for (k,s,i,j) in set_KSA
        val = x_star[(k,s,i,j)]
        push!(x_df, vcat("x",(k,s,i,j),val))
    end;

    z_df = DataFrame(variable_type =[],index=[],value=[]);
    for (k,s,i) in set_KSN
        val = z_star[(k,s,i)]
        push!(z_df, vcat("z",(k,s,i),val))
    end;

    w_df = DataFrame(variable_type =[],index=[],value=[]);
    for (k,s,i) in set_KSN
        val = w_star[(k,s,i)]
        push!(w_df, vcat("w",(k,s,i),val))
    end;

    gamma_df = DataFrame(variable_type =[],index=[],value=[]);
    for s in set_S
        val = gamma_star[s]
        push!(gamma_df, vcat("gamma",s,val))
    end;

    # Merge all the data frames together
    result_df = DataFrame(variable_type=[], index=[], value=[]);
    result_df = DataFrames.append!(result_df,y_df);
    result_df = DataFrames.append!(result_df,r_df);
    result_df = DataFrames.append!(result_df,x_df);
    result_df = DataFrames.append!(result_df,z_df);
    result_df = DataFrames.append!(result_df,w_df);
    result_df = DataFrames.append!(result_df,gamma_df);

    # Export the merged data frame
    CSV.write("output_var$i.csv",result_df);

    # Export Objective value and Running Time (Add another column for model no)
    vars_no = length(y_star) + length(r_star) + length(x_star) + length(z_star) + length(w_star)
    constraint_no = length(fc) + length(ofc) + length(fpn) + length(ac) + length(adl) + 1 + length(dmrs)
    stat_df = DataFrame(scenario=[], objective_value = [], modeling_time = [], solve_time = [],
                        vars_no = [], y_no = [], r_no = [] , x_no = [], z_no =[] , w_no = [],
                        constraint_no = [], fc_no = [], ofc_no = [], fpn_no = [],ac_no = [], adl_no = [], rsd_no = [], dmrs_no = []
                        );
    DataFrames.push!(stat_df, vcat(i, JuMP.objective_value(m), round(TimeTrack_elapsed,digits = 5), round(JuMP.solve_time(m),digits = 5),
    vars_no,length(y_star), length(r_star), length(x_star), length(z_star), length(w_star),
    constraint_no,length(fc),length(ofc),length(fpn),length(ac),length(adl),1,length(dmrs)
    ));

    CSV.write("output_stat$i.csv",stat_df);

    println("Results successfully exported for scenario $i");

end


text:
using LightGraphs
import LightGraphs: add_vertex!, add_edge!, SimpleDiGraph
using LazyArtifacts

# Dependency graph struct creation
# --------------------------------

"""
    IDSGraph([input])

Create a graph representation of IDS data; if no input is provided, an empty graph will be
created. The input can be a symbol representing a dataset to load, or it can be something
readable by `eachline`.

# Available IDS Datasets
* `:ids` - the default IDS file
"""
IDSGraph

struct IDSGraph <: AbstractGraph{Char}
    graph::SimpleDiGraph{UInt32}
    mapping::Dict{Char, UInt32}
    reverse_mapping::Vector{Char}
    structures::Dict{Char, AbstractCharStructure}
end

function IDSGraph()
     IDSGraph(
        SimpleDiGraph{UInt32}(),
        Dict{Char, UInt32}(),
        Vector{Char}(),
        Dict{Char, AbstractCharStructure}())
end
function IDSGraph(filename::Union{AbstractString, IO})
    dep = IDSGraph()

    for line in eachline(filename)
        startswith(line, "#") && continue

        m = match(r"^[^\s]+\s+([^\s])\s+(.+)$", line)
        m === nothing && continue
        char_str, ids_string = m.captures
        char = first(char_str)

        add_vertex!(dep, char)
        for component in filter(c -> c ∉ '⿰':'⿻' && c != char, ids_string)
            add_edge!(dep, component, char)
        end
        dep.structures[char] = parse(ids_string)
    end

    dep
end
function IDSGraph(src::Symbol)
    if src == :ids
        return IDSGraph(joinpath(artifact"ids", "ids.txt"))
    else
        throw(ArgumentError("unknown identifier $(src) for a IDS file"))
    end
end

function LightGraphs.add_vertex!(dep::IDSGraph, vertex::Char)
    if !haskey(dep.mapping, vertex)
        add_vertex!(dep.graph)
        dep.mapping[vertex] = nv(dep.graph)
        push!(dep.reverse_mapping, vertex)
    end
    dep
end

function LightGraphs.add_edge!(dep::IDSGraph, from::Char, to::Char)
    add_vertex!(dep, from)
    add_vertex!(dep, to)
    add_edge!(dep.graph, dep.mapping[from], dep.mapping[to])
    dep
end

# new edge type
"""Graph edge between 2 `Char` instances."""
struct CharEdge <: LightGraphs.AbstractEdge{Char}
    src::Char
    dest::Char
end

LightGraphs.src(c::CharEdge) = c.src
LightGraphs.dst(c::CharEdge) = c.dest

# abstract graph interface
LightGraphs.vertices(dep::IDSGraph) = (v for v in dep.reverse_mapping)
LightGraphs.edges(dep::IDSGraph) = (CharEdge(src(edge), dst(edge)) for edge in edges(dep.graph))

Base.eltype(::Type{IDSGraph}) = Char

LightGraphs.edgetype(dep::IDSGraph) = CharEdge

#LightGraphs.has_contiguous_vertices(::Type{IDSGraph}) = false

LightGraphs.has_vertex(dep::IDSGraph, v) = haskey(dep.mapping, v)
LightGraphs.has_edge(dep::IDSGraph, s, d) =
    LightGraphs.has_edge(dep.graph, dep.mapping[s], dep.mapping[d])

LightGraphs.inneighbors(dep::IDSGraph, v) = collect(components(dep, v))
LightGraphs.outneighbors(dep::IDSGraph, v) = collect(compounds(dep, v))

LightGraphs.ne(dep::IDSGraph) = LightGraphs.ne(dep.graph)
LightGraphs.nv(dep::IDSGraph) = length(dep.reverse_mapping)

Base.zero(dep::IDSGraph) = IDSGraph()

LightGraphs.is_directed(::Type{IDSGraph}) = true

Base.getindex(dep::IDSGraph, char::Char) = dep.structures[char]
Base.length(dep::IDSGraph) = nv(dep.graph)

# Functions on dependency graphs
# ------------------------------
"""
    components(idsgraph, char)

The components that make up a character.

# Examples
```julia-repl
julia> g = IDSGraph(:ids);

julia> collect(components(g, '㲉'))
5-element Vector{Char}:
 '一': Unicode U+4E00 (category Lo: Letter, other)
 '冖': Unicode U+5196 (category Lo: Letter, other)
 '士': Unicode U+58EB (category Lo: Letter, other)
 '殳': Unicode U+6BB3 (category Lo: Letter, other)
 '卵': Unicode U+5375 (category Lo: Letter, other)
```
"""
components(dep::IDSGraph, char::Char) =
    (dep.reverse_mapping[code] for code in inneighbors(dep.graph, dep.mapping[char]))

"""
    compounds(idsgraph, char)

The characters that are compounds of the given character.

# Examples
```julia-repl
julia> g = IDSGraph(:ids);

julia> collect(compounds(g, '毛'))
529-element Vector{Char}:
 '兞': Unicode U+515E (category Lo: Letter, other)
 '尾': Unicode U+5C3E (category Lo: Letter, other)
 '宒': Unicode U+5B92 (category Lo: Letter, other)
 '毳': Unicode U+6BF3 (category Lo: Letter, other)
 '旄': Unicode U+65C4 (category Lo: Letter, other)
 '枆': Unicode U+6786 (category Lo: Letter, other)
 ⋮
 '𭴎': Unicode U+2DD0E (category Lo: Letter, other)
 '𭸶': Unicode U+2DE36 (category Lo: Letter, other)
 '𮁠': Unicode U+2E060 (category Lo: Letter, other)
 '𮊐': Unicode U+2E290 (category Lo: Letter, other)
 '𮗥': Unicode U+2E5E5 (category Lo: Letter, other)
```
"""
compounds(dep::IDSGraph, char::Char) =
    (dep.reverse_mapping[code] for code in outneighbors(dep.graph, dep.mapping[char]))

"""
    subgraph(condition, idsgraph)

Create a subgraph keeping only vertices `v` where `condition(v) == true`.
"""
function subgraph(condition, dep::IDSGraph)
    vlist = [dep.mapping[v] for v in vertices(dep) if condition(v)]
    length(vlist) == 0 && return IDSGraph()
    sg, vmap = induced_subgraph(dep.graph, vlist)

    reverse_mapping = [dep.reverse_mapping[vmap[sg_code]] for sg_code in 1:length(vlist)]
    mapping = Dict(char => sg_code for (sg_code, char) in enumerate(reverse_mapping))
    structures = Dict(char => structure for (char, structure) in dep.structures if haskey(mapping, char))

    IDSGraph(sg, mapping, reverse_mapping, structures)
end

"""
    topological_sort(idsgraph)

Create a topological ordering of the characters in this IDS graph.
"""
topological_sort(dep::IDSGraph) =
    (dep.reverse_mapping[code] for code in LightGraphs.topological_sort_by_dfs(dep.graph))

ext: jl


text:
function LineSearch(arg0::MultivariateOptimizer, arg1::jdouble, arg2::jdouble, arg3::jdouble)
    return LineSearch((MultivariateOptimizer, jdouble, jdouble, jdouble), arg0, arg1, arg2, arg3)
end

function search(obj::LineSearch, arg0::Vector{jdouble}, arg1::Vector{jdouble})
    return jcall(obj, "search", UnivariatePointValuePair, (Vector{jdouble}, Vector{jdouble}), arg0, arg1)
end


text:
println("Testing...")
using Test
using SeqAdaptiveIS
using StatsFuns
using Distributions: MvNormal, logpdf
using Statistics: mean, cov

# These are fairly rudimentary 2D tests with easy targets: I guess their primary
# purpose is to ensure that nothing has *broken* the procedures, but is not
# sufficiently strong enough yet to tell if it breaks in difficult or edge
# cases.

# ======================== AMIS inference tests ================================
p_x = MvNormal(zeros(2), Float64[1 0; 0 1])
test_lpdf64_v0 = (x-> logpdf(MvNormal(zeros(2), Float64[1 0; 0 1]), x'), p_x, zeros(2), Float64[1 0; 0 1])
test_lpdf64_v1 = (x-> logpdf(MvNormal(ones(2), Float64[1 0; 0 1]), x'), p_x, ones(2), Float64[1 0; 0 1])

function test_amis(test_case, k::Int)
    log_target, prior, μ, Σ = test_case
    S, logW, pis, mus, covs = amis(log_target, prior, k)
    W = softmax(logW)
    μ̂ = vec(sum(S .* W, dims=1))
    Σ̂ = (S .- μ̂')' * ((S .- μ̂') .* W)
    @test maximum(abs.(μ - μ̂)) < 0.1
    @test maximum(vec(Σ - Σ̂)) < 0.3
end

test_amis(test_lpdf64_v0, 1)
test_amis(test_lpdf64_v0, 2)
test_amis(test_lpdf64_v0, 5)
test_amis(test_lpdf64_v1, 1)
test_amis(test_lpdf64_v1, 2)
test_amis(test_lpdf64_v1, 5)

# ============================= Seq AMIS test ==================================

n_targets = 8
true_pars = [(zeros(2) .+ i, Float64[1 0; 0 1] ./ i) for i in 1:n_targets];
seq_targets = [x->logpdf(MvNormal(μ, Σ), x') for (μ, Σ) in true_pars]

seq_smps, seq_gmms = seq_amis(seq_targets, 2, 3)
print("Sequential targets complete: ")
for i in 1:n_targets
    μ, Σ = true_pars[i]
    S = resample(seq_smps[i], 1000)
    μ̂ = vec(mean(S, dims=1))
    Σ̂ = cov(S, dims=1)
    print("|")
    @test maximum(abs.(μ - μ̂)) < 0.1
    @test maximum(vec(Σ - Σ̂)) < 0.3
end
println()

max_stars_repo_name: ornithos/SeqAdaptiveIS

max_issues_repo_name: ornithos/SeqAdaptiveIS

max_forks_repo_name: ornithos/SeqAdaptiveIS


text:
import AstroBase: TDBEpoch, mercury_barycenter, ssb, earth, moon,
    earth_barycenter, mercury

# Reference value from CSPICE
r_ref = [4.250906022073639e7, 2.3501057648129586e7, 8.158467467032234e6]
v_ref = [-34.160008371029825, 37.844059275357594, 23.756128199757867]
rv_ref = (r_ref, v_ref)

de430segments = [
    "Solar System Barycenter (0) => Mercury Barycenter (1)",
    "Solar System Barycenter (0) => Venus Barycenter (2)",
    "Solar System Barycenter (0) => Earth Barycenter (3)",
    "Solar System Barycenter (0) => Mars Barycenter (4)",
    "Solar System Barycenter (0) => Jupiter Barycenter (5)",
    "Solar System Barycenter (0) => Saturn Barycenter (6)",
    "Solar System Barycenter (0) => Uranus Barycenter (7)",
    "Solar System Barycenter (0) => Neptune Barycenter (8)",
    "Solar System Barycenter (0) => Pluto Barycenter (9)",
    "Solar System Barycenter (0) => Sun (10)",
    "Mercury Barycenter (1) => Mercury (199)",
    "Venus Barycenter (2) => Venus (299)",
    "Earth Barycenter (3) => Luna (301)",
    "Earth Barycenter (3) => Earth (399)",
]
ep = TDBEpoch(2016, 1, 1)
spk = SPK("$path/de430.bsp")

@testset "API" begin
    @testset "Segments" begin
        @test JPLEphemeris.findsegment(spk.segments, 0, 3) == (spk.segments[0][3], 1.0)
        @test JPLEphemeris.findsegment(spk.segments, 3, 0) == (spk.segments[0][3], -1.0)
    end
    @testset for (a, b) in zip(JPLEphemeris.list_segments(spk), de430segments)
        @test a == b
    end
    @testset for (func, ref) in zip((position, velocity, state), (r_ref, v_ref, rv_ref))
        res = func(spk, ep, ssb, mercury_barycenter)
        @test all(res .≈ ref)
        res = func(spk, ep, mercury_barycenter, ssb)
        @test all(res .≈ -1 .* ref)

        res = func(spk, ep, earth, mercury)
        exp = func(spk, ep, earth, earth_barycenter) .+
            func(spk, ep, earth_barycenter, ssb) .+
            func(spk, ep, ssb, mercury_barycenter) .+
            func(spk, ep, mercury_barycenter, mercury)
        @test all(res .≈ exp)
    end
end


text:
@testset "Problem Size" begin

    # Test ProblemSize
    model_dbl = DoubleIntegratorGame(p=3,d=2)
    model_uni = UnicycleGame(p=3)
    N = 10
    probsize_uni = ProblemSize(N,model_uni)
    probsize_dbl = ProblemSize(N,model_dbl)
    @test probsize_uni == probsize_dbl

end


text:
# Command: Accept Alert
"""
    alert_text(session::Session)::String

Gets the text of the currently displayed JavaScript alert(), confirm(), or prompt() dialog.

!!! note

    This command uses the JSON Wire Protocol instead of the current W3c WebDriver API.
"""
function alert_text(session::Session)::String
    @unpack addr, id = session
    response =
        HTTP.get("$addr/session/$id/alert_text", [("Content-Type" => "application/json")])
    @assert response.status == 200
    JSON3.read(response.body).value
end


text:
function count_move!(r, side :: HorizonSide, count)
    for i = 1:count
        move!(r,side)
    end
end

function movements_mark!(r,side::HorizonSide, side_part :: HorizonSide)

    while isborder(r,side_part) == false
        while isborder(r,side) ==  false
            putmarker!(r)
            move!(r,side)
        end
        putmarker!(r)
        move!(r, side_part)
        side = revers(side)
    end

    while isborder(r,side) ==  false
        putmarker!(r)
        move!(r,side)
    end
    putmarker!(r)
end

function corner(r)
    x = 0
    y = 0
    while (isborder(r, Nord) == false) || (isborder(r, West) == false)
        y = y + movements_to_side!(r, Nord)
        x = x + movements_to_side!(r, West)
    end
    return x, y
end

function movements_to_side!(r,side::HorizonSide)
    count = 0
    while isborder(r,side) ==  false
        move!(r,side)
        count = count + 1
    end
    return count
end

function go_home!(r, x, y)
    corner(r)
    count_move!(r, Sud, y)
    count_move!(r, Ost, x)
end

function all_kvadro(r)
    x = 0;
    y = 0;
    x, y = corner(r)
    movements_mark!(r,Ost,Sud)
    go_home!(r, x ,y)

end

all_kvadro(r)
show(r)

max_stars_repo_name: AntonDudDm/mirea-progs

max_issues_repo_name: AntonDudDm/mirea-progs

max_forks_repo_name: AntonDudDm/mirea-progs


text:
# ------------------------------------------------------------------
# Licensed under the ISC License. See LICENSE in the project root.
# ------------------------------------------------------------------

"""
    AbstractSolver

A solver for geostatistical problems.
"""
abstract type AbstractSolver end

"""
    AbstractEstimationSolver

A solver for a geostatistical estimation problem.
"""
abstract type AbstractEstimationSolver <: AbstractSolver end

"""
    AbstractSimulationSolver

A solver for a geostatistical simulation problem.
"""
abstract type AbstractSimulationSolver <: AbstractSolver end

"""
    AbstractLearningSolver

A solver for a geostatistical learning problem.
"""
abstract type AbstractLearningSolver <: AbstractSolver end

"""
    solve(problem, solver)

Solve the `problem` with the `solver`.
"""
solve(::AbstractProblem, ::AbstractSolver) = @error "not implemented"

"""
    solve(problem, solver)

Solve the simulation `problem` with the simulation `solver`.

### Notes

Default implementation calls `solve_single` in parallel.
"""
function solve(problem::SimulationProblem, solver::AbstractSimulationSolver)
  # sanity checks
  @assert keys(solver.params) ⊆ keys(variables(problem)) "invalid variable names in solver parameters"

  # optional preprocessing step
  preproc = preprocess(problem, solver)

  realizations = []
  for (var,V) in variables(problem)
    if nworkers() > 1
      # generate realizations in parallel
      λ = _ -> solve_single(problem, var, solver, preproc)
      varreals = pmap(λ, 1:nreals(problem))
    else
      # fallback to serial execution
      varreals = [solve_single(problem, var, solver, preproc) for i=1:nreals(problem)]
    end

    push!(realizations, var => varreals)
  end

  SimulationSolution(domain(problem), Dict(realizations))
end

"""
    preprocess(problem, solver)

Preprocess the simulation `problem` once before generating each realization
with simulation `solver`.

### Notes

The output of the function is defined by the solver developer.
Default implementation returns nothing.
"""
preprocess(::SimulationProblem, ::AbstractSimulationSolver) = nothing

"""
    solve_single(problem, var, solver, preproc)

Solve a single realization of `var` in the simulation `problem`
with the simulation `solver`, optionally using preprocessed
data in `preproc`.

### Notes

By implementing this function instead of `solve`, the developer is
informing the framework that realizations generated with his/her
solver are indenpendent one from another. GeoStats.jl will trigger
the algorithm in parallel (if enough processes are available).
"""
solve_single(::SimulationProblem, ::Symbol, ::AbstractSimulationSolver,
             ::Any) = @error "not implemented"

#------------------
# IMPLEMENTATIONS
#------------------
include("solvers/sequential_simulation.jl")
include("solvers/cookie_cutter_simulation.jl")
include("solvers/pointwise_learning.jl")


text:
#=
regularized matrix regression with row-sparsity

min ‖Y - X A‖ + λₙ ‖A‖⋆ :
Aᵢⱼ ∈ [-1,1], ∀i,j
ℓ₀(‖A₁‖₁, …, ‖Aₙ‖₁) ≤ k
where:
- design matrix X is n x p
- response matrix Y is n x m
- coefficient matrix variable A is p x m
- Aᵢ is the ith row of A
=#

struct MatrixRegression <: ExampleInstance
    n::Int # number of samples
    p::Int # number of predictors
    m::Int # number of responses
    use_nat::Bool # use nuclear norm cone, else PSD cone formulation
end

function build(inst::MatrixRegression)
    (n, m, p) = (inst.n, inst.m, inst.p)
    @assert n >= p >= m > 1
    k = ceil(Int, p * 2 / 3)

    # generate noisy data
    A0 = 2 * rand(p, m) .- 1
    A0[(k + 1):end, :] .= 0
    X = randn(n, p)
    Y = X * A0 + 0.1 * randn(n, m)

    # use dimension reduction via QR
    F = qr(X, ColumnNorm())
    Y = (F.Q' * Y)[1:p, :]
    X = F.R[1:p, 1:p] * F.P'
    λ = 0.2 # TODO?

    # build model
    model = JuMP.Model()
    JuMP.@variable(model, loss)
    JuMP.@variable(model, nuc)
    JuMP.@variable(model, A[1:p, 1:m])
    JuMP.@variable(model, row_on[1:p], Bin)

    JuMP.@objective(model, Min, loss + λ * nuc)

    JuMP.@constraints(
        model,
        begin
            vcat(loss, vec(Y - X * A)) in
            Hypatia.EpiNormEuclCone{Float64}(1 + length(vec(Y)))
            [i = 1:p], A[i, :] .<= row_on[i]
            [i = 1:p], A[i, :] .>= -row_on[i]
            sum(row_on) <= k
        end
    )

    add_nonsymm_specnuc(inst.use_nat, true, nuc, A', model)

    # save for use in tests
    model.ext[:λ] = λ
    model.ext[:X] = X
    model.ext[:Y] = Y
    model.ext[:A] = A
    model.ext[:row_on] = row_on

    return model
end

function test_extra(inst::MatrixRegression, model::JuMP.Model)
    stat = JuMP.termination_status(model)
    @test stat in OPT_OR_LIMIT
    (stat == MOI.OPTIMAL) || return

    tol = eps()^0.2
    A = JuMP.value.(model.ext[:A])
    (Y, X) = (model.ext[:Y], model.ext[:X])
    # check objective
    loss = norm(Y - X * A)
    nuc = sum(svdvals(A))
    obj_result = loss + model.ext[:λ] * nuc
    @test JuMP.objective_value(model) ≈ obj_result atol = tol rtol = tol
    # check integer feasibility
    row_on = JuMP.value.(model.ext[:row_on])
    @test row_on ≈ round.(Int, row_on) atol = tol rtol = tol
    @test all(-tol .<= row_on .<= 1 + tol)
    for i in 1:size(A, 1)
        if abs(row_on[i]) < tol
            @assert norm(A[i, :]) < tol
        end
    end
    return
end


text:
"""
Physics related to line lists and masks.

Author: Eric Ford
Created: August 2020
"""

# physical constants
const speed_of_light_mps = 2.99782458e8    # m/s

"""   `calc_doppler_factor(vel)``
Compute the longitudinal relativistic doppler factor given a velocity in meters per second.
"""
function calc_doppler_factor(vel::Real)
    one(vel) + vel/speed_of_light_mps
end

#=
 # Eric replaced this version with above.  Should double check that won't cause anyeone suprises.
function calc_doppler_factor(vel::Real)
    num = one(vel) + vel/c_ms
    den = one(vel) - vel/c_ms
    return sqrt(num/den)
end
=#

"""  Convert vacuum wavelength (in Å) to air wavelength
Ref: Donald Morton (2000, ApJ. Suppl., 130, 403) via
     https://www.astro.uu.se/valdwiki/Air-to-vacuum%20conversion
"""
function λ_vac_to_air(λ_vac::Real)
    @assert 3500 < λ_vac < 13000  # Making sure in Å for optical/NIR spectra.
    local s = 10000/λ_vac
    local n = 1 + 0.0000834254 + 0.02406147 / (130 - s^2) + 0.00015998 / (38.9 - s^2)
    return λ_vac/n
end

""" Convert air wavelength (in Å) to vacuum wavelength
Ref: https://www.astro.uu.se/valdwiki/Air-to-vacuum%20conversion
     VALD3 tools use the following solution derived by N. Piskunov
"""
function λ_air_to_vac(λ_air::Real)
    @assert 3500 < λ_air < 13000  # Making sure in Å for optical/NIR spectra.
    local s = 10000/λ_air
    local n = 1 + 0.00008336624212083 + 0.02408926869968 / (130.1065924522 - s^2) + 0.0001599740894897 / (38.92568793293 - s^2)
    λ_air*n
end

max_stars_repo_name: RvSpectML/EchelleCCFs

max_issues_repo_name: RvSpectML/EchelleCCFs

max_forks_repo_name: RvSpectML/EchelleCCFs


text:
int_rules_3_1_2 = @theory begin

    #= ::Subsection::Closed:: =#
    #= 3.1.2*(d*x)^m*(a+b*log(c*x^n))^p =#
    @apply_utils Antiderivative((~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) / ~x, ~x) => (~a + ~b * log(~c * (~x) ^ ~n)) ^ 2 / (2 * ~b * ~n) <-- FreeQ([~a, ~b, ~c, ~n], ~x)
    @apply_utils Antiderivative((~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~(p') / ~x, ~x) => (1 / (~b * ~n)) * Subst(Antiderivative((~x) ^ ~p, ~x), ~x, ~a + ~b * log(~c * (~x) ^ ~n)) <-- FreeQ([~a, ~b, ~c, ~n, ~p], ~x)
    @apply_utils Antiderivative((~(d') * ~x) ^ ~(m') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))), ~x) => (~b * (~d * ~x) ^ (~m + 1) * log(~c * (~x) ^ ~n)) / (~d * (~m + 1)) <-- FreeQ([~a, ~b, ~c, ~d, ~m, ~n], ~x) && (NeQ(~m, -1) && EqQ(~a * (~m + 1) - ~b * ~n, 0))
    @apply_utils Antiderivative((~(d') * ~x) ^ ~(m') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))), ~x) => ((~d * ~x) ^ (~m + 1) * (~a + ~b * log(~c * (~x) ^ ~n))) / (~d * (~m + 1)) - (~b * ~n * (~d * ~x) ^ (~m + 1)) / (~d * (~m + 1) ^ 2) <-- FreeQ([~a, ~b, ~c, ~d, ~m, ~n], ~x) && NeQ(~m, -1)
    @apply_utils Antiderivative((~(d') * ~x) ^ ~(m') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~(p'), ~x) => ((~d * ~x) ^ (~m + 1) * (~a + ~b * log(~c * (~x) ^ ~n)) ^ ~p) / (~d * (~m + 1)) - ((~b * ~n * ~p) / (~m + 1)) * Antiderivative((~d * ~x) ^ ~m * (~a + ~b * log(~c * (~x) ^ ~n)) ^ (~p - 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~m, ~n], ~x) && (NeQ(~m, -1) && GtQ(~p, 0))
    @apply_utils Antiderivative((~(d') * ~x) ^ ~(m') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~p, ~x) => ((~d * ~x) ^ (~m + 1) * (~a + ~b * log(~c * (~x) ^ ~n)) ^ (~p + 1)) / (~b * ~d * ~n * (~p + 1)) - ((~m + 1) / (~b * ~n * (~p + 1))) * Antiderivative((~d * ~x) ^ ~m * (~a + ~b * log(~c * (~x) ^ ~n)) ^ (~p + 1), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~m, ~n], ~x) && (NeQ(~m, -1) && LtQ(~p, -1))
    @apply_utils Antiderivative((~x) ^ ~(m') / log(~(c') * (~x) ^ ~n), ~x) => (1 / ~n) * Subst(Antiderivative(1 / log(~c * ~x), ~x), ~x, (~x) ^ ~n) <-- FreeQ([~c, ~m, ~n], ~x) && EqQ(~m, ~n - 1)
    @apply_utils Antiderivative((~d * ~x) ^ ~(m') / log(~(c') * (~x) ^ ~n), ~x) => ((~d * ~x) ^ ~m / (~x) ^ ~m) * Antiderivative((~x) ^ ~m / log(~c * (~x) ^ ~n), ~x) <-- FreeQ([~c, ~d, ~m, ~n], ~x) && EqQ(~m, ~n - 1)
    @apply_utils Antiderivative((~x) ^ ~(m') * (~(a') + ~(b') * log(~(c') * ~x)) ^ ~p, ~x) => (1 / (~c) ^ (~m + 1)) * Subst(Antiderivative(ℯ ^ ((~m + 1) * ~x) * (~a + ~b * ~x) ^ ~p, ~x), ~x, log(~c * ~x)) <-- FreeQ([~a, ~b, ~c, ~p], ~x) && IntegerQ(~m)
    @apply_utils Antiderivative((~(d') * ~x) ^ ~(m') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~p, ~x) => ((~d * ~x) ^ (~m + 1) / (~d * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative(ℯ ^ (((~m + 1) / ~n) * ~x) * (~a + ~b * ~x) ^ ~p, ~x), ~x, log(~c * (~x) ^ ~n)) <-- FreeQ([~a, ~b, ~c, ~d, ~m, ~n, ~p], ~x)
    @apply_utils Antiderivative((~(d') * (~x) ^ ~q) ^ ~m * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~(p'), ~x) => ((~d * (~x) ^ ~q) ^ ~m / (~x) ^ (~m * ~q)) * Antiderivative((~x) ^ (~m * ~q) * (~a + ~b * log(~c * (~x) ^ ~n)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~m, ~n, ~p, ~q], ~x)
    @apply_utils Antiderivative((~(d1') * (~x) ^ ~q1) ^ ~m1 * (~(d2') * (~x) ^ ~q2) ^ ~m2 * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~(p'), ~x) => (((~d1 * (~x) ^ ~q1) ^ ~m1 * (~d2 * (~x) ^ ~q2) ^ ~m2) / (~x) ^ (~m1 * ~q1 + ~m2 * ~q2)) * Antiderivative((~x) ^ (~m1 * ~q1 + ~m2 * ~q2) * (~a + ~b * log(~c * (~x) ^ ~n)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~c, ~d1, ~d2, ~m1, ~m2, ~n, ~p, ~q1, ~q2], ~x)
end

max_stars_repo_path: src/rules/3 Logarithms/3.1.2 (d x)^m (a+b log(c x^n))^p.jl


text: struct S ; ; ; end

max_stars_repo_name: gabriel-doriath-dohler/pjulia

max_issues_repo_name: gabriel-doriath-dohler/pjulia

max_forks_repo_name: gabriel-doriath-dohler/pjulia


text:
using LightGraphs.SimpleGraphs: SimpleEdge, AbstractSimpleGraph

mutable struct HyperCube{T,SG<:AbstractGraph{T}} <: AbstractWrappedSimpleGraph{T}
    bare_graph::SG

    dims::Vector{T}
    vert_coords::Vector{Vector{T}}
end

"""
    HyperCube([dims::Int]; periodic=true, neighbours_distances=[1]) -> HyperCube

Creates a HyperCube graph with spatial dimensions specified by dims. If `periodic==true`
then every dimension is periodic. You can also pass `periodic=[true, false, false]`
and only the specified dimensions will be periodic.

`neighbours_distances` is a list of the distances to be encoded in the lattice.
A standard nearest-neighbour coupling lattice is obtained with the default
of `[1]`, if you want nearest-neighbour and next-nearest neighbour you need
`[1,2]` and so on and so forth.
The ordering is important and determines the coloring of the graph.

The returned graph holds the lattice coordinates of every vertex in the underlying
graph, useful when computing correlation functions.
"""
function HyperCube(dims; periodic=true, neighbours_distances=[1])
    T=Int

    nv = prod(dims)
    vert_coords = Vector{Vector{T}}()

    # Convert the linear indices of vertices to N-dim coordinates
    for i=1:nv
        push!(vert_coords, int_to_hypercube_coord(i, dims))
    end

    #
    if !(periodic isa AbstractVector)
        periodic = fill(periodic, size(dims))
    elseif size(periodic) ≠ size(dims)
        throw("Error: periodic should match sizes")
    end

    sg = SimpleGraph{T}(nv)

    # If neighbours distances is an integer use only this as a distance
    if neighbours_distances isa Integer
        neighbours_distances = [neighbours_distances]
    end

    for dist = neighbours_distances
        is_good = all(dist .< dims)
        if !is_good
            throw("neighbours_distances should be greater than all dimensions.")
        end
    end

    if length(neighbours_distances) > 1
        sg = ColoredGraph(sg)
    end

    _add_edge!(sg::AbstractGraph, src, dst, col) = add_edge!(sg, src, dst)
    _add_edge!(sg::ColoredGraph, src, dst, col) = add_edge!(sg, src, dst, col)

    for i=1:nv
        neighbors = Vector{T}()
        coord_o   = vert_coords[i]
        for (j, (dim, loop_dim)) = enumerate(zip(dims, periodic))
            for (col,Δ)=enumerate(neighbours_distances)
                for δⱼ=[Δ,-Δ]
                    nj = coord_o[j]+δⱼ
                    if (nj < 1 || nj > dim)
                        # if we don't loop this dimension lets skip this connection
                        !loop_dim && continue

                        # wrap around
                        nj = nj<=0 ? rem(nj,dim) + dim : rem(nj,dim)
                    end

                    coord = copy(coord_o)
                    coord[j] = nj
                    push!(neighbors, findfirst(x->x==coord, vert_coords))
                    _add_edge!(sg, i, findfirst(x->x==coord, vert_coords), col)
                end
            end
        end
    end

    return HyperCube(sg, dims, vert_coords)
end

## make it static

# I/O
show(io::IO, g::HyperCube) = print(io, "HyperCube with $(nv(g)) vertices, $(ne(g)) edges")
######

int_to_hypercube_coord(r, dims::Vector) = int_to_hypercube_coord(r, Tuple(dims)...)
int_to_hypercube_coord(c, dims...) = begin
    r, cc = divrem(c-1,prod(Base.front(dims)))
    append!(int_to_hypercube_coord(cc+1, Base.front(dims)...), r+1)
end
int_to_hypercube_coord(c, dims::Vararg{Integer, 1}) = [c]

## Useful functions
translational_symm_table(g::HyperCube) = _hypercube_translational_symmetry_table(g.dims)
function _hypercube_translational_symmetry_table(dims)
    nv = prod(dims)
    lat = reshape(collect(1:nv), Tuple(dims))

    iso_table = Vector{Vector{Int}}()
    if length(dims) == 1
        for i=0:dims[1]-1
            push!(iso_table, vec(circshift(lat, i)))
        end
    elseif length(dims) == 2
        for i=0:dims[1]-1
            for j=0:dims[2]-1
                push!(iso_table, vec(circshift(lat, [i,j])))
            end
        end
    elseif length(dims) == 3
        for i=0:dims[1]-1
            for j=0:dims[2]-1
                for k=0:dims[3]-1
                    push!(iso_table, vec(circshift(lat, [i,j,k])))
                end
            end
        end
    else
        @error "not supported"
    end
    return iso_table
end


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

using Markdown
using InteractiveUtils

# ╔═╡ b0020dc0-78a7-483f-877f-719f42b0c044
using Plots, PlutoUI, DataStructures

# ╔═╡ aec0517c-01e7-4d3f-b9b4-3e4ec8acdfc3
begin

	using HTTP

	hamming(s,t) = sum((si != ti for (si, ti) in zip(s, t)))

	"""Get all English words"""
	function getwords()
		io = HTTP.get("https://github.com/dwyl/english-words/raw/master/words_alpha.txt")
		words = split(String(io.body), "\n") .|> rstrip .|> String
		return words
	end

	"""Get all English words of length `wordsize`"""
	function getwords(wordsize::Integer)
		return filter(w -> length(w) == wordsize, getwords())
	end

	"""
		getwordedges(words; cutoff=5)

	Returns all the weigthed edges between a list of `words` where the Hamming
	distance is less than `cutoff`.
	"""
	function getwordedges(words; cutoff=5)
		edges = Tuple{Int,String,String}[]
		for (i, w1) in enumerate(words[1:end-1])
			for w2 in words[(i+1):end]
				d = hamming(w1, w2)
				d ≤ cutoff && push!(edges, (d, w1, w2))
			end
		end
		return edges
	end

end #Words

# ╔═╡ 9803aaf0-08c3-4501-8865-318a988210c9
module Solution
	export reconstruct_path, dijkstra, a_star

	using DataStructures

	WeightedEdgeList{R,T} = Array{Tuple{R,T,T},1}
	AdjList{R,T} = Dict{T,Array{Tuple{R,T},1}}

	"""
		reconstruct_path(previous::Dict{T,T}, source::T, sink::T) where {T}

	Reconstruct the path from the output of the Dijkstra algorithm.

	Inputs:
			- previous : a Dict with the previous node in the path
			- source : the source node
			- sink : the sink node
	Ouput:
			- the shortest path from source to sink
	"""
	function reconstruct_path(previous::Dict{T,T}, source::T, sink::T) where {T}
		path = T[sink]
		current = sink
		while current != source
			current = previous[current]
			push!(path, current)
		end
		return reverse!(path)
	end

	"""
		dijkstra(graph::AdjList{R,T}, source::T) where {R<:Real,T}

	Dijkstra without a specified sink. Give the `graph` and a `source` and this
	function uses Dijkstra's algorithm to compute all distances between the nodes
	and the source. Returns
		- `distances`: a dictionary with the distances
		- `previous`: a dictionary representing the tree of the shortest paths.
	"""
	function dijkstra(graph::AdjList{R,T}, source::T) where {R<:Real,T}
		# initialize the tentative distances
		distances = Dict(v => Inf for v in keys(graph))
		distances[source] = 0.0
		previous = Dict{T,T}()
		vertices_to_check = [(0.0, source)]
		while length(vertices_to_check) > 0
			dist, u = heappop!(vertices_to_check)
			for (dist_u_v, v) in graph[u]
				new_dist = dist + dist_u_v
				if distances[v] > new_dist
					distances[v] = new_dist
					previous[v] = u
					heappush!(vertices_to_check, (new_dist, v))
				end
			end
		end
		return distances, previous
	end

	"""
		dijkstra(graph::AdjList{R,T}, source::T, sink::T) where {R<:Real,T}

	Dijkstra's shortest path algorithm.

	Inputs:
		- `graph` : adjacency list representing a weighted directed graph
		- `source`
		- `sink`

	Outputs:
		- the shortest path
		- the cost of this shortest path
	"""
	function dijkstra(graph::AdjList{R,T}, source::T, sink::T) where {R<:Real,T}
		# initialize the tentative distances
		distances = Dict(v => Inf for v in keys(graph))
		distances[source] = 0.0
		previous = Dict{T,T}()
		vertices_to_check = [(0.0, source)]
		while length(vertices_to_check) > 0
			dist, u = heappop!(vertices_to_check)
			if u == sink
				return reconstruct_path(previous, source, sink), dist
			end
			for (dist_u_v, v) in graph[u]
				new_dist = dist + dist_u_v
				if distances[v] > new_dist
					distances[v] = new_dist
					previous[v] = u
					heappush!(vertices_to_check, (new_dist, v))
				end
			end
		end
	end

	"""
		a_star(graph::AdjList{R,T}, source::T, sink::T, heuristic) where {R<:Real,T}

	A* shortest path algorithm.

	Inputs:
		- `graph` : adjacency list representing a weighted directed graph
		- `source`
		- `sink`
		- `heuristic` : a function that inputs a node and returns an lower bound
				for the distance to the source. Note that a distance can be turned into
				a heuristic using `n -> d(n, sink)`

	Outputs:
		- the shortest path
		- the cost of this shortest path
	"""
	function a_star(graph::AdjList{R,T}, source::T, sink::T, heuristic) where {R<:Real,T}
		# initialize the tentative distances
		distances = Dict(v => Inf for v in keys(graph))
		distances[source] = 0.0
		previous = Dict{T,T}()
		vertices_to_check = [(heuristic(source), source)]
		while length(vertices_to_check) > 0
			dist, u = heappop!(vertices_to_check)
			if u == sink
				return reconstruct_path(previous, source, sink), distances[sink]
			end
			for (dist_u_v, v) in graph[u]
				new_dist = dist + dist_u_v
				if distances[v] > new_dist
					distances[v] = new_dist
					min_dist_to_sink = new_dist + heuristic(v)
					previous[v] = u
					heappush!(vertices_to_check, (min_dist_to_sink, v))
				end
			end
		end
	end
end

# ╔═╡ 2ab0b80e-1e02-11ec-1596-8bd8e81d347c
md"""
# Shortest path problems

*STMO*

**Michiel Stock**
"""

# ╔═╡ b4977f9f-2bcc-405f-b875-99cde2ccb77d
md"## Dijkstra's shortest path algorithm

Dijkstra's algorithm is a popular algorithm to find the shortest path between the nodes of a graph. The algorithm can be used in two ways:

- when both a source and a sink node are provided, the algorithm gives the list of nodes of the shortest path, together with the length (distance of the path).
- when only a source is given, the shortest distance between the source and all (accessable) nodes is returned together with a dictionary representing the tree of the shortest paths between the source and other nodes.

The pseudocode can be found below."

# ╔═╡ 2492a904-77da-4a36-baf4-65d40aa89d74
md"""
### Pseudocode of Dijkstra's shortest path algorithm
Source: Wikipedia.org
```
1  function Dijkstra(Graph, source, sink (optional)):
2      distance[source] := 0  // initialize a dictionary with distance
3                             // to source
4      for each vertex V in Graph:
5          if V ≠ source
6              distance[V] := infinity
7      previous := empty dict   // stores the previous node in path
8
10     make empty priority queue Q for vertices to check
11     Q.add_with_priority(source, 0)  # first check the source
12
13
14     while Q is not empty:                     // The main loop
15         get node U with smallest distance from Q
16         if U is the sink (if provided)
17              break the loop
17         for every neighbor V of U:
18             alternative := distance[U] + dist(U, V)
18             if alternative < distance[V]
19                 distance[V] := alternative
20                 previous[V] := U
21                 Q.add_with_priority(V, alternative)
22
23     if sink is given
24         reconstruct shortest path
25         return shortest path and length of path
26     else
27         return distance, previous
```
"""

# ╔═╡ 194250f8-c94d-4732-b179-0ebead51110b
md"""
### Pseudocode of path reconstruction  algorithm
```
1 function reconstruct_path(previous, source, sink)
2    if the source is not in previous
3          return empty path
4    V := sink   \\ path is reconstructed backwards
5    path := [V]  \\ path is a list of nodes
6    while V is not source
7         V := previous node in path
8         add V in beginning of the path
9    return the path
```
"""

# ╔═╡ 40b7b2f4-ec2b-4b89-b2f0-adc368ee15bc
"""
    reconstruct_path(previous::Dict{T,T}, source::T, sink::T) where {T}

Reconstruct the path from the output of the Dijkstra algorithm.

Inputs:
        - previous : a Dict with the previous node in the path
        - source : the source node
        - sink : the sink node
Ouput:
        - the shortest path from source to sink
"""
function reconstruct_path(previous::Dict{T,T}, source::T, sink::T) where {T}
    path = T[sink]
    missing
    return missing
end

# ╔═╡ 67729a4c-df55-4fdb-8962-25b133eaaaf5
md"""

**Assignment 1: Dijkstra**

1. Complete the implementation for Dijstra's algorithm and the path reconstruction function
2. Find the shortest path from node A to I in the example graph below.
3. Find the shortest path from Portland to Nashville on the Ticket to Ride graph.
3. (optional, medium hard) Modify `dijkstra` such that the sink is optional. When no sink is given, the dictionary `previous` (where `previous[u] = v` indicates that the shortest path from `v` is via `u`) and `distances`, a dictionary containing the minimal distance from every node to the sink.

![Example network](https://github.com/MichielStock/STMO/blob/master/chapters/08.ShortestPath/Figures/example_graph.png?raw=true)
"""

# ╔═╡ a47b09eb-7441-4441-98de-d48111e172a7
# the above graph as an adjacency list
graph = Dict('A' => [(2, 'B'), (3, 'D')],
        'B' => [(1, 'C'), (5, 'E')],
        'C' => [(2, 'D'), (1, 'E')],
        'D' => [(3, 'E')],
        'E' => [(2, 'B'), (3, 'F')],
        'F' => [(5, 'G'), (8, 'I')],
        'G' => [(2, 'H'), (5, 'I')],
        'H' => [(3, 'I')],
        'I' => [(7, 'G')]);

# ╔═╡ c12360cc-5208-417c-9003-5ce1308e8081
# find the shortest path

# ╔═╡ 47e0c111-83c1-4c3f-b293-a337b19feee9

# ╔═╡ a7cb520d-d221-45e9-83ac-e1927aafd0ab
md"""
## A* shortest path algorithm

It is hard to explain the algorithm into more depth than [here](http://theory.stanford.edu/~amitp/GameProgramming/) and [here](http://www.redblobgames.com/pathfinding/a-star/introduction.html).

The A\* algorithm is exact (like Dijkstra's algorithm), but it can also use a **heuristic** to speed up the search. In each iteration, the next neighbor $v$ of the current vertex that the algorithm considers is chosen based on the heuristic

$$f(v) = g(v) + h(v)$$

with $g(v)$ the cost of the path so far and $h(v)$ a heuristic that estimates the cost of the cost of the shortest path from $v$ to the goal. The heuristic $h(v)$ should satify two properties:
1. To guaranty that a shortest path is found, the heuristic should be **admissible**, i.e. it should never overestimate the true distance to goal.
2. Evaluating the heuristic should be cheap (it is either pre-computed or is a function).

So the A\* algorithm is basically the same as Dijkstra's algorithm, but with the main difference that the the latter chooses nodes to explore based on the distance from the starting node, while the latter chooses nodes **based on an estimate of distance to the goal**.

When using A\* to find the shortest path between two physical locations, each vertex corresponds to a point in space. A good heuristic is the (Euclidian) distance between the vertexs, as this will always be a lower bound for the actual distance to travel to the goal.

Consider the following example of finding the path from vertex $a$ to vertex $h$.

![Example how A\* uses the heuristics](https://github.com/MichielStock/STMO/blob/master/chapters/08.ShortestPath/Figures/astarexample.png?raw=true)

The shortest path so far is $[a, e]$ and the algorithm needs to choose to explore vertex $d$ or vertex $g$. Since the path of $ed$ is shorter than the path $eg$, Dijkstra will choose this vertex, even though it is farther removed from the goal $h$ (Dijkstra chooses a neighbor $n$ only based on the current path length form the starting vertex $g(n)$. The A\* algorithm will chose vertex $g$ to explore, because the estimated path length $f(e) = g(e) + h(e) > f(d)$ and hence will approach the goal.
"""

# ╔═╡ a2906480-383f-4456-9a80-04d172f85c41
md"""
### Pseudocode of A\* shortest path algorithm
Source from Wikipedia (modified)
```
1  function Astar(Graph, source, sink, heuristic):
2      make empty priority queue Q for vertices to check
3
4      add source to Q with priority f(source)
5          // use the estimated path length for priority
6
7      distance[V] := 0   // initialize a dictionary with distance
8                           // to source
9      previous := empty dict   // stores the previous node in path
10
11     while Q is not empty:                     // The main loop
12         pop node U with lowest estimated path length to sink
13         if U is the sink
14              break the loop
15         for every neighbor V of U:
16             distance_source_U := distance[U] + dist(U, V)
17             if V not in distance or distance_source_U < distance[V]
18                 distance[V] := distance_source_U
19                 previous[V] := U
20                 heuristic_V_sink := distance[V] + heuristic(V)
21                 Q.add_with_priority(V, heuristic_V_sink)
22
23     reconstruct shortest path
24     return shortest path and length of path
```
"""

# ╔═╡ f8bc5419-054e-4b8f-807e-b594784661f6
md"""
**Assignment 2: A**\*

1. Complete the implementation for the A\* algorithm.
2. Compute the shortest path between Portland to Nashville. The function `tickettoride_dist` returns the shortest distance (as the bird flies) between two cities.
3. Compare running time of the two shortest path algorithms using `@time`.
"""

# ╔═╡ 74b62c2b-58b5-4c37-9399-266855086f9b

# ╔═╡ 54b185a7-7b4e-4756-9663-db0b6419de27
md"""
## Word problem

Let us use shortest path for some word problems? What is the shortest chain from one word to another if you can only change 5 letters at a time? We will explore this on all words of length 12.
"""

# ╔═╡ db00faa4-1d04-47aa-a062-4cf9b8cbe208
words12 = getwords(12)

# ╔═╡ fddb2f51-e5dc-47eb-81d9-9485435c60ea
md"We have the function `hamming` to compute the hamming distance between two stings."

# ╔═╡ 6a1dae01-b78b-4e8b-9a4d-d20bc6a025a5
w1, w2 = rand(words12, 2)

# ╔═╡ 4a867566-14eb-4d8a-ae17-a267054840fd
hamming(w1, w2)

# ╔═╡ cf659c75-b8b9-488d-b937-36ea1e0cadbe
md"We can compute the weighted graph where two words are connected if they have a Hamming distance of at most 5."

# ╔═╡ 94a53663-6dba-4e9b-8c30-bc1f2be3a43e
words_edges = getwordedges(words12, cutoff=5);

# ╔═╡ 9fd3c33d-275d-420b-a03b-8ceb81a56ad3
md"""
**Assignment 3: word salad**

1. Use Dijkstra and A* to find the distance between two randomly chosen words.
2. Can you find the longest word chain?
"""

# ╔═╡ 9d467594-8a33-4e1d-a272-744379bf2722

# ╔═╡ 63e2620a-6897-4664-81e3-479a7a5af9ff

# ╔═╡ eb9dfc6d-b9d8-4771-9b71-e4d0fba38cb7
md"## Appendix"

# ╔═╡ 89941271-8a9d-4e1c-94b0-77b35ebd8816
begin
	myblue = "#304da5"
	mygreen = "#2a9d8f"
	myyellow = "#e9c46a"
	myorange = "#f4a261"
	myred = "#e76f51"
	myblack = "#50514F"

	mycolors = [myblue, myred, mygreen, myorange, myyellow]
end;

# ╔═╡ ecde4baa-0aff-434c-b34a-59b0938a100f
const tickettoride_edges = [(1, "Vancouver", "Seattle"),
          (1, "Seattle", "Portland"),
          (3, "Vancouver", "Calgary"),
          (6, "Calgary", "Winnipeg"),
          (6, "Winnipeg", "Sault Ste. Marie"),
          (4, "Winnipeg", "Helena"),
          (4, "Calgary", "Helena"),
          (6, "Seattle", "Helena"),
          (4, "Seattle", "Calgary"),
          (6, "Portland", "Salt Lake City"),
          (5, "Portland", "San Francisco"),
          (5, "San Francisco", "Salt Lake City"),
          (3, "San Francisco", "Los Angeles"),
          (2, "Los Angeles", "Las Vegas"),
          (3, "Los Angeles", "Phoenix"),
          (6, "Los Angeles", "El Paso"),
          (3, "Phoenix", "El Paso"),
          (3, "Phoenix", "Santa Fe"),
          (3, "Las Vegas", "Salt Lake City"),
          (5, "Phoenix", "Denver"),
          (3, "Salt Lake City", "Denver"),
          (3, "Helena", "Salt Lake City"),
          (6, "Helena", "Duluth"),
          (4, "Winnipeg", "Duluth"),
          (4, "Helena", "Denver"),
          (5, "Helena", "Omaha"),
          (4, "Denver", "Omaha"),
          (4, "Denver", "Kansas City"),
          (2, "Denver", "Santa Fe"),
          (2, "Santa Fe", "El Paso"),
          (3, "Santa Fe", "Oklahoma City"),
          (4, "Denver", "Oklahoma City"),
          (6, "El Paso", "Houston"),
          (4, "El Paso", "Dallas"),
          (5, "El Paso", "Oklahoma City"),
          (1, "Dallas", "Houston"),
          (2, "Dallas", "Oklahoma City"),
          (2, "Kansas City", "Oklahoma City"),
          (1, "Omaha", "Kansas City"),
          (2, "Omaha", "Duluth"),
          (3, "Duluth", "Chicago"),
          (4, "Omaha", "Chicago"),
          (6, "Duluth", "Toronto"),
          (3, "Duluth", "Sault Ste. Marie"),
          (5, "Sault Ste. Marie", "Montreal"),
          (2, "Montreal", "Boston"),
          (2, "Boston", "New York"),
          (3, "Montreal", "New York"),
          (3, "Montreal", "Toronto"),
          (4, "Toronto", "Chicago"),
          (3, "Chicago", "Pittsburgh"),
          (2, "Chicago", "Saint Louis"),
          (2, "Pittsburgh", "Toronto"),
          (2, "Toronto", "Sault Ste. Marie"),
          (2, "Pittsburgh", "New York"),
          (2, "Pittsburgh", "Washington"),
          (2, "Washington", "New York"),
          (2, "Washington", "Raleigh"),
          (2, "Pittsburgh", "Raleigh"),
          (5, "Pittsburgh", "Saint Louis"),
          (2, "Kansas City", "Saint Louis"),
          (2, "Nashville", "Saint Louis"),
          (2, "Little Rock", "Saint Louis"),
          (2, "Oklahoma City", "Little Rock"),
          (2, "Little Rock", "Dallas"),
          (3, "Little Rock", "Nashville"),
          (2, "Houston", "New Orleans"),
          (3, "Little Rock", "New Orleans"),
          (4, "New Orleans", "Atlanta"),
          (1, "Atlanta", "Nashville"),
          (4, "Nashville", "Pittsburgh"),
          (2, "Atlanta", "Raleigh"),
          (3, "Nashville", "Raleigh"),
          (2, "Raleigh", "Charleston"),
          (2, "Charleston", "Atlanta"),
          (6, "New Orleans", "Miami"),
          (5, "Atlanta", "Miami"),
          (4, "Charleston", "Miami")
          ]

# ╔═╡ 30651af8-ad5d-4cd2-89be-8283d381da5b
const cities_coordinates = Dict("Atlanta" => (-84.3901849, 33.7490987),
                               "Boston" => (-71.0595678, 42.3604823),
                               "Calgary" => (-114.0625892, 51.0534234),
                               "Charleston" => (-79.9402728, 32.7876012),
                               "Chicago" => (-87.6244212, 41.8755546),
                               "Dallas" => (-96.7968559, 32.7762719),
                               "Denver" => (-104.9847034, 39.7391536),
                               "Duluth" => (-92.1251218, 46.7729322),
                               "El Paso" => (-106.501349395577, 31.8111305),
                               "Helena" => (-112.036109, 46.592712),
                               "Houston" => (-95.3676974, 29.7589382),
                               "Kansas City" => (-94.5630298, 39.0844687),
                               "Las Vegas" => (-115.149225, 36.1662859),
                               "Little Rock" => (-92.2895948, 34.7464809),
                               "Los Angeles" => (-118.244476, 34.054935),
                               "Miami" => (-80.1936589, 25.7742658),
                               "Montreal" => (-73.6103642, 45.4972159),
                               "Nashville" => (-86.7743531, 36.1622296),
                               "New Orleans" => (-89.9750054503052, 30.03280175),
                               "New York" => (-73.9866136, 40.7306458),
                               "Oklahoma City" => (-97.5170536, 35.4729886),
                               "Omaha" => (-95.9378732, 41.2587317),
                               "Phoenix" => (-112.0773456, 33.4485866),
                               "Pittsburgh" => (-79.99, 40.42),
                               "Portland" => (-122.6741949, 45.5202471),
                               "Raleigh" => (-78.6390989, 35.7803977),
                               "Saint Louis" => (-90.12954315, 38.60187637),
                               "Salt Lake City" => (-111.8904308, 40.7670126),
                               "San Francisco" => (-122.49, 37.75),
                               "Santa Fe" => (-105.9377997, 35.6869996),
                               "Sault Ste. Marie" => (-84.320068, 46.52391),
                               "Seattle" => (-122.3300624, 47.6038321),
                               "Toronto" => (-79.387207, 43.653963),
                               "Vancouver" => (-123.1139529, 49.2608724),
                               "Washington" => (-77.0366456, 38.8949549),
                               "Winnipeg" => (-97.168579, 49.884017))

# ╔═╡ 1e332d32-7846-4bdb-935e-505dd290e1f0
begin
	p = plot(xaxis="longitude", yaxis="lattitude")

	# add edges
	for (w, c1, c2) in tickettoride_edges
		x1, y1 = cities_coordinates[c1]
		x2, y2 = cities_coordinates[c2]
		plot!(p, [x1, x2], [y1, y2], color=myred, alpha=0.8,
			lw=w, label="")
	end
	# plot cities
	for (city, (x, y)) in cities_coordinates
		println("$city: $x, $y")
		scatter!(p, [x], [y], label="", color=mygreen, markersize=10, alpha=0.8
		, annotations=[(x, y, city, 8)]  # comment this for clarity
		)
	end
	p
end

# ╔═╡ d69435c1-c19a-4a94-8778-cea2ffcdfaa6
const cities = [k for k in keys(cities_coordinates)]

# ╔═╡ 8c64f65f-b610-40b5-b9a1-6abb39a6f0bb
tickettoride_dist(c1, c2) = sqrt(sum((cities_coordinates[c1] .- cities_coordinates[c2]).^2))

# ╔═╡ 76b4809a-3fed-4bea-bfe8-66582cbb3fc9
tickettoride_edges_dists = [(tickettoride_dist(u, v), u, v) for (w, u, v) in tickettoride_edges]

# ╔═╡ 427428ab-1978-4317-86f3-ea211141e52f
WeightedEdgeList{R,T} = Array{Tuple{R,T,T},1}

# ╔═╡ 9d754d22-2a09-4458-8fa0-589ae4f75d76
AdjList{R,T} = Dict{T,Array{Tuple{R,T},1}}

# ╔═╡ 38cb6e91-b7bb-4000-b883-f24c17ad827a
"""
    dijkstra(graph::AdjList{R,T}, source::T, sink::T) where {R<:Real,T}

Dijkstra's shortest path algorithm.

Inputs:
    - `graph` : adjacency list representing a weighted directed graph
    - `source` : node to start with
	- `sink` : node to end with

Outputs:
    - the shortest path
    - the cost of this shortest path
"""
function dijkstra(graph::AdjList{R,T}, source::T, sink) where {R<:Real,T}
    # initialize the tentative distances
    distances = Dict(v => Inf for v in keys(graph))
    #distances[source] = missing
    return missing
end

# ╔═╡ 6b6ede88-b4b8-4dc7-8f27-bc2228512e22
dijkstra(graph, 'A', 'I')

# ╔═╡ 0c280cb9-9f30-4570-91a1-19538b56f957
"""
    a_star(graph::AdjList{R,T}, source::T, sink::T, heuristic) where {R<:Real,T}

A* shortest path algorithm.

Inputs:
    - `graph` : adjacency list representing a weighted directed graph
    - `source`
    - `sink`
    - `heuristic` : a function that inputs a node and returns an lower bound
            for the distance to the source. Note that a distance can be turned into
            a heuristic using `n -> d(n, sink)`

Outputs:
    - the shortest path
    - the cost of this shortest path
"""
function a_star(graph::AdjList{R,T}, source::T, sink::T, heuristic) where {R<:Real,T}
    # initialize the tentative distances
    distances = Dict(v => Inf for v in keys(graph))
    missing
    while missing
        missing
	end
	return missing
end

# ╔═╡ 7654100f-86ca-481f-bfb7-bc9b9ee20639
"""
Turns a list of weighted edges in an adjacency matrix (implemented as a Dict).
If the keyword `double` is set to `true`, every edge is added twice: `(w, u, v)`
and `(w, v, u)`. This is the default behaviour.
"""
function edges2adjlist(edges::WeightedEdgeList{R,T}; double=true) where {R<:Real,T}
    adjlist = AdjList{R,T}()
    for (w, i, j) in edges
        if !haskey(adjlist, i); adjlist[i] = [] end
        if !haskey(adjlist, j); adjlist[j] = [] end
        push!(adjlist[i], (w, j))
        double && push!(adjlist[j], (w, i))
    end
    return adjlist
end

# ╔═╡ 1a2a55a5-424c-4522-a4bd-9c657f9f8565
words_graph = edges2adjlist(words_edges)

# ╔═╡ 80c1d9d2-f8d7-4a16-90a3-a0af2ce96ced
const tickettoride_graph = edges2adjlist(tickettoride_edges_dists)

# ╔═╡ a130184f-06af-4767-ad6a-d8d8c1bbf6ca
tickettoride_graph

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
DataStructures = "~0.18.10"
HTTP = "~0.9.14"
Plots = "~1.22.2"
PlutoUI = "~0.7.11"
"""

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

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

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

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

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

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

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

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

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

[[GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "dba1e8614e98949abfa60480b13653813d8f0157"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+0"

[[GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "c2178cfbc0a5a552e16d097fae508f2024de61a3"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.59.0"

[[GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "ef49a187604f865f4708c90e3f431890724e9012"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.59.0+0"

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

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

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

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

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

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

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

[[HypertextLiteral]]
git-tree-sha1 = "72053798e1be56026b81d4e2682dbe58922e5ec9"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.0"

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

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

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

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

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

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

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

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

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

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

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "a4b12a1bd2ebade87891ab7e36fdbce582301a92"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.6"

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

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

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

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

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

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

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

[[Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

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

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

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

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

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

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

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

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "5a5bc6bf062f0f95e62d0fe0a2d99699fed82dd9"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.8"

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

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

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

[[Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

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

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

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

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

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

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

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

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

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

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

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

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

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

[[PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

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

[[Plots]]
deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"]
git-tree-sha1 = "457b13497a3ea4deb33d273a6a5ea15c25c0ebd9"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.22.2"

[[PlutoUI]]
deps = ["Base64", "Dates", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "0c3e067931708fa5641247affc1a1aceb53fff06"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.11"

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

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

[[Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

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

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

[[RecipesBase]]
git-tree-sha1 = "44a75aa7a527910ee3d1751d1f0e4148698add9e"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.2"

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.4.1"

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

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

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

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

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

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

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

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

[[Xorg_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

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

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

[[Xorg_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

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

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

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

[[Xorg_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

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

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

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

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

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

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

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

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

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

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

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

[[xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╟─2ab0b80e-1e02-11ec-1596-8bd8e81d347c
# ╠═b0020dc0-78a7-483f-877f-719f42b0c044
# ╟─b4977f9f-2bcc-405f-b875-99cde2ccb77d
# ╟─2492a904-77da-4a36-baf4-65d40aa89d74
# ╟─194250f8-c94d-4732-b179-0ebead51110b
# ╠═38cb6e91-b7bb-4000-b883-f24c17ad827a
# ╠═40b7b2f4-ec2b-4b89-b2f0-adc368ee15bc
# ╟─67729a4c-df55-4fdb-8962-25b133eaaaf5
# ╠═a47b09eb-7441-4441-98de-d48111e172a7
# ╠═6b6ede88-b4b8-4dc7-8f27-bc2228512e22
# ╠═a130184f-06af-4767-ad6a-d8d8c1bbf6ca
# ╠═c12360cc-5208-417c-9003-5ce1308e8081
# ╟─1e332d32-7846-4bdb-935e-505dd290e1f0
# ╠═47e0c111-83c1-4c3f-b293-a337b19feee9
# ╟─a7cb520d-d221-45e9-83ac-e1927aafd0ab
# ╟─a2906480-383f-4456-9a80-04d172f85c41
# ╟─f8bc5419-054e-4b8f-807e-b594784661f6
# ╠═0c280cb9-9f30-4570-91a1-19538b56f957
# ╠═74b62c2b-58b5-4c37-9399-266855086f9b
# ╟─54b185a7-7b4e-4756-9663-db0b6419de27
# ╠═db00faa4-1d04-47aa-a062-4cf9b8cbe208
# ╟─fddb2f51-e5dc-47eb-81d9-9485435c60ea
# ╠═6a1dae01-b78b-4e8b-9a4d-d20bc6a025a5
# ╠═4a867566-14eb-4d8a-ae17-a267054840fd
# ╟─cf659c75-b8b9-488d-b937-36ea1e0cadbe
# ╠═94a53663-6dba-4e9b-8c30-bc1f2be3a43e
# ╠═1a2a55a5-424c-4522-a4bd-9c657f9f8565
# ╟─9fd3c33d-275d-420b-a03b-8ceb81a56ad3
# ╠═9d467594-8a33-4e1d-a272-744379bf2722
# ╠═63e2620a-6897-4664-81e3-479a7a5af9ff
# ╟─eb9dfc6d-b9d8-4771-9b71-e4d0fba38cb7
# ╟─89941271-8a9d-4e1c-94b0-77b35ebd8816
# ╟─ecde4baa-0aff-434c-b34a-59b0938a100f
# ╟─30651af8-ad5d-4cd2-89be-8283d381da5b
# ╟─d69435c1-c19a-4a94-8778-cea2ffcdfaa6
# ╟─8c64f65f-b610-40b5-b9a1-6abb39a6f0bb
# ╟─76b4809a-3fed-4bea-bfe8-66582cbb3fc9
# ╟─80c1d9d2-f8d7-4a16-90a3-a0af2ce96ced
# ╟─427428ab-1978-4317-86f3-ea211141e52f
# ╟─9d754d22-2a09-4458-8fa0-589ae4f75d76
# ╟─7654100f-86ca-481f-bfb7-bc9b9ee20639
# ╟─aec0517c-01e7-4d3f-b9b4-3e4ec8acdfc3
# ╟─9803aaf0-08c3-4501-8865-318a988210c9
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

max_stars_repo_name: MichielStock/STMO

max_issues_repo_name: MichielStock/STMO

max_forks_repo_name: MichielStock/STMO


text:
module StaticRenderer

"""
    render(;headers::Dict{String, String}, status_code::Int16, data::String) :: Dict{Symbol, Union{Dict{String, String}, Int16, String}}

Renderer to output static file as string

Cannot set `headers type to `Dict{String, String} here, as can be blank (status_code !=200)
"""
function render(;headers::Dict{String, String}, status_code::Int16, data::String) :: Dict{Symbol, Union{Dict{String, String}, Int16, String}}
    return Dict(
        :headers => headers,
        :status_code => status_code,
        :content_type => headers["Content-Type"],
        :body => data
    )
end

end


text:
module ReverseDiffSparse

using Base.Meta
using ForwardDiff
import Calculus
import MathProgBase
using Compat
using Compat.SparseArrays
using Compat.LinearAlgebra

const TAG = :rds_tag

# Override basic math functions to return NaN instead of throwing errors.
# This is what NLP solvers expect, and
# sometimes the results aren't needed anyway,
# because the code may compute derivatives wrt constants.
import NaNMath: sin, cos, tan, asin, acos, acosh, atanh, log, log2, log10, lgamma, log1p, pow, sqrt

include("types.jl")
include("conversion.jl")
include("coloring.jl")
export Coloring
include("linearity.jl")
include("sparsity.jl")
include("forward.jl")
include("reverse.jl")
include("subexpressions.jl")
include("simplify.jl")

end # module


text:
using ThreeBodyTB
using Test
using Suppressor

EXAMPLESDIR=ThreeBodyTB.EXAMPLESDIR

disp_old = deepcopy(ThreeBodyTB.BandStruct.no_display)
ThreeBodyTB.BandStruct.set_no_display(true)

for f in readdir("$EXAMPLESDIR")
    if occursin(".jl", f) && !occursin("~", f)
        @testset "example $f" begin
            @suppress begin
                include("$EXAMPLESDIR/$f")
                @test 1 == 1
            end
        end
    end
end

ThreeBodyTB.BandStruct.set_no_display(disp_old)

@testset "rm example pdfs generated" begin

    rm("mgs_compare_dft.pdf")
    rm("mgs_compare_self.pdf")
    rm("mgs_proj.pdf")
    rm("ScP_rocksalt.pdf")
    rm("al_fcc.pdf")
    rm("ScP_rocksalt_DOS.pdf")
##    rm("ScP_rocksalt_DOS_orbital.pdf")
    @test 1 == 1
end